2021-07-31 22:45:28 +00:00
< template >
2021-10-04 02:38:45 +00:00
< v-container fluid class = "narrow-container" >
< BasePageTitle divider >
< template # header >
2021-10-30 23:46:44 +00:00
< v-img max -height = " 200 " max -width = " 150 " :src = "require('~/static/svgs/admin-site-settings.svg')" > < / v-img >
2021-10-04 02:38:45 +00:00
< / template >
< template # title > { { $t ( "settings.site-settings" ) } } < / template >
< / BasePageTitle >
2021-10-05 04:16:37 +00:00
< section >
2022-04-03 00:35:53 +00:00
< BaseCardSectionTitle class = "pb-0" :icon = "$globals.icons.cog" title = "Configuration" > < / BaseCardSectionTitle >
< v-card class = "mb-4" >
< template v-for = "(check, idx) in simpleChecks" >
< v-list-item :key = "`list-item-${idx}`" >
< v-list-item-icon >
< v-icon :color = "check.color" >
{ { check . icon } }
< / v-icon >
< / v-list-item-icon >
< v-list-item-content >
< v-list-item-title >
{ { check . text } }
< / v-list-item-title >
< v-list-item-subtitle class = "wrap-word" >
{ { check . status ? check . successText : check . errorText } }
< / v-list-item-subtitle >
< / v-list-item-content >
< / v-list-item >
< v-divider :key = "`divider-${idx}`" > < / v-divider >
< / template >
< / v-card >
< / section >
2021-12-04 23:18:46 +00:00
2022-04-03 00:35:53 +00:00
< section >
< BaseCardSectionTitle class = "pt-2" :icon = "$globals.icons.docker" title = "Docker Volume" / >
2021-12-04 23:18:46 +00:00
< v-alert
border = "left"
colored - border
2022-04-03 00:35:53 +00:00
: type = "docker.state === DockerVolumeState.Error ? 'error' : 'info'"
: icon = "$globals.icons.docker"
2021-12-04 23:18:46 +00:00
elevation = "2"
2022-04-03 00:35:53 +00:00
: loading = "docker.loading"
2021-12-04 23:18:46 +00:00
>
2022-04-03 00:35:53 +00:00
< div class = "d-flex align-center font-weight-medium" >
Docker Volume
< HelpIcon small class = "my-n3" >
Mealie requires that the frontend container and the backend share the same docker volume or storage . This
ensures that the frontend container can properly access the images and assets stored on disk .
< / HelpIcon >
< / div >
2021-12-04 23:18:46 +00:00
< div >
2022-04-03 00:35:53 +00:00
< template v-if = "docker.state === DockerVolumeState.Error" > Volumes are misconfigured. < / template >
< template v -else -if = " docker.state = = = DockerVolumeState.Success " >
Volumes are configured correctly .
< / template >
< template v -else -if = " docker.state = = = DockerVolumeState.Unknown " >
Status Unknown . Try running a validation .
< / template >
< / div >
< div class = "mt-4" >
< BaseButton color = "info" :loading = "docker.loading" @click ="dockerValidate" >
< template # icon > { { $globals . icons . checkboxMarkedCircle } } < / template >
Validate
< / BaseButton >
2021-12-04 23:18:46 +00:00
< / div >
< / v-alert >
2021-10-05 04:16:37 +00:00
< / section >
2022-04-03 00:35:53 +00:00
2021-10-05 04:16:37 +00:00
< section >
2022-04-03 00:35:53 +00:00
< BaseCardSectionTitle class = "pt-2" :icon = "$globals.icons.email" title = "Email" / >
< v-alert border = "left" colored -border : type = "appConfig.emailReady ? 'success' : 'error'" elevation = "2" >
2021-12-04 23:18:46 +00:00
< div class = "font-weight-medium" > Email Configuration Status < / div >
< div >
{ { appConfig . emailReady ? "Ready" : "Not Ready - Check Environmental Variables" } }
< / div >
< div >
< v-text-field v-model = "address" class="mr-4" :label="$t('user.email')" :rules="[validators.email]" >
< / v-text-field >
< BaseButton
color = "info"
: disabled = "!appConfig.emailReady || !validEmail"
: loading = "loading"
@ click = "testEmail"
>
< template # icon > { { $globals . icons . email } } < / template >
{ { $t ( "general.test" ) } }
< / BaseButton >
< template v-if = "tested" >
2022-02-24 00:04:45 +00:00
< v-divider class = "my-x mt-6" > < / v-divider >
< v-card-text class = "px-0" >
< h4 > Email Test Results < / h4 >
< span class = "pl-4" >
{ { success ? "Succeeded" : "Failed" } }
< / span >
2021-12-04 23:18:46 +00:00
< / v-card-text >
< / template >
< / div >
< / v-alert >
2021-10-05 04:16:37 +00:00
< / section >
2021-11-05 23:48:10 +00:00
< section class = "mt-4" >
< BaseCardSectionTitle class = "pb-0" :icon = "$globals.icons.cog" title = "General About" > < / BaseCardSectionTitle >
< v-card class = "mb-4" >
< v-list-item v-for = "property in appInfo" :key="property.name" >
< v-list-item-icon >
< v-icon > { { property . icon || $globals . icons . user } } < / v-icon >
< / v-list-item-icon >
< v-list-item-content >
< v-list-item-title >
< div > { { property . name } } < / div >
< / v-list-item-title >
< v-list-item-subtitle class = "text-end" >
{ { property . value } }
< / v-list-item-subtitle >
< / v-list-item-content >
< / v-list-item >
< / v-card >
< / section >
2021-08-07 00:28:12 +00:00
< / v-container >
2021-08-02 03:24:47 +00:00
< / template >
2022-01-09 06:15:23 +00:00
2021-08-02 03:24:47 +00:00
< script lang = "ts" >
2021-11-05 23:48:10 +00:00
import {
computed ,
onMounted ,
reactive ,
toRefs ,
ref ,
defineComponent ,
useAsync ,
useContext ,
} from "@nuxtjs/composition-api" ;
2021-11-06 19:28:47 +00:00
import { useAdminApi , useUserApi } from "~/composables/api" ;
2021-10-04 02:38:45 +00:00
import { validators } from "~/composables/use-validators" ;
2021-11-05 23:48:10 +00:00
import { useAsyncKey } from "~/composables/use-utils" ;
2022-04-03 00:35:53 +00:00
import { CheckAppConfig } from "~/types/api-types/admin" ;
enum DockerVolumeState {
Unknown = "unknown" ,
Success = "success" ,
Error = "error" ,
}
2021-08-02 03:24:47 +00:00
2021-10-30 23:46:44 +00:00
interface SimpleCheck {
text : string ;
2022-04-03 00:35:53 +00:00
status : boolean | undefined ;
2021-10-30 23:46:44 +00:00
successText : string ;
errorText : string ;
2022-04-03 00:35:53 +00:00
color : string ;
icon : string ;
}
interface CheckApp extends CheckAppConfig {
isSiteSecure ? : boolean ;
2021-10-30 23:46:44 +00:00
}
2021-08-02 03:24:47 +00:00
export default defineComponent ( {
layout : "admin" ,
setup ( ) {
2022-04-03 00:35:53 +00:00
// ==========================================================
// Docker Volume Validation
const docker = reactive ( {
loading : false ,
state : DockerVolumeState . Unknown ,
} ) ;
async function dockerValidate ( ) {
docker . loading = true ;
// Do API Check
const { data } = await adminApi . about . checkDocker ( ) ;
if ( data == null ) {
docker . state = DockerVolumeState . Error ;
return ;
}
// Get File Contents
const { data : fileContents } = await adminApi . about . getDockerValidateFileContents ( ) ;
if ( data . text === fileContents ) {
docker . state = DockerVolumeState . Success ;
} else {
docker . state = DockerVolumeState . Error ;
}
docker . loading = false ;
}
2021-10-04 02:38:45 +00:00
const state = reactive ( {
loading : false ,
address : "" ,
success : false ,
error : "" ,
tested : false ,
} ) ;
2022-04-03 00:35:53 +00:00
const appConfig = ref < CheckApp > ( {
emailReady : true ,
baseUrlSet : true ,
isSiteSecure : true ,
2021-12-04 23:18:46 +00:00
isUpToDate : false ,
2021-11-25 23:17:02 +00:00
ldapReady : false ,
2021-10-05 04:16:37 +00:00
} ) ;
2022-04-03 00:35:53 +00:00
function isLocalHostOrHttps ( ) {
return window . location . hostname === "localhost" || window . location . protocol === "https:" ;
}
2021-10-04 02:38:45 +00:00
2022-04-03 00:35:53 +00:00
const api = useUserApi ( ) ;
2021-11-05 23:48:10 +00:00
const adminApi = useAdminApi ( ) ;
2022-04-03 00:35:53 +00:00
2021-10-04 02:38:45 +00:00
onMounted ( async ( ) => {
2021-11-05 23:48:10 +00:00
const { data } = await adminApi . about . checkApp ( ) ;
2021-10-04 02:38:45 +00:00
if ( data ) {
2021-10-05 04:16:37 +00:00
appConfig . value = data ;
2021-10-04 02:38:45 +00:00
}
2021-10-30 23:46:44 +00:00
2021-11-25 23:17:02 +00:00
appConfig . value . isSiteSecure = isLocalHostOrHttps ( ) ;
2021-10-30 23:46:44 +00:00
} ) ;
const simpleChecks = computed < SimpleCheck [ ] > ( ( ) => {
2022-04-03 00:35:53 +00:00
const goodIcon = $globals . icons . checkboxMarkedCircle ;
const badIcon = $globals . icons . alert ;
const warningIcon = $globals . icons . alertCircle ;
const goodColor = "success" ;
const badColor = "error" ;
const warningColor = "warning" ;
const data : SimpleCheck [ ] = [
2021-10-30 23:46:44 +00:00
{
2021-12-04 23:18:46 +00:00
text : "Application Version" ,
2022-04-03 00:35:53 +00:00
status : appConfig . value . isUpToDate ,
2021-12-04 23:18:46 +00:00
errorText : ` Your current version ( ${ rawAppInfo . value . version } ) does not match the latest release. Considering updating to the latest version ( ${ rawAppInfo . value . versionLatest } ). ` ,
successText : "Mealie is up to date" ,
2022-04-03 00:35:53 +00:00
color : appConfig . value . isUpToDate ? goodColor : warningColor ,
icon : appConfig . value . isUpToDate ? goodIcon : warningIcon ,
2021-10-30 23:46:44 +00:00
} ,
{
text : "Secure Site" ,
2022-04-03 00:35:53 +00:00
status : appConfig . value . isSiteSecure ,
2021-12-04 23:18:46 +00:00
errorText : "Serve via localhost or secure with https. Clipboard and additional browser APIs may not work." ,
2021-10-30 23:46:44 +00:00
successText : "Site is accessed by localhost or https" ,
2022-04-03 00:35:53 +00:00
color : appConfig . value . isSiteSecure ? goodColor : badColor ,
icon : appConfig . value . isSiteSecure ? goodIcon : badIcon ,
2021-12-04 23:18:46 +00:00
} ,
{
text : "Server Side Base URL" ,
2022-04-03 00:35:53 +00:00
status : appConfig . value . baseUrlSet ,
2021-12-04 23:18:46 +00:00
errorText :
"`BASE_URL` is still the default value on API Server. This will cause issues with notifications links generated on the server for emails, etc." ,
successText : "Server Side URL does not match the default" ,
2022-04-03 00:35:53 +00:00
color : appConfig . value . baseUrlSet ? goodColor : badColor ,
icon : appConfig . value . baseUrlSet ? goodIcon : badIcon ,
2021-10-30 23:46:44 +00:00
} ,
2021-11-25 23:17:02 +00:00
{
text : "LDAP Ready" ,
2022-04-03 00:35:53 +00:00
status : appConfig . value . ldapReady ,
2021-12-04 23:18:46 +00:00
errorText :
"Not all LDAP Values are configured. This can be ignored if you are not using LDAP Authentication." ,
2021-11-25 23:17:02 +00:00
successText : "Required LDAP variables are all set." ,
2022-04-03 00:35:53 +00:00
color : appConfig . value . ldapReady ? goodColor : warningColor ,
icon : appConfig . value . ldapReady ? goodIcon : warningIcon ,
2021-11-25 23:17:02 +00:00
} ,
2021-10-30 23:46:44 +00:00
] ;
2022-04-03 00:35:53 +00:00
return data ;
2021-10-04 02:38:45 +00:00
} ) ;
async function testEmail ( ) {
state . loading = true ;
state . tested = false ;
const { data } = await api . email . test ( { email : state . address } ) ;
if ( data ) {
if ( data . success ) {
state . success = true ;
} else {
state . error = data . error ;
state . success = false ;
}
}
state . loading = false ;
state . tested = true ;
}
const validEmail = computed ( ( ) => {
if ( state . address === "" ) {
return false ;
}
const valid = validators . email ( state . address ) ;
// Explicit bool check because validators.email sometimes returns a string
if ( valid === true ) {
return true ;
}
return false ;
} ) ;
2021-11-05 23:48:10 +00:00
// ============================================================
// General About Info
2021-12-04 23:18:46 +00:00
2021-11-05 23:48:10 +00:00
const { $globals , i18n } = useContext ( ) ;
2022-01-16 02:38:11 +00:00
const rawAppInfo = ref ( {
2021-12-04 23:18:46 +00:00
version : "null" ,
versionLatest : "null" ,
} ) ;
2021-11-05 23:48:10 +00:00
function getAppInfo ( ) {
const statistics = useAsync ( async ( ) => {
const { data } = await adminApi . about . about ( ) ;
if ( data ) {
2022-01-16 02:38:11 +00:00
rawAppInfo . value . version = data . version ;
rawAppInfo . value . versionLatest = data . versionLatest ;
2021-12-04 23:18:46 +00:00
2021-11-05 23:48:10 +00:00
const prettyInfo = [
{
name : i18n . t ( "about.version" ) ,
icon : $globals . icons . information ,
value : data . version ,
} ,
2022-03-25 04:29:01 +00:00
{
name : "Build" ,
icon : $globals . icons . information ,
value : data . buildId ,
} ,
2021-11-05 23:48:10 +00:00
{
name : i18n . t ( "about.application-mode" ) ,
icon : $globals . icons . devTo ,
value : data . production ? i18n . t ( "about.production" ) : i18n . t ( "about.development" ) ,
} ,
{
name : i18n . t ( "about.demo-status" ) ,
icon : $globals . icons . testTube ,
value : data . demoStatus ? i18n . t ( "about.demo" ) : i18n . t ( "about.not-demo" ) ,
} ,
{
name : i18n . t ( "about.api-port" ) ,
icon : $globals . icons . api ,
value : data . apiPort ,
} ,
{
name : i18n . t ( "about.api-docs" ) ,
icon : $globals . icons . file ,
value : data . apiDocs ? i18n . t ( "general.enabled" ) : i18n . t ( "general.disabled" ) ,
} ,
{
name : i18n . t ( "about.database-type" ) ,
icon : $globals . icons . database ,
value : data . dbType ,
} ,
{
name : i18n . t ( "about.database-url" ) ,
icon : $globals . icons . database ,
value : data . dbUrl ,
} ,
{
name : i18n . t ( "about.default-group" ) ,
icon : $globals . icons . group ,
value : data . defaultGroup ,
} ,
] ;
return prettyInfo ;
}
return data ;
} , useAsyncKey ( ) ) ;
return statistics ;
}
const appInfo = getAppInfo ( ) ;
2021-10-04 02:38:45 +00:00
return {
2022-04-03 00:35:53 +00:00
DockerVolumeState ,
docker ,
dockerValidate ,
2021-10-30 23:46:44 +00:00
simpleChecks ,
2021-10-05 04:16:37 +00:00
appConfig ,
2021-10-04 02:38:45 +00:00
validEmail ,
validators ,
... toRefs ( state ) ,
testEmail ,
2021-11-05 23:48:10 +00:00
appInfo ,
2021-10-04 02:38:45 +00:00
} ;
2021-08-02 03:24:47 +00:00
} ,
2021-10-07 17:39:47 +00:00
head ( ) {
return {
title : this . $t ( "settings.site-settings" ) as string ,
} ;
} ,
2021-08-02 03:24:47 +00:00
} ) ;
< / script >
2022-01-09 06:15:23 +00:00
2022-04-03 00:35:53 +00:00
< style scoped >
. wrap - word {
white - space : normal ;
word - wrap : break - word ;
}
< / style >