Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable30] feat(settings): migrate AppAPI ExApps management to settings #48988

Merged
merged 21 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 11 additions & 0 deletions apps/settings/lib/Controller/AppSettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Server;
use Psr\Log\LoggerInterface;

#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
Expand Down Expand Up @@ -77,6 +78,8 @@ public function __construct(
}

/**
* @psalm-suppress UndefinedClass AppAPI is shipped since 30.0.1
*
* @return TemplateResponse
*/
#[NoCSRFRequired]
Expand All @@ -88,6 +91,13 @@ public function viewApps(): TemplateResponse {
$this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual'));
$this->initialState->provideInitialState('appstoreUpdateCount', count($this->getAppsWithUpdates()));

if ($this->appManager->isInstalled('app_api')) {
try {
Server::get(\OCA\AppAPI\Service\ExAppsPageService::class)->provideAppApiState($this->initialState);
} catch (\Psr\Container\NotFoundExceptionInterface|\Psr\Container\ContainerExceptionInterface $e) {
}
}

$policy = new ContentSecurityPolicy();
$policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');

Expand Down Expand Up @@ -431,6 +441,7 @@ private function getAppsForCategory($requestedCategory = ''): array {

$formattedApps[] = [
'id' => $app['id'],
'app_api' => false,
'name' => $app['translations'][$currentLanguage]['name'] ?? $app['translations']['en']['name'],
'description' => $app['translations'][$currentLanguage]['description'] ?? $app['translations']['en']['description'],
'summary' => $app['translations'][$currentLanguage]['summary'] ?? $app['translations']['en']['summary'],
Expand Down
44 changes: 42 additions & 2 deletions apps/settings/src/app-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,54 @@ export interface IAppstoreApp {
preview?: string
screenshot?: string

app_api: boolean
active: boolean
internal: boolean
removeable: boolean
removable: boolean
installed: boolean
canInstall: boolean
canUninstall: boolean
canUnInstall: boolean
isCompatible: boolean
needsDownload: boolean
update?: string

appstoreData: Record<string, never>
releases?: IAppstoreAppRelease[]
}

export interface IComputeDevice {
id: string,
label: string,
}

export interface IDeployConfig {
computeDevice: IComputeDevice,
net: string,
nextcloud_url: string,
}

export interface IDeployDaemon {
accepts_deploy_id: string,
deploy_config: IDeployConfig,
display_name: string,
host: string,
id: number,
name: string,
protocol: string,
}

export interface IExAppStatus {
action: string
deploy: number
deploy_start_time: number
error: string
init: number
init_start_time: number
type: string
}

export interface IAppstoreExApp extends IAppstoreApp {
daemon: IDeployDaemon | null | undefined
status: IExAppStatus | Record<string, never>
error: string
}
18 changes: 10 additions & 8 deletions apps/settings/src/components/AppList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,10 @@

<script>
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { useAppsStore } from '../store/apps-store'
import AppItem from './AppList/AppItem.vue'
import pLimit from 'p-limit'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import AppManagement from '../mixins/AppManagement'
import { useAppApiStore } from '../store/app-api-store'

export default {
name: 'AppList',
Expand All @@ -153,8 +152,6 @@ export default {
NcButton,
},

mixins: [AppManagement],

props: {
category: {
type: String,
Expand All @@ -163,9 +160,9 @@ export default {
},

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

Expand All @@ -179,7 +176,10 @@ export default {
return this.apps.filter(app => app.update).length
},
loading() {
return this.$store.getters.loading('list')
if (!this.$store.getters['appApiApps/isAppApiEnabled']) {
return this.$store.getters.loading('list')
}
return this.$store.getters.loading('list') || this.appApiStore.getLoading('list')
},
hasPendingUpdate() {
return this.apps.filter(app => app.update).length > 0
Expand All @@ -188,7 +188,9 @@ export default {
return this.hasPendingUpdate && this.useListView
},
apps() {
const apps = this.$store.getters.getAllApps
// Exclude ExApps from the list if AppAPI is disabled
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) {
const sortStringA = '' + (a.active ? 0 : 1) + (a.update ? 0 : 1) + a.name
Expand Down
37 changes: 37 additions & 0 deletions apps/settings/src/components/AppList/AppDaemonBadge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<span v-if="daemon"
class="app-daemon-badge"
:title="daemon.name">
<NcIconSvgWrapper :path="mdiFileChart" :size="20" inline />
{{ daemon.display_name }}
</span>
</template>

<script setup lang="ts">
import type { IDeployDaemon } from '../../app-types.ts'
import { mdiFileChart } from '@mdi/js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'

defineProps<{
daemon?: IDeployDaemon
}>()
</script>

<style scoped lang="scss">
.app-daemon-badge {
color: var(--color-text-maxcontrast);
background-color: transparent;
border: 1px solid var(--color-text-maxcontrast);
border-radius: var(--border-radius);

display: flex;
flex-direction: row;
gap: 6px;
padding: 3px 6px;
width: fit-content;
}
</style>
36 changes: 27 additions & 9 deletions apps/settings/src/components/AppList/AppItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
<component :is="dataItemTag"
class="app-image app-image-icon"
:headers="getDataItemHeaders(`app-table-col-icon`)">
<div v-if="(listView && !app.preview) || (!listView && !screenshotLoaded)" class="icon-settings-dark" />
<div v-if="!app?.app_api && shouldDisplayDefaultIcon" class="icon-settings-dark" />
<NcIconSvgWrapper v-else-if="app.app_api && shouldDisplayDefaultIcon"
:path="mdiCogOutline"
:size="listView ? 24 : 48"
style="min-width: auto; min-height: auto; height: 100%;" />

<svg v-else-if="listView && app.preview"
<svg v-else-if="listView && app.preview && !app.app_api"
width="32"
height="32"
viewBox="0 0 32 32">
Expand Down Expand Up @@ -71,10 +75,11 @@
<div v-if="app.error" class="warning">
{{ app.error }}
</div>
<div v-if="isLoading" class="icon icon-loading-small" />
<div v-if="isLoading || isInitializing" class="icon icon-loading-small" />
<NcButton v-if="app.update"
type="primary"
:disabled="installing || isLoading"
:disabled="installing || isLoading || !defaultDeployDaemonAccessible || isManualInstall"
:title="updateButtonText"
@click.stop="update(app.id)">
{{ t('settings', 'Update to {update}', {update:app.update}) }}
</NcButton>
Expand All @@ -86,23 +91,23 @@
{{ t('settings', 'Remove') }}
</NcButton>
<NcButton v-if="app.active"
:disabled="installing || isLoading"
:disabled="installing || isLoading || isInitializing || isDeploying"
@click.stop="disable(app.id)">
{{ t('settings','Disable') }}
{{ disableButtonText }}
</NcButton>
<NcButton v-if="!app.active && (app.canInstall || app.isCompatible)"
:title="enableButtonTooltip"
:aria-label="enableButtonTooltip"
type="primary"
:disabled="!app.canInstall || installing || isLoading"
:disabled="!app.canInstall || installing || isLoading || !defaultDeployDaemonAccessible || isInitializing || isDeploying"
@click.stop="enable(app.id)">
{{ enableButtonText }}
</NcButton>
<NcButton v-else-if="!app.active"
:title="forceEnableButtonTooltip"
:aria-label="forceEnableButtonTooltip"
type="secondary"
:disabled="installing || isLoading"
:disabled="installing || isLoading || !defaultDeployDaemonAccessible"
@click.stop="forceEnable(app.id)">
{{ forceEnableButtonText }}
</NcButton>
Expand All @@ -118,13 +123,17 @@ import AppLevelBadge from './AppLevelBadge.vue'
import AppManagement from '../../mixins/AppManagement.js'
import SvgFilterMixin from '../SvgFilterMixin.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
import { mdiCogOutline } from '@mdi/js'
import { useAppApiStore } from '../../store/app-api-store.ts'

export default {
name: 'AppItem',
components: {
AppLevelBadge,
AppScore,
NcButton,
NcIconSvgWrapper,
},
mixins: [AppManagement, SvgFilterMixin],
props: {
Expand Down Expand Up @@ -155,7 +164,13 @@ export default {
},
setup() {
const store = useAppsStore()
return { store }
const appApiStore = useAppApiStore()

return {
store,
appApiStore,
mdiCogOutline,
}
},
data() {
return {
Expand All @@ -174,6 +189,9 @@ export default {
withSidebar() {
return !!this.$route.params.id
},
shouldDisplayDefaultIcon() {
return (this.listView && !this.app.preview) || (!this.listView && !this.screenshotLoaded)
},
},
watch: {
'$route.params.id'(id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<template>
<NcAppSidebarTab v-if="app?.daemon"
id="daemon"
:name="t('settings', 'Daemon')"
:order="3">
<template #icon>
<NcIconSvgWrapper :path="mdiFileChart" :size="24" />
</template>
<div class="daemon">
<h4>{{ t('settings', 'Deploy Daemon') }}</h4>
<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>: {{ gpuSupport }}</p>
<p><b>{{ t('settings', 'Compute device') }}</b>: {{ app?.daemon?.deploy_config?.computeDevice?.label }}</p>
</div>
</NcAppSidebarTab>
</template>

<script setup lang="ts">
import type { IAppstoreExApp } from '../../app-types'

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'

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

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

<style scoped lang="scss">
.daemon {
padding: 20px;

h4 {
font-weight: bold;
margin: 10px auto;
}
}
</style>
Loading
Loading