diff --git a/apps/settings/src/app-types.ts b/apps/settings/src/app-types.ts index 9bba3ee6d50dc..9b42fd6f0c354 100644 --- a/apps/settings/src/app-types.ts +++ b/apps/settings/src/app-types.ts @@ -87,8 +87,38 @@ export interface IExAppStatus { type: string } +export interface IDeployOptions { + environment_variables: IDeployEnv[] + mounts: IDeployMount[] + ports: IDeployPort[] +} + +export interface IDeployEnv { + envName: string + displayName: string + description: string + default?: string +} + +export interface IDeployMount { + hostPath: string + containerPath: string + readOnly: boolean +} + +export interface IDeployPort { + hostPort: string // 443, 80, 443/tcp, 80/udp, etc. + hostIp: string // 0.0.0.0, 127.0.0.1, localhost, etc. + containerPort: number +} + +export interface IAppstoreExAppRelease extends IAppstoreAppRelease { + environmentVariables?: IDeployEnv[] +} + export interface IAppstoreExApp extends IAppstoreApp { daemon: IDeployDaemon | null | undefined status: IExAppStatus | Record error: string + releases: IAppstoreExAppRelease[] } diff --git a/apps/settings/src/components/AppStoreSidebar/AppDeployOptionsModal.vue b/apps/settings/src/components/AppStoreSidebar/AppDeployOptionsModal.vue new file mode 100644 index 0000000000000..6494ad8b79cb9 --- /dev/null +++ b/apps/settings/src/components/AppStoreSidebar/AppDeployOptionsModal.vue @@ -0,0 +1,306 @@ + + + + + + + diff --git a/apps/settings/src/components/AppStoreSidebar/AppDetailsTab.vue b/apps/settings/src/components/AppStoreSidebar/AppDetailsTab.vue index f3adbfd2a1ca5..acd61b69f07c6 100644 --- a/apps/settings/src/components/AppStoreSidebar/AppDetailsTab.vue +++ b/apps/settings/src/components/AppStoreSidebar/AppDetailsTab.vue @@ -77,6 +77,16 @@ :value="forceEnableButtonText" :disabled="installing || isLoading" @click="forceEnable(app.id)"> + + + {{ t('settings', 'Deploy options') }} +

{{ t('settings', 'Default Deploy daemon is not accessible') }} @@ -182,6 +192,11 @@ + + @@ -193,9 +208,10 @@ import NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js' import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' +import AppDeployOptionsModal from './AppDeployOptionsModal.vue' import AppManagement from '../../mixins/AppManagement.js' -import { mdiBug, mdiFeatureSearch, mdiStar, mdiTextBox, mdiTooltipQuestion } from '@mdi/js' +import { mdiBug, mdiFeatureSearch, mdiStar, mdiTextBox, mdiTooltipQuestion, mdiToyBrickPlus } from '@mdi/js' import { useAppsStore } from '../../store/apps-store' import { useAppApiStore } from '../../store/app-api-store' @@ -209,6 +225,7 @@ export default { NcIconSvgWrapper, NcSelect, NcCheckboxRadioSwitch, + AppDeployOptionsModal, }, mixins: [AppManagement], @@ -232,6 +249,7 @@ export default { mdiStar, mdiTextBox, mdiTooltipQuestion, + mdiToyBrickPlus, } }, @@ -239,6 +257,7 @@ export default { return { groupCheckedAppsData: false, removeData: false, + showDeployOptionsModal: false, } }, @@ -370,6 +389,7 @@ export default { &-manage { // if too many, shrink them and ellipsis display: flex; + align-items: center; input { flex: 0 1 auto; min-width: 0; diff --git a/apps/settings/src/mixins/AppManagement.js b/apps/settings/src/mixins/AppManagement.js index 893939bc2649a..55a702e414419 100644 --- a/apps/settings/src/mixins/AppManagement.js +++ b/apps/settings/src/mixins/AppManagement.js @@ -188,9 +188,9 @@ export default { .catch((error) => { showError(error) }) } }, - enable(appId) { + enable(appId, deployOptions = []) { if (this.app?.app_api) { - this.appApiStore.enableApp(appId) + this.appApiStore.enableApp(appId, deployOptions) .then(() => { rebuildNavigation() }) .catch((error) => { showError(error) }) } else { diff --git a/apps/settings/src/store/app-api-store.ts b/apps/settings/src/store/app-api-store.ts index ff7a56c6d039d..4c72109783f9b 100644 --- a/apps/settings/src/store/app-api-store.ts +++ b/apps/settings/src/store/app-api-store.ts @@ -14,7 +14,7 @@ import { defineStore } from 'pinia' import api from './api' import logger from '../logger' -import type { IAppstoreExApp, IDeployDaemon, IExAppStatus } from '../app-types' +import type { IAppstoreExApp, IDeployDaemon, IDeployOptions, IExAppStatus } from '../app-types.ts' import Vue from 'vue' interface AppApiState { @@ -76,12 +76,13 @@ export const useAppApiStore = defineStore('app-api-apps', { }) }, - enableApp(appId: string) { + enableApp(appId: string, deployOptions: IDeployOptions[] = []) { this.setLoading(appId, true) this.setLoading('install', true) return confirmPassword().then(() => { - return axios.post(generateUrl(`/apps/app_api/apps/enable/${appId}`)) + console.debug('[DEBUG] enableApp - deployOptions', deployOptions) + return axios.post(generateUrl(`/apps/app_api/apps/enable/${appId}`), { deployOptions }) .then((response) => { this.setLoading(appId, false) this.setLoading('install', false) @@ -132,6 +133,9 @@ export const useAppApiStore = defineStore('app-api-apps', { this.setError(appId, error.response.data.data.message) this.appsApiFailure({ appId, error }) }) + }).catch(() => { + this.setLoading(appId, false) + this.setLoading('install', false) }) }, @@ -150,6 +154,9 @@ export const useAppApiStore = defineStore('app-api-apps', { this.setError(appId, error.response.data.data.message) this.appsApiFailure({ appId, error }) }) + }).catch(() => { + this.setLoading(appId, false) + this.setLoading('install', false) }) }, @@ -173,6 +180,8 @@ export const useAppApiStore = defineStore('app-api-apps', { this.setLoading(appId, false) this.appsApiFailure({ appId, error }) }) + }).catch(() => { + this.setLoading(appId, false) }) }, @@ -237,6 +246,9 @@ export const useAppApiStore = defineStore('app-api-apps', { this.setLoading('install', false) this.appsApiFailure({ appId, error }) }) + }).catch(() => { + this.setLoading(appId, false) + this.setLoading('install', false) }) },