Merge branch 'master' of github.com:Lissy93/dashy into FEATURE/minimal-view
This commit is contained in:
@@ -1,55 +1,55 @@
|
||||
<template>
|
||||
<div class="cloud-backup-restore-wrapper">
|
||||
<div class="section intro">
|
||||
<h2>Cloud Backup & Restore</h2>
|
||||
<h2>{{ $t('cloud-sync.title') }}</h2>
|
||||
<p class="intro">
|
||||
Cloud backup and restore is an optional feature, that enables you to upload your
|
||||
config to the internet, and then restore it on any other device or instance of Dashy.
|
||||
{{ $t('cloud-sync.intro-l1') }}
|
||||
<br><br>
|
||||
All data is fully end-to-end encrypted with AES, using your password as the key.
|
||||
{{ $t('cloud-sync.intro-l2') }}
|
||||
<br>
|
||||
For more info, please see the
|
||||
{{ $t('cloud-sync.intro-l3') }}
|
||||
<a href="https://github.com/Lissy93/dashy/blob/master/docs/backup-restore.md">docs</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="section backup-section">
|
||||
<h3 v-if="backupId">Update Backup</h3>
|
||||
<h3 v-else>Make a Backup</h3>
|
||||
<h3 v-if="backupId">{{ $t('cloud-sync.backup-title-setup') }}</h3>
|
||||
<h3 v-else>{{ $t('cloud-sync.backup-title-setup') }}</h3>
|
||||
<Input
|
||||
v-model="backupPassword"
|
||||
name="backup-password"
|
||||
:label="backupId ? 'Enter your Password' : 'Choose a Password'"
|
||||
:label="backupId
|
||||
? $t('cloud-sync.password-label-update') : $t('cloud-sync.password-label-setup')"
|
||||
layout="vertical"
|
||||
type="password"
|
||||
/>
|
||||
<Button :click="checkPass">
|
||||
<template v-slot:text>{{backupId ? 'Update Backup' : 'Backup'}}</template>
|
||||
<template v-slot:text>
|
||||
{{backupId
|
||||
? $t('cloud-sync.backup-button-update') : $t('cloud-sync.backup-button-setup')}}
|
||||
</template>
|
||||
<template v-slot:icon><IconBackup /></template>
|
||||
</Button>
|
||||
<div class="results-view" v-if="backupId">
|
||||
<span class="backup-id-label">Your Backup ID: </span>
|
||||
<span class="backup-id-label">{{ $t('cloud-sync.backup-id-label') }}: </span>
|
||||
<pre class="backup-id-value">{{ backupId }}</pre>
|
||||
<span class="backup-id-note">
|
||||
This is used to restore from backups later.
|
||||
So keep it, along with your password somewhere safe.
|
||||
</span>
|
||||
<span class="backup-id-note">{{ $t('cloud-sync.backup-id-note') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section restore-section">
|
||||
<h3>Restore a Backup</h3>
|
||||
<h3>{{ $t('cloud-sync.restore-title') }}</h3>
|
||||
<Input
|
||||
v-model="restoreCode"
|
||||
name="restore-code"
|
||||
label="Restore ID"
|
||||
:label="$t('cloud-sync.restore-id-label')"
|
||||
/>
|
||||
<Input
|
||||
v-model="restorePassword"
|
||||
name="restore-password"
|
||||
label="Password"
|
||||
:label="$t('cloud-sync.restore-password-label')"
|
||||
type="password"
|
||||
/>
|
||||
<Button :click="restoreBackup">
|
||||
<template v-slot:text>Restore</template>
|
||||
<template v-slot:text>{{ $t('cloud-sync.restore-button') }}</template>
|
||||
<template v-slot:icon><IconRestore /></template>
|
||||
</Button>
|
||||
</div>
|
||||
@@ -101,7 +101,7 @@ export default {
|
||||
} else if (savedHash === this.makeHash(this.backupPassword)) {
|
||||
this.makeUpdate();
|
||||
} else {
|
||||
this.showErrorMsg('Incorrect password. Please enter your current password.');
|
||||
this.showErrorMsg(this.$t('cloud-sync.backup-error-password'));
|
||||
}
|
||||
},
|
||||
makeBackup() {
|
||||
@@ -113,7 +113,7 @@ export default {
|
||||
this.updateUiAfterBackup(response.data.backupId, false);
|
||||
}
|
||||
}).catch(() => {
|
||||
this.showErrorMsg('Unable to process request');
|
||||
this.showErrorMsg(this.$t('cloud-sync.backup-error-unknown'));
|
||||
});
|
||||
},
|
||||
makeUpdate() {
|
||||
@@ -125,7 +125,7 @@ export default {
|
||||
this.updateUiAfterBackup(response.data.backupId, true);
|
||||
}
|
||||
}).catch(() => {
|
||||
this.showErrorMsg('Unable to process request');
|
||||
this.showErrorMsg(this.$t('cloud-sync.backup-error-unknown'));
|
||||
});
|
||||
},
|
||||
restoreFromBackup(config, backupId) {
|
||||
@@ -136,12 +136,14 @@ export default {
|
||||
localStorage.setItem(localStorageKeys.THEME, config.appConfig.theme);
|
||||
}
|
||||
this.setBackupIdLocally(backupId, this.restorePassword);
|
||||
this.showSuccessMsg('Config Restored Succesfully');
|
||||
this.showSuccessMsg(this.$t('cloud-sync.restore-success-msg'));
|
||||
setTimeout(() => { location.reload(); }, 1500); // eslint-disable-line no-restricted-globals
|
||||
},
|
||||
updateUiAfterBackup(backupId, isUpdate = false) {
|
||||
this.setBackupIdLocally(backupId, this.backupPassword);
|
||||
this.showSuccessMsg(`${isUpdate ? 'Update' : 'Backup'} Completed Succesfully`);
|
||||
this.showSuccessMsg(
|
||||
`${isUpdate ? 'Update' : 'Backup'} ${this.$t('cloud-sync.backup-success-msg')}`,
|
||||
);
|
||||
this.backupPassword = '';
|
||||
},
|
||||
showErrorMsg(errorMsg) {
|
||||
|
||||
@@ -1,67 +1,74 @@
|
||||
<template>
|
||||
<Tabs :navAuto="true" name="Add Item" ref="tabView">
|
||||
<TabItem name="Config" class="main-tab">
|
||||
<TabItem :name="$t('config.main-tab')" class="main-tab">
|
||||
<div class="main-options-container">
|
||||
<h2>Configuration Options</h2>
|
||||
<a class="hyperlink-wrapper" @click="downloadConfigFile('conf.yml', yaml)">
|
||||
<button class="config-button center">
|
||||
<DownloadIcon class="button-icon"/>
|
||||
Download Config
|
||||
<DownloadIcon class="button-icon"/>
|
||||
{{ $t('config.download-config-button') }}
|
||||
</button>
|
||||
</a>
|
||||
<button class="config-button center" @click="() => navigateToTab(2)">
|
||||
<EditIcon class="button-icon"/>
|
||||
Edit Config
|
||||
{{ $t('config.edit-config-button') }}
|
||||
</button>
|
||||
<button class="config-button center" @click="() => navigateToTab(3)">
|
||||
<CustomCssIcon class="button-icon"/>
|
||||
Edit Custom CSS
|
||||
{{ $t('config.edit-css-button') }}
|
||||
</button>
|
||||
<button class="config-button center" @click="openCloudSync()">
|
||||
<CloudIcon class="button-icon"/>
|
||||
{{backupId ? 'Edit Cloud Sync' : 'Enable Cloud Sync'}}
|
||||
{{backupId ? $t('config.edit-cloud-sync-button') : $t('config.cloud-sync-button') }}
|
||||
</button>
|
||||
<button class="config-button center" @click="openLanguageSwitchModal()">
|
||||
<LanguageIcon class="button-icon"/>
|
||||
{{ $t('config.change-language-button') }}
|
||||
</button>
|
||||
<button class="config-button center" @click="openRebuildAppModal()">
|
||||
<RebuildIcon class="button-icon"/>
|
||||
Rebuild Application
|
||||
{{ $t('config.rebuild-app-button') }}
|
||||
</button>
|
||||
<button class="config-button center" @click="resetLocalSettings()">
|
||||
<DeleteIcon class="button-icon"/>
|
||||
Reset Local Settings
|
||||
{{ $t('config.reset-settings-button') }}
|
||||
</button>
|
||||
<button class="config-button center" @click="openAboutModal()">
|
||||
<IconAbout class="button-icon" />
|
||||
App Info
|
||||
{{ $t('config.app-info-button') }}
|
||||
</button>
|
||||
<p class="small-screen-note" style="display: none;">
|
||||
You are using a very small screen, and some screens in this menu may not be optimal
|
||||
</p>
|
||||
<p class="app-version">Dashy version {{ appVersion }}</p>
|
||||
<p class="app-version">{{ $t('config.app-version-note') }} {{ appVersion }}</p>
|
||||
<p class="language">{{ getLanguage() }}</p>
|
||||
<div class="config-note">
|
||||
<span>
|
||||
It is recommend to make a backup of your conf.yml file before making changes.
|
||||
</span>
|
||||
<span>{{ $t('config.backup-note') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rebuild App Modal -->
|
||||
<RebuildApp />
|
||||
</TabItem>
|
||||
<TabItem name="View Config" class="code-container">
|
||||
<TabItem :name="$t('config.view-config-tab')" class="code-container">
|
||||
<pre id="conf-yaml">{{yaml}}</pre>
|
||||
<div class="yaml-action-buttons">
|
||||
<h2>Actions</h2>
|
||||
<h2>{{ $t('config.actions-label') }}</h2>
|
||||
<a class="yaml-button download" @click="downloadConfigFile('conf.yml', yaml)">
|
||||
Download Config
|
||||
{{ $t('config.download-config-button') }}
|
||||
</a>
|
||||
<a class="yaml-button copy" @click="copyConfigToClipboard()">
|
||||
{{ $t('config.copy-config-label') }}
|
||||
</a>
|
||||
<a class="yaml-button reset" @click="resetLocalSettings()">
|
||||
{{ $t('config.reset-config-label') }}
|
||||
</a>
|
||||
<a class="yaml-button copy" @click="copyConfigToClipboard()">Copy Config</a>
|
||||
<a class="yaml-button reset" @click="resetLocalSettings()">Reset Config</a>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem name="Edit Config">
|
||||
<TabItem :name="$t('config.edit-config-tab')">
|
||||
<JsonEditor :config="config" />
|
||||
</TabItem>
|
||||
<TabItem name="Custom Styles">
|
||||
<CustomCssEditor :config="config" initialCss="hello" />
|
||||
<TabItem :name="$t('config.custom-css-tab')">
|
||||
<CustomCssEditor :config="config" />
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</template>
|
||||
@@ -74,6 +81,7 @@ import 'highlight.js/styles/mono-blue.css';
|
||||
|
||||
import JsonToYaml from '@/utils/JsonToYaml';
|
||||
import { localStorageKeys, modalNames } from '@/utils/defaults';
|
||||
import { getUsersLanguage } from '@/utils/ConfigHelpers';
|
||||
import JsonEditor from '@/components/Configuration/JsonEditor';
|
||||
import CustomCssEditor from '@/components/Configuration/CustomCss';
|
||||
import RebuildApp from '@/components/Configuration/RebuildApp';
|
||||
@@ -84,6 +92,7 @@ import EditIcon from '@/assets/interface-icons/config-edit-json.svg';
|
||||
import CustomCssIcon from '@/assets/interface-icons/config-custom-css.svg';
|
||||
import CloudIcon from '@/assets/interface-icons/cloud-backup-restore.svg';
|
||||
import RebuildIcon from '@/assets/interface-icons/application-rebuild.svg';
|
||||
import LanguageIcon from '@/assets/interface-icons/config-language.svg';
|
||||
import IconAbout from '@/assets/interface-icons/application-about.svg';
|
||||
|
||||
export default {
|
||||
@@ -115,6 +124,7 @@ export default {
|
||||
EditIcon,
|
||||
CloudIcon,
|
||||
CustomCssIcon,
|
||||
LanguageIcon,
|
||||
RebuildIcon,
|
||||
IconAbout,
|
||||
},
|
||||
@@ -133,20 +143,21 @@ export default {
|
||||
openCloudSync() {
|
||||
this.$modal.show(modalNames.CLOUD_BACKUP);
|
||||
},
|
||||
openLanguageSwitchModal() {
|
||||
this.$modal.show(modalNames.LANG_SWITCHER);
|
||||
},
|
||||
copyConfigToClipboard() {
|
||||
navigator.clipboard.writeText(this.jsonParser(this.config));
|
||||
// event.target.textContent = 'Copied to clipboard';
|
||||
this.$toasted.show(this.$t('config.data-copied-msg'));
|
||||
},
|
||||
/* Checks that the user is sure, then resets site-wide local storage, and reloads page */
|
||||
resetLocalSettings() {
|
||||
const msg = 'This will remove all user settings from local storage, '
|
||||
+ 'but won\'t effect your \'conf.yml\' file. '
|
||||
+ 'It is recommend to make a backup of your modified YAML settings first.\n\n'
|
||||
+ 'Are you sure you want to proceed?';
|
||||
const msg = `${this.$t('config.reset-config-msg-l1')
|
||||
}${this.$t('config.reset-config-msg-l2')}\n\n${this.$t('config.reset-config-msg-l3')}`;
|
||||
const isTheUserSure = confirm(msg); // eslint-disable-line no-alert, no-restricted-globals
|
||||
if (isTheUserSure) {
|
||||
localStorage.clear();
|
||||
this.$toasted.show('Data cleared succesfully');
|
||||
this.$toasted.show(this.$t('config.data-cleared-msg'));
|
||||
setTimeout(() => {
|
||||
location.reload(true); // eslint-disable-line no-restricted-globals
|
||||
}, 1900);
|
||||
@@ -162,11 +173,19 @@ export default {
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
},
|
||||
/* Highlights the YAML config in View config tab */
|
||||
initiateStntaxHighlighter() {
|
||||
hljs.registerLanguage('yaml', yaml);
|
||||
const highlighted = hljs.highlight(this.jsonParser(this.config), { language: 'yaml' }).value;
|
||||
document.getElementById('conf-yaml').innerHTML = highlighted;
|
||||
},
|
||||
getLanguage() {
|
||||
const lang = getUsersLanguage();
|
||||
return lang ? `${lang.flag} ${lang.name}` : '';
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
hljs.registerLanguage('yaml', yaml);
|
||||
const highlighted = hljs.highlight(this.jsonParser(this.config), { language: 'yaml' }).value;
|
||||
document.getElementById('conf-yaml').innerHTML = highlighted;
|
||||
this.initiateStntaxHighlighter();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -213,10 +232,11 @@ a.config-button, button.config-button {
|
||||
}
|
||||
}
|
||||
|
||||
p.app-version {
|
||||
p.app-version, p.language {
|
||||
margin: 0.5rem auto;
|
||||
font-size: 1rem;
|
||||
color: var(--transparent-white-50);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
div.code-container {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="css-editor-outer">
|
||||
<prism-editor class="my-editor" v-model="customCss" :highlight="highlighter" line-numbers />
|
||||
<button class="save-button" @click="save()">Save Changes</button>
|
||||
<button class="save-button" @click="save()">{{ $t('config.css-save-btn') }}</button>
|
||||
<p class="quick-note">
|
||||
<b>Note</b>: You will need to refresh the page for your changes to take effect.
|
||||
Styles overides are only stored locally, so it is reccomended to make a copy of your CSS.
|
||||
To remove all custom styles, delete the contents and hit Save Changes
|
||||
<b>{{ $t('config.css-note-label') }}:</b>
|
||||
{{ $t('config.css-note-l1') }} {{ $t('config.css-note-l2') }} {{ $t('config.css-note-l3') }}
|
||||
</p>
|
||||
<CustomThemeMaker :themeToEdit="currentTheme" class="color-config" />
|
||||
</div>
|
||||
|
||||
@@ -8,19 +8,25 @@
|
||||
/>
|
||||
<!-- Options raido, and save button -->
|
||||
<div class="save-options">
|
||||
<span class="save-option-title">Save Location:</span>
|
||||
<span class="save-option-title">{{ $t('config-editor.save-location-label') }}:</span>
|
||||
<div class="option">
|
||||
<input type="radio" id="local" value="local"
|
||||
v-model="saveMode" class="radio-option" :disabled="!allowWriteToDisk" />
|
||||
<label for="local" class="save-option-label">Apply Locally</label>
|
||||
<label for="local" class="save-option-label">
|
||||
{{ $t('config-editor.location-local-label') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" id="file" value="file" v-model="saveMode" class="radio-option"
|
||||
:disabled="!allowWriteToDisk" />
|
||||
<label for="file" class="save-option-label">Write Changes to Config File</label>
|
||||
<label for="file" class="save-option-label">
|
||||
{{ $t('config-editor.location-disk-label') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button :class="`save-button ${!isValid ? 'err' : ''}`" @click="save()">Save Changes</button>
|
||||
<button :class="`save-button ${!isValid ? 'err' : ''}`" @click="save()">
|
||||
{{ $t('config-editor.save-button') }}
|
||||
</button>
|
||||
<!-- List validation warnings -->
|
||||
<p class="errors">
|
||||
<ul>
|
||||
@@ -28,24 +34,23 @@
|
||||
{{error.msg}}
|
||||
</li>
|
||||
<li v-if="errorMessages.length < 1" class="type-valid">
|
||||
Config is Valid
|
||||
{{ $t('config-editor.valid-label') }}
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
<!-- Information notes -->
|
||||
<p v-if="saveSuccess !== undefined"
|
||||
:class="`response-output status-${saveSuccess ? 'success' : 'fail'}`">
|
||||
{{saveSuccess ? 'Task Complete' : 'Task Failed'}}
|
||||
{{saveSuccess
|
||||
? $t('config-editor.status-success-msg') : $t('config-editor.status-fail-msg') }}
|
||||
</p>
|
||||
<p class="response-output">{{ responseText }}</p>
|
||||
<p v-if="saveSuccess" class="response-output">
|
||||
The app should rebuild automatically.
|
||||
This may take up to a minute.
|
||||
You will need to refresh the page for changes to take effect.
|
||||
</p>
|
||||
<p class="note">
|
||||
It is recommend to backup your existing confiruration before making any changes.
|
||||
{{ $t('config-editor.success-note-l1') }}
|
||||
{{ $t('config-editor.success-note-l2') }}
|
||||
{{ $t('config-editor.success-note-l3') }}
|
||||
</p>
|
||||
<p class="note">{{ $t('config.backup-note') }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -103,7 +108,7 @@ export default {
|
||||
} else if (this.saveMode === 'file') {
|
||||
this.writeConfigToDisk();
|
||||
} else {
|
||||
this.$toasted.show('Please select a Save Mode: Local or File');
|
||||
this.$toasted.show(this.$t('config-editor.error-msg-save-mode'));
|
||||
}
|
||||
},
|
||||
writeConfigToDisk() {
|
||||
@@ -121,9 +126,9 @@ export default {
|
||||
this.responseText = response.data.message;
|
||||
if (this.saveSuccess) {
|
||||
this.carefullyClearLocalStorage();
|
||||
this.showToast('Config file written to disk succesfully', true);
|
||||
this.showToast(this.$t('config-editor.success-msg-disk'), true);
|
||||
} else {
|
||||
this.showToast('An error occurred saving config', false);
|
||||
this.showToast(this.$t('config-editor.error-msg-cannot-save'), false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -146,7 +151,7 @@ export default {
|
||||
if (data.appConfig.theme) {
|
||||
localStorage.setItem(localStorageKeys.THEME, data.appConfig.theme);
|
||||
}
|
||||
this.showToast('Changes saved succesfully', true);
|
||||
this.showToast(this.$t('config-editor.success-msg-local'), true);
|
||||
},
|
||||
carefullyClearLocalStorage() {
|
||||
localStorage.removeItem(localStorageKeys.PAGE_INFO);
|
||||
@@ -160,7 +165,8 @@ export default {
|
||||
case 'validation':
|
||||
errorMessages.push({
|
||||
type: 'validation',
|
||||
msg: `Validatation Warning: ${error.error.keyword} ${error.error.message}`,
|
||||
msg: `${this.$t('config-editor.warning-msg-validation')}: `
|
||||
+ `${error.error.keyword} ${error.error.message}`,
|
||||
});
|
||||
break;
|
||||
case 'error':
|
||||
@@ -172,7 +178,7 @@ export default {
|
||||
default:
|
||||
errorMessages.push({
|
||||
type: 'editor',
|
||||
msg: 'Error in JSON',
|
||||
msg: this.$t('config-editor.error-msg-bad-json'),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,35 +2,41 @@
|
||||
<modal :name="modalName" :resizable="true" width="50%" height="60%" classes="dashy-modal">
|
||||
<div class="rebuild-app-container">
|
||||
<!-- Title, intro and start button -->
|
||||
<h3 class="rebuild-app-title">Rebuild Application</h3>
|
||||
<h3 class="rebuild-app-title">{{ $t('app-rebuild.title') }}</h3>
|
||||
<p>
|
||||
A rebuild is required for changes written to the conf.yml file to take effect.
|
||||
This should happen automatically, but if it hasn't, you can manually trigger it here.<br>
|
||||
This is not required for modifications stored locally.
|
||||
{{ $t('app-rebuild.rebuild-note-l1') }}
|
||||
{{ $t('app-rebuild.rebuild-note-l2') }}<br>
|
||||
{{ $t('app-rebuild.rebuild-note-l3') }}
|
||||
</p>
|
||||
<Button :click="startBuild" :disabled="loading || !allowRebuild" :disallow="!allowRebuild">
|
||||
<template v-slot:text>{{ loading ? 'Building...' : 'Start Build' }}</template>
|
||||
<template v-slot:text>
|
||||
{{ loading ? $t('app-rebuild.rebuilding-status-1') : $t('app-rebuild.rebuild-button') }}
|
||||
</template>
|
||||
<template v-slot:icon><RebuildIcon /></template>
|
||||
</Button>
|
||||
<div v-if="!allowRebuild">
|
||||
<p class="disallow-rebuild-msg">You do no have permission to trigger this action</p>
|
||||
<p class="disallow-rebuild-msg">{{ $t('app-rebuild.error-permission') }}</p>
|
||||
</div>
|
||||
<!-- Loading animation and text (shown while build is happening) -->
|
||||
<div v-if="loading" class="loader-info">
|
||||
<LoadingAnimation class="loader" />
|
||||
<p class="loading-message">This may take a few minutes...</p>
|
||||
<p class="loading-message">{{ $t('app-rebuild.rebuilding-status-2') }}...</p>
|
||||
</div>
|
||||
<!-- Build response, and next actions (shown after build is done) -->
|
||||
<div class="rebuild-response" v-if="success !== undefined">
|
||||
<p v-if="success" class="response-status success">✅ Build completed succesfully</p>
|
||||
<p v-else class="response-status failure">❌ Build operation failed</p>
|
||||
<p v-if="success" class="response-status success">
|
||||
✅ {{ $t('app-rebuild.success-msg') }}
|
||||
</p>
|
||||
<p v-else class="response-status failure">
|
||||
❌ {{ $t('app-rebuild.fail-msg') }}
|
||||
</p>
|
||||
<pre class="output"><code>{{ output || error }}</code></pre>
|
||||
<p class="rebuild-message">{{ message }}</p>
|
||||
<p v-if="success" class="rebuild-message">
|
||||
A page reload is now required for changes to take effect
|
||||
{{ $t('app-rebuild.reload-note') }}
|
||||
</p>
|
||||
<Button :click="refreshPage" v-if="success">
|
||||
<template v-slot:text>Reload Page</template>
|
||||
<template v-slot:text>{{ $t('app-rebuild.reload-button') }}</template>
|
||||
<template v-slot:icon><ReloadIcon /></template>
|
||||
</Button>
|
||||
</div>
|
||||
@@ -65,6 +71,7 @@ export default {
|
||||
allowRebuild: true,
|
||||
}),
|
||||
methods: {
|
||||
/* Calls to the rebuild endpoint, to kickoff the app build */
|
||||
startBuild() {
|
||||
const baseUrl = process.env.VUE_APP_DOMAIN || window.location.origin;
|
||||
const endpoint = `${baseUrl}/config-manager/rebuild`;
|
||||
@@ -77,6 +84,7 @@ export default {
|
||||
this.finished({ success: false, error });
|
||||
});
|
||||
},
|
||||
/* Called when rebuild is complete, updates UI with either success or fail message */
|
||||
finished(responseData) {
|
||||
this.loading = false;
|
||||
if (responseData) {
|
||||
@@ -89,7 +97,8 @@ export default {
|
||||
this.error = error;
|
||||
}
|
||||
this.$toasted.show(
|
||||
(this.success ? '✅ Build Completed Succesfully' : '❌ Build Failed'),
|
||||
(this.success
|
||||
? `✅ ${this.$t('app-rebuild.success-msg')}` : `❌ ${this.$t('app-rebuild.fail-msg')}`),
|
||||
{ className: `toast-${this.success ? 'success' : 'error'}` },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="config-options">
|
||||
<!-- Button and label -->
|
||||
<span>Config</span>
|
||||
<span>{{ $t('settings.config-launcher-label') }}</span>
|
||||
<div class="config-buttons">
|
||||
<IconSpanner @click="showEditor()" tabindex="-2"
|
||||
v-tooltip="tooltip('Update configuration locally')" />
|
||||
v-tooltip="tooltip('Update configuration')" />
|
||||
<IconCloud @click="showCloudModal()" tabindex="-2"
|
||||
v-tooltip="tooltip('Backup / restore cloud config')" />
|
||||
</div>
|
||||
@@ -20,6 +20,13 @@
|
||||
@closed="$emit('modalChanged', false)" classes="dashy-modal">
|
||||
<CloudBackupRestore :config="combineConfig()" />
|
||||
</modal>
|
||||
|
||||
<!-- Modal for manually changing locale -->
|
||||
<modal :name="modalNames.LANG_SWITCHER" classes="dashy-modal"
|
||||
:resizable="true" width="30%" height="25%">
|
||||
<LanguageSwitcher />
|
||||
</modal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -29,6 +36,7 @@ import IconSpanner from '@/assets/interface-icons/config-editor.svg';
|
||||
import IconCloud from '@/assets/interface-icons/cloud-backup-restore.svg';
|
||||
import ConfigContainer from '@/components/Configuration/ConfigContainer';
|
||||
import CloudBackupRestore from '@/components/Configuration/CloudBackupRestore';
|
||||
import LanguageSwitcher from '@/components/Settings/LanguageSwitcher';
|
||||
import { topLevelConfKeys, localStorageKeys, modalNames } from '@/utils/defaults';
|
||||
|
||||
export default {
|
||||
@@ -43,6 +51,7 @@ export default {
|
||||
IconCloud,
|
||||
ConfigContainer,
|
||||
CloudBackupRestore,
|
||||
LanguageSwitcher,
|
||||
},
|
||||
props: {
|
||||
sections: Array,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div :class="`theme-configurator-wrapper ${showingAllVars ? 'showing-all' : ''}`">
|
||||
<h3 class="configurator-title">Theme Configurator</h3>
|
||||
<h3 class="configurator-title">{{ $t('theme-maker.title') }}</h3>
|
||||
<div class="color-row-container">
|
||||
<div class="color-row" v-for="colorName in Object.keys(customColors)" :key="colorName">
|
||||
<label :for="`color-input-${colorName}`" class="color-name">
|
||||
@@ -33,17 +33,21 @@
|
||||
</div> <!-- End of color list -->
|
||||
</div>
|
||||
<p @click="exportToClipboard" class="action-text-btn">
|
||||
Export Custom Variables
|
||||
{{ $t('theme-maker.export-button') }}
|
||||
</p>
|
||||
<p @click="resetAndSave" class="action-text-btn show-all-vars-btn">
|
||||
Reset Styles for '{{ themeToEdit }}'
|
||||
{{ $t('theme-maker.reset-button') }} '{{ themeToEdit }}'
|
||||
</p>
|
||||
<p @click="findAllVariableNames" class="action-text-btn">
|
||||
Show All Variables
|
||||
{{ $t('theme-maker.show-all-button') }}
|
||||
</p>
|
||||
<div class="action-buttons">
|
||||
<Button :click="saveChanges"><SaveIcon />Save</Button>
|
||||
<Button :click="resetUnsavedColors"><CancelIcon />Cancel</Button>
|
||||
<Button :click="saveChanges">
|
||||
<SaveIcon /> {{ $t('theme-maker.save-button') }}
|
||||
</Button>
|
||||
<Button :click="resetUnsavedColors">
|
||||
<CancelIcon /> {{ $t('theme-maker.cancel-button') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -89,7 +93,7 @@ export default {
|
||||
const priorSettings = JSON.parse(localStorage[localStorageKeys.CUSTOM_COLORS] || '{}');
|
||||
priorSettings[this.themeToEdit] = this.customColors;
|
||||
localStorage.setItem(localStorageKeys.CUSTOM_COLORS, JSON.stringify(priorSettings));
|
||||
this.$toasted.show('Theme Updates Succesfully');
|
||||
this.$toasted.show(this.$t('theme-maker.saved-toast', { theme: this.themeToEdit }));
|
||||
this.$emit('closeThemeConfigurator');
|
||||
},
|
||||
/* Itterates over available variables, removing them from the DOM */
|
||||
@@ -107,7 +111,7 @@ export default {
|
||||
delete priorSettings[this.themeToEdit];
|
||||
localStorage.setItem(localStorageKeys.CUSTOM_COLORS, JSON.stringify(priorSettings));
|
||||
this.resetUnsavedColors();
|
||||
this.$toasted.show(`Custom Colors for ${this.themeToEdit} Removed`);
|
||||
this.$toasted.show(this.$t('theme-maker.reset-toast', { theme: this.themeToEdit }));
|
||||
},
|
||||
/* Generates CSS for the currently applied variables, and copys to users clipboard */
|
||||
exportToClipboard() {
|
||||
@@ -117,7 +121,7 @@ export default {
|
||||
clipboardText += (`--${customVar}: ${this.customColors[customVar]};\n`);
|
||||
});
|
||||
navigator.clipboard.writeText(clipboardText);
|
||||
this.$toasted.show(`Theme data for ${themeName} copied to clipboard`);
|
||||
this.$toasted.show(this.$t('theme-maker.copied-toast', { theme: themeName }));
|
||||
},
|
||||
/* Returns a JSON object, with the variable name as key, and color as value */
|
||||
makeInitialData(variableArray) {
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<span class="options-label">Icon Size</span>
|
||||
<span class="options-label">{{ $t('settings.item-size-label') }}</span>
|
||||
<div class="display-options">
|
||||
<IconSmall @click="updateIconSize('small')" v-tooltip="tooltip('Small')"
|
||||
:class="`layout-icon ${iconSize === 'small' ? 'selected' : ''}`" tabindex="-2" />
|
||||
<IconMedium @click="updateIconSize('medium')" v-tooltip="tooltip('Medium')"
|
||||
:class="`layout-icon ${iconSize === 'medium' ? 'selected' : ''}`" tabindex="-2" />
|
||||
<IconLarge @click="updateIconSize('large')" v-tooltip="tooltip('Large')"
|
||||
:class="`layout-icon ${iconSize === 'large' ? 'selected' : ''}`" tabindex="-2" />
|
||||
<IconSmall
|
||||
@click="updateIconSize('small')"
|
||||
v-tooltip="tooltip($t('settings.item-size-small'))"
|
||||
:class="`layout-icon ${iconSize === 'small' ? 'selected' : ''}`"
|
||||
tabindex="-2"
|
||||
/>
|
||||
<IconMedium
|
||||
@click="updateIconSize('medium')"
|
||||
v-tooltip="tooltip($t('settings.item-size-medium'))"
|
||||
:class="`layout-icon ${iconSize === 'medium' ? 'selected' : ''}`"
|
||||
tabindex="-2"
|
||||
/>
|
||||
<IconLarge
|
||||
@click="updateIconSize('large')"
|
||||
v-tooltip="tooltip($t('settings.item-size-large'))"
|
||||
:class="`layout-icon ${iconSize === 'large' ? 'selected' : ''}`"
|
||||
tabindex="-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
110
src/components/Settings/LanguageSwitcher.vue
Normal file
110
src/components/Settings/LanguageSwitcher.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="language-switcher">
|
||||
<h3 class="title">{{ $t('language-switcher.title') }}</h3>
|
||||
<p class="intro">{{ $t('language-switcher.dropdown-label') }}:</p>
|
||||
<v-select
|
||||
v-model="language"
|
||||
:selectOnTab="true"
|
||||
:options="availibleLanguages"
|
||||
class="language-dropdown"
|
||||
label="name"
|
||||
:input="setLangLocally()"
|
||||
/>
|
||||
<Button class="save-button" :click="saveLanguage" :disallow="!language">
|
||||
{{ $t('language-switcher.save-button') }}
|
||||
<SaveConfigIcon />
|
||||
</Button>
|
||||
<p v-if="language">{{ language.flag }} {{ language.name }}</p>
|
||||
<p v-if="$i18n.availableLocales.length <= 1" class="sad-times">
|
||||
There are not currently any additional languages supported,
|
||||
but stay tuned as more are on their way!
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Button from '@/components/FormElements/Button';
|
||||
import { languages } from '@/utils/languages';
|
||||
import SaveConfigIcon from '@/assets/interface-icons/save-config.svg';
|
||||
import { localStorageKeys, modalNames } from '@/utils/defaults';
|
||||
|
||||
export default {
|
||||
name: 'LanguageSwitcher',
|
||||
inject: ['config'],
|
||||
components: {
|
||||
Button,
|
||||
SaveConfigIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
availibleLanguages: languages,
|
||||
language: '',
|
||||
modalName: modalNames.LANG_SWITCHER,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/* Save language to local storage, show success msg and close modal */
|
||||
saveLanguage() {
|
||||
const selectedLanguage = this.language;
|
||||
if (this.checkLocale(selectedLanguage)) {
|
||||
localStorage.setItem(localStorageKeys.LANGUAGE, selectedLanguage.code);
|
||||
this.setLangLocally();
|
||||
const successMsg = `${selectedLanguage.flag} `
|
||||
+ `${this.$t('language-switcher.success-msg')} ${selectedLanguage.name}`;
|
||||
this.$toasted.show(successMsg, { className: 'toast-success' });
|
||||
this.$modal.hide(this.modalName);
|
||||
} else {
|
||||
this.$toasted.show('Unable to update language', { className: 'toast-error' });
|
||||
}
|
||||
},
|
||||
/* Check language is supported, before saving */
|
||||
checkLocale(selectedLanguage) {
|
||||
if (!selectedLanguage || !selectedLanguage.code) return false;
|
||||
const i18nLocales = this.$i18n.availableLocales;
|
||||
return i18nLocales.includes(selectedLanguage.code);
|
||||
},
|
||||
/* Apply language locally */
|
||||
setLangLocally() {
|
||||
if (this.language && this.language.code) {
|
||||
this.$i18n.locale = this.language.code;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.language-switcher {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
background: var(--config-settings-background);
|
||||
color: var(--config-settings-color);
|
||||
|
||||
h3.title {
|
||||
text-align: center;
|
||||
}
|
||||
p.intro {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
button.save-button {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
p.sad-times {
|
||||
color: var(--warning);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.language-dropdown {
|
||||
margin: 1rem auto;
|
||||
div.vs__dropdown-toggle {
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,13 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<span class="options-label">Layout</span>
|
||||
<span class="options-label">{{ $t('settings.layout-label') }}</span>
|
||||
<div class="display-options">
|
||||
<IconDeafault @click="updateDisplayLayout('auto')" v-tooltip="tooltip('Auto')"
|
||||
:class="`layout-icon ${displayLayout === 'auto' ? 'selected' : ''}`" tabindex="-2" />
|
||||
<IconHorizontal @click="updateDisplayLayout('horizontal')" v-tooltip="tooltip('Horizontal')"
|
||||
:class="`layout-icon ${displayLayout === 'horizontal' ? 'selected' : ''}`" tabindex="-2" />
|
||||
<IconVertical @click="updateDisplayLayout('vertical')" v-tooltip="tooltip('Vertical')"
|
||||
:class="`layout-icon ${displayLayout === 'vertical' ? 'selected' : ''}`" tabindex="-2" />
|
||||
<IconDeafault
|
||||
@click="updateDisplayLayout('auto')"
|
||||
v-tooltip="tooltip($t('settings.layout-auto'))"
|
||||
:class="`layout-icon ${displayLayout === 'auto' ? 'selected' : ''}`"
|
||||
tabindex="-2"
|
||||
/>
|
||||
<IconHorizontal
|
||||
@click="updateDisplayLayout('horizontal')"
|
||||
v-tooltip="tooltip($t('settings.layout-horizontal'))"
|
||||
:class="`layout-icon ${displayLayout === 'horizontal' ? 'selected' : ''}`"
|
||||
tabindex="-2"
|
||||
/>
|
||||
<IconVertical
|
||||
@click="updateDisplayLayout('vertical')"
|
||||
v-tooltip="tooltip($t('settings.layout-vertical'))"
|
||||
:class="`layout-icon ${displayLayout === 'vertical' ? 'selected' : ''}`"
|
||||
tabindex="-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<form>
|
||||
<label for="filter-tiles">Search</label>
|
||||
<label for="filter-tiles">{{ $t('search.search-label') }}</label>
|
||||
<input
|
||||
id="filter-tiles"
|
||||
v-model="input"
|
||||
ref="filter"
|
||||
placeholder="Start typing to filter..."
|
||||
:placeholder="$t('search.search-placeholder')"
|
||||
v-on:input="userIsTypingSomething"
|
||||
@keydown.esc="clearFilterInput" />
|
||||
<i v-if="input.length > 0"
|
||||
class="clear-search"
|
||||
title="Clear search"
|
||||
:title="$t('search.clear-search-tooltip')"
|
||||
@click="clearFilterInput">x</i>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="theme-selector-section" v-click-outside="closeThemeConfigurator">
|
||||
<div>
|
||||
<span class="theme-label">Theme</span>
|
||||
<span class="theme-label">{{ $t('settings.theme-label') }}</span>
|
||||
<v-select
|
||||
:options="themeNames"
|
||||
v-model="selectedTheme"
|
||||
|
||||
Reference in New Issue
Block a user