Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3a51374
feat(app_api): add initial state data for AppAPI UI part
andrey18106 Oct 9, 2024
475ce2e
feat(settings): migrate AppAPI ExApps management (1)
andrey18106 Oct 9, 2024
151a758
WIP: add Daemon badge in app sidebar (2)
andrey18106 Oct 11, 2024
18c9a03
WIP: use global mutation, since app_api_apps is namespaced
andrey18106 Oct 11, 2024
3d4f0f9
WIP: add missing state checks
andrey18106 Oct 11, 2024
9e694d1
WIP: minor fixes
andrey18106 Oct 11, 2024
a29e170
fix(ci): resolve eslint errors
andrey18106 Oct 14, 2024
fb4150e
fix(ci): suppress UndefinedClass for AppAPI related classes since it'…
andrey18106 Oct 14, 2024
c53f5c4
WIP: address review comments, small fixes
andrey18106 Oct 17, 2024
606a9a3
WIP: migrate to Pinia, minor fixes
andrey18106 Oct 21, 2024
d91a7fe
WIP: remove app_api_apps vuex store
andrey18106 Oct 21, 2024
67b4d3d
fix: address review comments
andrey18106 Oct 23, 2024
cac5be5
fix(ci): psalm, suppress undefined for viewApps
andrey18106 Oct 24, 2024
6be8cbd
fix(ci): fix eslint errors
andrey18106 Oct 24, 2024
41c61c3
fix: loading state reactivity
andrey18106 Oct 29, 2024
128b65e
fix(ci): eslint fix, minor correction after rebase
andrey18106 Oct 29, 2024
864376d
chore(assets): Recompile assets
nextcloud-command Oct 29, 2024
d66f0cc
chore(assets): Recompile assets
nextcloud-command Oct 29, 2024
824aa30
fix: add missing import after backport
andrey18106 Oct 29, 2024
487431f
chore(assets): Recompile assets
nextcloud-command Oct 29, 2024
0ee0e04
chore(assets): Recompile assets
nextcloud-command Oct 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP: migrate to Pinia, minor fixes
Signed-off-by: Andrey Borysenko <[email protected]>
  • Loading branch information
andrey18106 committed Oct 30, 2024
commit 606a9a3d648baf86233c763a848db901354550d5
12 changes: 10 additions & 2 deletions apps/settings/src/components/AppList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import AppItem from './AppList/AppItem.vue'
import pLimit from 'p-limit'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import { useAppApiStore } from '../store/app-api-store'

export default {
name: 'AppList',
Expand All @@ -158,6 +159,13 @@ export default {
},
},

setup() {
const appApiStore = useAppApiStore()
return {
appApiStore,
}
},

