Skip to content

Commit

Permalink
WIP: address review comments, small fixes
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Borysenko <[email protected]>
  • Loading branch information
andrey18106 committed Oct 17, 2024
1 parent 2068375 commit 5cc9df8
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 81 deletions.
42 changes: 7 additions & 35 deletions apps/settings/lib/Controller/AppSettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,12 @@ public function viewApps(): TemplateResponse {
$this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual'));
$this->initialState->provideInitialState('appstoreUpdateCount', count($this->getAppsWithUpdates()));

$this->provideAppApiState();
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 All @@ -102,40 +107,6 @@ public function viewApps(): TemplateResponse {
return $templateResponse;
}

/**
* @psalm-suppress UndefinedClass
*/
private function provideAppApiState(): void {
$appApiEnabled = $this->appManager->isInstalled('app_api');
$this->initialState->provideInitialState('appApiEnabled', $appApiEnabled);
$daemonConfigAccessible = false;
$defaultDaemonConfig = null;

if ($appApiEnabled) {
$exAppFetcher = Server::get(\OCA\AppAPI\Fetcher\ExAppFetcher::class);
$this->initialState->provideInitialState('appstoreExAppUpdateCount', count($exAppFetcher->getExAppsWithUpdates()));

$defaultDaemonConfigName = $this->config->getAppValue('app_api', 'default_daemon_config');
if ($defaultDaemonConfigName !== '') {
$daemonConfigService = Server::get(\OCA\AppAPI\Service\DaemonConfigService::class);
$daemonConfig = $daemonConfigService->getDaemonConfigByName($defaultDaemonConfigName);
if ($daemonConfig !== null) {
$defaultDaemonConfig = $daemonConfig->jsonSerialize();
unset($defaultDaemonConfig['deploy_config']['haproxy_password']);
$dockerActions = Server::get(\OCA\AppAPI\DeployActions\DockerActions::class);
$dockerActions->initGuzzleClient($daemonConfig);
$daemonConfigAccessible = $dockerActions->ping($dockerActions->buildDockerUrl($daemonConfig));
if (!$daemonConfigAccessible) {
$this->logger->warning(sprintf('Deploy daemon "%s" is not accessible by Nextcloud. Please verify its configuration', $daemonConfig->getName()));
}
}
}
}

$this->initialState->provideInitialState('defaultDaemonConfigAccessible', $daemonConfigAccessible);
$this->initialState->provideInitialState('defaultDaemonConfig', $defaultDaemonConfig);
}

/**
* Get all active entries for the app discover section
*/
Expand Down Expand Up @@ -449,6 +420,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
25 changes: 14 additions & 11 deletions apps/settings/src/app-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ export interface IAppstoreApp {
preview?: string
screenshot?: string

app_api: boolean
active: boolean
internal: boolean
removeable: boolean
installed: boolean
canInstall: boolean
canUninstall: boolean
isCompatible: boolean
needsDownload: boolean
update: string | null

appstoreData: Record<string, never>
releases?: IAppstoreAppRelease[]
Expand Down Expand Up @@ -75,18 +78,18 @@ export interface IDeployDaemon {
}

export interface IExAppStatus {
action: string,
deploy: number,
deploy_start_time: number,
error: string,
init: number,
init_start_time: number,
type: string,
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,
status: IExAppStatus,
error: string,
app_api: boolean,
daemon: IDeployDaemon | null | undefined
status: IExAppStatus | Record<string, never>
error: string
removable: boolean
}
8 changes: 6 additions & 2 deletions apps/settings/src/components/AppList/AppItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
<component :is="dataItemTag"
class="app-image app-image-icon"
:headers="getDataItemHeaders(`app-table-col-icon`)">
<div v-if="(listView && !app.preview && !app?.app_api) || (!listView && !screenshotLoaded && !app?.app_api)" class="icon-settings-dark" />
<NcIconSvgWrapper v-else-if="(listView && app?.app_api && !app.preview) || (!listView && !screenshotLoaded && app?.app_api)"
<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%;" />
Expand Down Expand Up @@ -79,6 +79,7 @@
<NcButton v-if="app.update"
type="primary"
:disabled="installing || isLoading || !defaultDeployDaemonAccessible || isManualInstall"
:title="updateButtonText"
@click.stop="update(app.id)">
{{ t('settings', 'Update to {update}', {update:app.update}) }}
</NcButton>
Expand Down Expand Up @@ -176,6 +177,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
Expand Up @@ -12,11 +12,11 @@
<NcIconSvgWrapper :path="mdiFileChart" :size="24" />
</template>
<div class="daemon">
<h4>{{ t('app_api', 'Deploy Daemon') }}</h4>
<p><b>{{ t('app_api', 'Type') }}</b>: {{ app?.daemon.accepts_deploy_id }}</p>
<p><b>{{ t('app_api', 'Name') }}</b>: {{ app?.daemon.name }}</p>
<p><b>{{ t('app_api', 'Display Name') }}</b>: {{ app?.daemon.display_name }}</p>
<p><b>{{ t('app_api', 'GPUs support') }}</b>: {{ app?.daemon.deploy_config?.computeDevice?.id !== 'cpu' || 'false' }}</p>
<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>: {{ app?.daemon.deploy_config?.computeDevice?.id !== 'cpu' || 'false' }}</p>
</div>
</NcAppSidebarTab>
</template>
Expand Down
18 changes: 12 additions & 6 deletions apps/settings/src/composables/useAppIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import type { Ref } from 'vue'
import type { IAppstoreApp } from '../app-types.ts'

import { mdiCog } from '@mdi/js'
import { mdiCog, mdiCogOutline } from '@mdi/js'
import { computed, ref, watchEffect } from 'vue'
import AppstoreCategoryIcons from '../constants/AppstoreCategoryIcons.ts'
import logger from '../logger.ts'
Expand All @@ -23,11 +23,17 @@ export function useAppIcon(app: Ref<IAppstoreApp>) {
* Fallback value if no app icon available
*/
const categoryIcon = computed(() => {
const path = [app.value?.category ?? []].flat()
.map((name) => AppstoreCategoryIcons[name])
.filter((icon) => !!icon)
.at(0)
?? mdiCog
let path: string
if (app.value?.app_api) {
// Use different default icon for ExApps (AppAPI)
path = mdiCogOutline
} else {
path = [app.value?.category ?? []].flat()
.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
36 changes: 18 additions & 18 deletions apps/settings/src/mixins/AppManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,26 @@ export default {
return false
},
updateButtonText() {
if (this.app?.daemon?.accepts_deploy_id === 'manual-install') {
return t('app_api', 'manual-install apps cannot be updated')
if (this.app?.app_api && this.app?.daemon?.accepts_deploy_id === 'manual-install') {
return t('settings', 'manual-install apps cannot be updated')
}
return ''
return t('settings', 'Update to {version}', { version: this.app?.update })
},
enableButtonText() {
if (this.app?.app_api) {
if (this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'deploy') {
return t('app_api', '{progress}% Deploying', { progress: this.app.status?.deploy })
if (this.app && this.app?.status?.action && this.app?.status?.action === 'deploy') {
return t('settings', '{progress}% Deploying', { progress: this.app?.status?.deploy ?? 0 })
}
if (this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'init') {
return t('app_api', '{progress}% Initializing', { progress: this.app.status?.init })
if (this.app && this.app?.status?.action && this.app?.status?.action === 'init') {
return t('settings', '{progress}% Initializing', { progress: this.app?.status?.init ?? 0 })
}
if (this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'healthcheck') {
return t('app_api', 'Healthchecking')
if (this.app && this.app?.status?.action && this.app?.status?.action === 'healthcheck') {
return t('settings', 'Health checking')
}
if (this.app.needsDownload) {
return t('app_api', 'Deploy and Enable')
return t('settings', 'Deploy and Enable')
}
return t('app_api', 'Enable')
return t('settings', 'Enable')
} else {
if (this.app.needsDownload) {
return t('settings', 'Download and enable')
Expand All @@ -71,17 +71,17 @@ export default {
},
disableButtonText() {
if (this.app?.app_api) {
if (this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'deploy') {
return t('app_api', '{progress}% Deploying', { progress: this.app.status?.deploy })
if (this.app && this.app?.status?.action && this.app?.status?.action === 'deploy') {
return t('settings', '{progress}% Deploying', { progress: this.app?.status?.deploy })
}
if (this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'init') {
return t('app_api', '{progress}% Initializing', { progress: this.app.status?.init })
if (this.app && this.app?.status?.action && this.app?.status?.action === 'init') {
return t('settings', '{progress}% Initializing', { progress: this.app?.status?.init })
}
if (this.app && Object.hasOwn(this.app?.status, 'action') && this.app.status.action === 'healthcheck') {
return t('app_api', 'Healthchecking')
if (this.app && this.app?.status?.action && this.app?.status?.action === 'healthcheck') {
return t('settings', 'Health checking')
}
}
return t('app_api', 'Disable')
return t('settings', 'Disable')
},
forceEnableButtonText() {
if (this.app.needsDownload) {
Expand Down
4 changes: 2 additions & 2 deletions apps/settings/src/store/app_api_apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const state = {
const mutations = {

APPS_API_FAILURE(state, error) {
showError(t('app_api', 'An error occurred during the request. Unable to proceed.') + '<br>' + error.error.response.data.data.message, { isHTML: true })
showError(t('settings', 'An error occurred during the request. Unable to proceed.') + '<br>' + error.error.response.data.data.message, { isHTML: true })
console.error(state, error)
},

Expand Down Expand Up @@ -227,7 +227,7 @@ const actions = {
.catch(() => {
context.commit('setError', {
appId: [appId],
error: t('app_api', 'Error: This app cannot be enabled because it makes the server unstable'),
error: t('settings', 'Error: This app cannot be enabled because it makes the server unstable'),
})
})
})
Expand Down
2 changes: 1 addition & 1 deletion apps/settings/src/store/apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const state = {
updateCount: loadState('settings', 'appstoreUpdateCount', 0),
loading: {},
gettingCategoriesPromise: null,
appApiEnabled: loadState('settings', 'appApiEnabled'),
appApiEnabled: loadState('settings', 'appApiEnabled', false),
}

const mutations = {
Expand Down
10 changes: 9 additions & 1 deletion apps/settings/src/views/AppStoreSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,15 @@ const { appIcon } = useAppIcon(app)
/**
* The second text line shown on the sidebar
*/
const licenseText = computed(() => app.value ? t('settings', 'Version {version}, {license}-licensed', { version: app.value.version, license: app.value.licence.toString().toUpperCase() }) : '')
const licenseText = computed(() => {
if (!app.value) {
return ''
}
if (app.value.license !== '') {
return t('settings', 'Version {version}, {license}-licensed', { version: app.value.version, license: app.value.licence.toString().toUpperCase() })
}
return t('settings', 'Version {version}', { version: app.value.version })
})

const activeTab = ref('details')
watch([app], () => { activeTab.value = 'details' })
Expand Down

0 comments on commit 5cc9df8

Please sign in to comment.