diff --git a/dashboard/src/components/app/Uninstall.vue b/dashboard/src/components/app/Uninstall.vue index 708805260..558ce325f 100644 --- a/dashboard/src/components/app/Uninstall.vue +++ b/dashboard/src/components/app/Uninstall.vue @@ -5,9 +5,9 @@ const i18n = useI18n(); const t = i18n.t; import { ref, onMounted, useTemplateRef } from 'vue'; -import { Button, InputDialog } from '@cloudron/pankow'; +import { Button, InputDialog, Spinner } from '@cloudron/pankow'; import { prettyLongDate } from '@cloudron/pankow/utils'; -import { APP_TYPES } from '../../constants.js'; +import { APP_TYPES, RSTATES } from '../../constants.js'; import AppsModel from '../../models/AppsModel.js'; const appsModel = AppsModel.create(); @@ -55,6 +55,47 @@ async function onArchive() { window.location.href = '/#/apps'; } +const TARGET_RUN_STATE = { + START: Symbol('start'), + STOP: Symbol('stop'), +}; + +function targetRunState() { + // if we have an error, we want to retry the pending state, otherwise toggle the runstate + if (props.app.error) { + if (props.app.error.installationState === ISTATES.PENDING_START) return TARGET_RUN_STATE.START; + else return TARGET_RUN_STATE.STOP; + } else { + if (props.app.runState === RSTATES.STOPPED) return TARGET_RUN_STATE.START; + else return TARGET_RUN_STATE.STOP; + } +} + +const toggleRunStateBusy = ref(false); +async function onStartApp() { + toggleRunStateBusy.value = true; + + const [error] = await appsModel.start(props.app.id); + if (error) { + toggleRunStateBusy.value = false; + return console.error(error); + } + + setTimeout(() => toggleRunStateBusy.value = false, 3000); +} + +async function onStopApp() { + toggleRunStateBusy.value = true; + + const [error] = await appsModel.stop(props.app.id); + if (error) { + toggleRunStateBusy.value = false; + return console.error(error); + } + + setTimeout(() => toggleRunStateBusy.value = false, 3000); +} + onMounted(async () => { let [error, result] = await appsModel.backups(props.app.id); if (error) return console.error(error); @@ -75,6 +116,16 @@ onMounted(async () => {
+
+
{{ $t('app.uninstall.startStop.description') }}
+
+ + + +
+ +
+
diff --git a/dashboard/src/views/AppConfigureView.vue b/dashboard/src/views/AppConfigureView.vue index 5fc77721b..5529e8fdf 100644 --- a/dashboard/src/views/AppConfigureView.vue +++ b/dashboard/src/views/AppConfigureView.vue @@ -5,7 +5,7 @@ const i18n = useI18n(); const t = i18n.t; import { ref, onMounted, onBeforeUnmount, useTemplateRef } from 'vue'; -import { Button, ButtonGroup, ProgressBar } from '@cloudron/pankow'; +import { Button, ButtonGroup, ProgressBar, InputDialog } from '@cloudron/pankow'; import PostInstallDialog from '../components/PostInstallDialog.vue'; import SftpInfoDialog from '../components/SftpInfoDialog.vue'; import Access from '../components/app/Access.vue'; @@ -33,6 +33,8 @@ const appsModel = AppsModel.create(); const tasksModel = TasksModel.create(); const installationStateLabel = AppsModel.installationStateLabel; +const inputDialog = useTemplateRef('inputDialog'); + const busy = ref(true); const id = ref(''); const app = ref(null); @@ -161,47 +163,6 @@ function isViewEnabled(view, errorState) { return false; } -const TARGET_RUN_STATE = { - START: Symbol('start'), - STOP: Symbol('stop'), -}; - -function targetRunState() { - // if we have an error, we want to retry the pending state, otherwise toggle the runstate - if (app.value.error) { - if (app.value.error.installationState === ISTATES.PENDING_START) return TARGET_RUN_STATE.START; - else return TARGET_RUN_STATE.STOP; - } else { - if (app.value.runState === RSTATES.STOPPED) return TARGET_RUN_STATE.START; - else return TARGET_RUN_STATE.STOP; - } -} - -const toggleRunStateBusy = ref(false); -async function onStartApp() { - toggleRunStateBusy.value = true; - - const [error] = await appsModel.start(app.value.id); - if (error) { - toggleRunStateBusy.value = false; - return console.error(error); - } - - setTimeout(() => toggleRunStateBusy.value = false, 3000); -} - -async function onStopApp() { - toggleRunStateBusy.value = true; - - const [error] = await appsModel.stop(app.value.id); - if (error) { - toggleRunStateBusy.value = false; - return console.error(error); - } - - setTimeout(() => toggleRunStateBusy.value = false, 3000); -} - async function onStopAppTask() { if (!app.value.taskId) return; @@ -236,6 +197,37 @@ function hashChange() { window.location.hash = `/app/${id.value}/${newView}`; } +const busyRestart = ref(false); + +async function onRestartApp() { + if (app.value.runState === RSTATES.STOPPED) { + busyRestart.value = true; + + const [error] = await appsModel.restart(id.value); + if (error) return console.error(error); + + busyRestart.value = false; + return; + } + + const confirmed = await inputDialog.value.confirm({ + message: t('filemanager.toolbar.restartApp') + '?', + confirmLabel: t('main.action.restart'), + confirmStyle: 'danger', + rejectLabel: t('main.dialog.cancel'), + rejectStyle: 'secondary', + }); + + if (!confirmed) return; + + busyRestart.value = true; + + const [error] = await appsModel.restart(id.value); + if (error) return console.error(error); + + busyRestart.value = false; +} + onMounted(async () => { const tmp = window.location.hash.slice('#/app/'.length); if (!tmp) return; @@ -294,6 +286,7 @@ onBeforeUnmount(() => {