data() {
return {
search: '',
Expand All @@ -171,7 +179,7 @@ export default {
if (!this.$store.getters['appApiApps/isAppApiEnabled']) {
return this.$store.getters.loading('list')
}
return this.$store.getters.loading('list') || this.$store.getters['appApiApps/loading']('list')
return this.$store.getters.loading('list') || this.appApiStore.getLoading('list')
},
hasPendingUpdate() {
return this.apps.filter(app => app.update).length > 0
Expand All @@ -181,7 +189,7 @@ export default {
},
apps() {
// Exclude ExApps from the list if AppAPI is disabled
const exApps = this.$store.getters.isAppApiEnabled ? this.$store.getters['appApiApps/getAllApps'] : []
const exApps = this.$store.getters.isAppApiEnabled ? this.appApiStore.getAllApps : []
const apps = [...this.$store.getters.getAllApps, ...exApps]
.filter(app => app.name.toLowerCase().search(this.search.toLowerCase()) !== -1)
.sort(function(a, b) {
Expand Down
6 changes: 3 additions & 3 deletions apps/settings/src/components/AppList/AppItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@
@click.stop="update(app.id)">
{{ t('settings', 'Update to {update}', {update:app.update}) }}
</NcButton>
<NcButton v-if="app.canUnInstall"
<NcButton v-if="app.canUnInstall || app.canUninstall"
class="uninstall"
type="tertiary"
:disabled="installing || isLoading"
@click.stop="remove(app.id)">
{{ t('settings', 'Remove') }}
</NcButton>
<NcButton v-if="app.active"
:disabled="installing || isLoading || isInitializing || isDeploying"
:disabled="installing || isLoading || isInitializing || isDeploying"
@click.stop="disable(app.id)">
{{ disableButtonText }}
</NcButton>
Expand Down Expand Up @@ -184,7 +184,7 @@ export default {
return !!this.$route.params.id
},
shouldDisplayDefaultIcon() {
return this.listView && !this.app.preview || !this.listView && !this.screenshotLoaded
return (this.listView && !this.app.preview) || (!this.listView && !this.screenshotLoaded)
},
},
watch: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
<p><b>{{ t('settings', 'Type') }}</b>: {{ app?.daemon.accepts_deploy_id }}</p>
<p><b>{{ t('settings', 'Name') }}</b>: {{ app?.daemon.name }}</p>
<p><b>{{ t('settings', 'Display Name') }}</b>: {{ app?.daemon.display_name }}</p>
<p><b>{{ t('settings', 'GPUs support') }}</b>: {{ app?.daemon.deploy_config?.computeDevice?.id !== 'cpu' || 'false' }}</p>
<p><b>{{ t('settings', 'GPUs support') }}</b>: {{ gpuSupport }}</p>
<p><b>{{ t('settings', 'Compute device') }}</b>: {{ app?.daemon?.deploy_config?.computeDevice?.label }}</p>
</div>
</NcAppSidebarTab>
</template>
Expand All @@ -28,10 +29,13 @@ import NcAppSidebarTab from '@nextcloud/vue/dist/Components/NcAppSidebarTab.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'

import { mdiFileChart } from '@mdi/js'
import { ref } from 'vue'

defineProps<{
const props = defineProps<{
app: IAppstoreExApp,
}>()

const gpuSupport = ref(props.app?.daemon?.deploy_config?.computeDevice?.id !== 'cpu' || false)
</script>

<style scoped lang="scss">
Expand Down
14 changes: 10 additions & 4 deletions apps/settings/src/components/AppStoreSidebar/AppDetailsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
:value="t('settings', 'Update to {version}', { version: app.update })"
:disabled="installing || isLoading || isManualInstall"
@click="update(app.id)">
<input v-if="app.canUnInstall"
<input v-if="app.canUnInstall || app.canUninstall"
class="uninstall"
type="button"
:value="t('settings', 'Remove')"
Expand Down Expand Up @@ -78,7 +78,10 @@
:disabled="installing || isLoading"
@click="forceEnable(app.id)">
</div>
<NcCheckboxRadioSwitch v-if="app.canUnInstall"
<p v-if="!defaultDeployDaemonAccessible" class="warning">
{{ t('settings', 'Default Deploy daemon is not accessible') }}
</p>
<NcCheckboxRadioSwitch v-if="app.canUnInstall || app.canUninstall"
:checked="removeData"
:disabled="installing || isLoading || !defaultDeployDaemonAccessible"
@update:checked="toggleRemoveData">
Expand Down Expand Up @@ -110,7 +113,7 @@
<NcDateTime :timestamp="lastModified" />
</div>

<div class="app-details__section">
<div v-if="appAuthors" class="app-details__section">
<h4>
{{ t('settings', 'Author') }}
</h4>
Expand All @@ -119,7 +122,7 @@
</p>
</div>

<div class="app-details__section">
<div v-if="appCategories" class="app-details__section">
<h4>
{{ t('settings', 'Categories') }}
</h4>
Expand Down Expand Up @@ -194,6 +197,7 @@ import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadi
import AppManagement from '../../mixins/AppManagement.js'
import { mdiBug, mdiFeatureSearch, mdiStar, mdiTextBox, mdiTooltipQuestion } from '@mdi/js'
import { useAppsStore } from '../../store/apps-store'
import { useAppApiStore } from '../../store/app-api-store'

export default {
name: 'AppDetailsTab',
Expand All @@ -217,9 +221,11 @@ export default {

setup() {
const store = useAppsStore()
const appApiStore = useAppApiStore()

return {
store,
appApiStore,

mdiBug,
mdiFeatureSearch,
Expand Down
6 changes: 3 additions & 3 deletions apps/settings/src/composables/useAppIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export function useAppIcon(app: Ref<IAppstoreApp>) {
path = mdiCogOutline
} else {
path = [app.value?.category ?? []].flat()
.map((name) => AppstoreCategoryIcons[name])
.filter((icon) => !!icon)
.at(0)
.map((name) => AppstoreCategoryIcons[name])
.filter((icon) => !!icon)
.at(0)
?? (!app.value?.app_api ? mdiCog : mdiCogOutline)
}
return path ? `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="${path}" /></svg>` : null
Expand Down
104 changes: 61 additions & 43 deletions apps/settings/src/mixins/AppManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,40 @@

import { showError } from '@nextcloud/dialogs'
import rebuildNavigation from '../service/rebuild-navigation.js'
import { useAppApiStore } from '../store/app-api-store'

export default {
setup() {
const appApiStore = useAppApiStore()
return {
appApiStore,
}
},
computed: {
appGroups() {
return this.app.groups.map(group => { return { id: group, name: group } })
},
installing() {
if (this.app?.app_api) {
return this.app && this.$store.getters['appApiApps/loading']('install')
return this.app && this?.appApiStore.getLoading('install') === true
}
return this.$store.getters.loading('install')
},
isLoading() {
if (this.app?.app_api) {
return this.app && this.$store.getters['appApiApps/loading'](this.app.id)
return this.app && this?.appApiStore.getLoading(this.app.id) === true
}
return this.app && this.$store.getters.loading(this.app.id)
},
isInitializing() {
if (this.app?.app_api) {
return this.app && Object.hasOwn(this.app?.status, 'action') && (this.app.status.action === 'init' || this.app.status.action === 'healthcheck')
return this.app && (this.app?.status?.action === 'init' || this.app?.status?.action === 'healthcheck')
}
return false
},
isDeploying() {
if (this.app?.app_api) {
return this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'deploy'
return this.app && this.app?.status?.action === 'deploy'
}
return false
},
Expand Down Expand Up @@ -90,7 +97,7 @@ export default {
return t('settings', 'Allow untested app')
},
enableButtonTooltip() {
if (this.app.needsDownload) {
if (!this.app?.app_api && this.app.needsDownload) {
return t('settings', 'The app will be downloaded from the App Store')
}
return null
Expand All @@ -107,10 +114,11 @@ export default {
if (this.app?.daemon && this.app?.daemon?.accepts_deploy_id === 'manual-install') {
return true
}
if (this.app?.daemon?.accepts_deploy_id === 'docker-install') {
return this.$store.getters['appApiApps/getDaemonAccessible'] === true
if (this.app?.daemon?.accepts_deploy_id === 'docker-install'
&& this.appApiStore.getDefaultDaemon?.name === this.app?.daemon?.name) {
return this?.appApiStore.getDaemonAccessible === true
}
return this.$store.getters['appApiApps/getDaemonAccessible']
return this?.appApiStore.getDaemonAccessible
}
return true
},
Expand Down Expand Up @@ -177,63 +185,73 @@ export default {
this.$store.dispatch('enableApp', { appId: this.app.id, groups: currentGroups })
},
forceEnable(appId) {
let type = 'forceEnableApp'
if (this.app?.app_api) {
type = 'appApiApps/forceEnableApp'
this.appApiStore.forceEnableApp(appId)
.then(() => { rebuildNavigation() })
.catch((error) => { showError(error) })
} else {
this.$store.dispatch('forceEnableApp', { appId, groups: [] })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
}
this.$store.dispatch(type, { appId, groups: [] })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
},
enable(appId) {
let type = 'enableApp'
if (this.app?.app_api) {
type = 'appApiApps/enableApp'
this.appApiStore.enableApp(appId)
.then(() => { rebuildNavigation() })
.catch((error) => { showError(error) })
} else {
this.$store.dispatch('enableApp', { appId, groups: [] })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
}
this.$store.dispatch(type, { appId, groups: [] })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
},
disable(appId) {
let type = 'disableApp'
if (this.app?.app_api) {
type = 'appApiApps/disableApp'
this.appApiStore.disableApp(appId)
.then(() => { rebuildNavigation() })
.catch((error) => { showError(error) })
} else {
this.$store.dispatch('disableApp', { appId })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
}
this.$store.dispatch(type, { appId })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
},
remove(appId, removeData = false) {
let type = 'uninstallApp'
let payload = { appId }
if (this.app?.app_api) {
type = 'appApiApps/uninstallApp'
payload = { appId, removeData }
this.appApiStore.uninstallApp(appId, removeData)
.then(() => { rebuildNavigation() })
.catch((error) => { showError(error) })
} else {
this.$store.dispatch('appApiApps/uninstallApp', { appId, removeData })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
}
this.$store.dispatch(type, payload)
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
},
install(appId) {
let type = 'enableApp'
if (this.app?.app_api) {
type = 'appApiApps/enableApp'
this.appApiStore.enableApp(appId)
.then(() => { rebuildNavigation() })
.catch((error) => { showError(error) })
} else {
this.$store.dispatch('enableApp', { appId })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
}
this.$store.dispatch(type, { appId })
.then((response) => { rebuildNavigation() })
.catch((error) => { showError(error) })
},
update(appId) {
let type = 'updateApp'
if (this.app?.app_api) {
type = 'appApiApps/updateApp'
this.appApiStore.updateApp(appId)
.then(() => { rebuildNavigation() })
.catch((error) => { showError(error) })
} else {
this.$store.dispatch('updateApp', { appId })
.catch((error) => { showError(error) })
.then(() => {
rebuildNavigation()
this.store.updateCount = Math.max(this.store.updateCount - 1, 0)
})
}
this.$store.dispatch(type, { appId })
.catch((error) => { showError(error) })
.then(() => {
rebuildNavigation()
this.store.updateCount = Math.max(this.store.updateCount - 1, 0)
})
},
},
}
Loading