Skip to content

Commit 8cc588f

Browse files
authored
Merge pull request #57341 from nextcloud/refactor/federation-vue3
refactor(federation): migrate app frontend (admin settings) to Vue 3
2 parents 8a05a3e + 35bfa1d commit 8cc588f

File tree

180 files changed

+1126
-343
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

180 files changed

+1126
-343
lines changed

apps/federation/js/settings-admin.js

Lines changed: 0 additions & 116 deletions
This file was deleted.

apps/federation/lib/AppInfo/Application.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818

1919
class Application extends App implements IBootstrap {
2020

21+
public const APP_ID = 'federation';
22+
2123
/**
2224
* @param array $urlParams
2325
*/
2426
public function __construct($urlParams = []) {
25-
parent::__construct('federation', $urlParams);
27+
parent::__construct(self::APP_ID, $urlParams);
2628
}
2729

2830
public function register(IRegistrationContext $context): void {

apps/federation/lib/Settings/Admin.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
<?php
22

3-
/**
3+
/*!
44
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
55
* SPDX-License-Identifier: AGPL-3.0-or-later
66
*/
77
namespace OCA\Federation\Settings;
88

9+
use OCA\Federation\AppInfo\Application;
910
use OCA\Federation\TrustedServers;
1011
use OCP\AppFramework\Http\TemplateResponse;
12+
use OCP\AppFramework\Services\IInitialState;
1113
use OCP\IL10N;
14+
use OCP\IURLGenerator;
1215
use OCP\Settings\IDelegatedSettings;
16+
use OCP\Util;
1317

1418
class Admin implements IDelegatedSettings {
1519
public function __construct(
1620
private TrustedServers $trustedServers,
21+
private IInitialState $initialState,
22+
private IURLGenerator $urlGenerator,
1723
private IL10N $l,
1824
) {
1925
}
@@ -24,9 +30,14 @@ public function __construct(
2430
public function getForm() {
2531
$parameters = [
2632
'trustedServers' => $this->trustedServers->getServers(),
33+
'docUrl' => $this->urlGenerator->linkToDocs('admin-sharing-federated') . '#configuring-trusted-nextcloud-servers',
2734
];
2835

29-
return new TemplateResponse('federation', 'settings-admin', $parameters, '');
36+
$this->initialState->provideInitialState('adminSettings', $parameters);
37+
38+
Util::addStyle(Application::APP_ID, 'settings-admin');
39+
Util::addScript(Application::APP_ID, 'settings-admin');
40+
return new TemplateResponse(Application::APP_ID, 'settings-admin', renderAs: '');
3041
}
3142

3243
/**
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<!--
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<script setup lang="ts">
7+
import type { ITrustedServer } from '../services/api.ts'
8+
9+
import { mdiPlus } from '@mdi/js'
10+
import { showError, showSuccess } from '@nextcloud/dialogs'
11+
import { t } from '@nextcloud/l10n'
12+
import { nextTick, ref, useTemplateRef } from 'vue'
13+
import NcButton from '@nextcloud/vue/components/NcButton'
14+
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
15+
import NcTextField from '@nextcloud/vue/components/NcTextField'
16+
import { addServer, ApiError } from '../services/api.ts'
17+
import { logger } from '../services/logger.ts'
18+
19+
const emit = defineEmits<{
20+
add: [server: ITrustedServer]
21+
}>()
22+
23+
const formElement = useTemplateRef<HTMLFormElement>('form')
24+
const newServerUrl = ref('')
25+
26+
/**
27+
* Handle add trusted server form submission
28+
*/
29+
async function onAdd() {
30+
try {
31+
const server = await addServer(newServerUrl.value)
32+
newServerUrl.value = ''
33+
emit('add', server)
34+
35+
nextTick(() => formElement.value?.reset()) // Reset native form validation state
36+
showSuccess(t('federation', 'Added to the list of trusted servers'))
37+
} catch (error) {
38+
logger.error('Failed to add trusted server', { error })
39+
if (error instanceof ApiError) {
40+
showError(error.message)
41+
} else {
42+
showError(t('federation', 'Could not add trusted server. Please try again later.'))
43+
}
44+
}
45+
}
46+
</script>
47+
48+
<template>
49+
<form ref="form" @submit.prevent="onAdd">
50+
<h3 :class="$style.addTrustedServerForm__heading">
51+
{{ t('federation', 'Add trusted server') }}
52+
</h3>
53+
<div :class="$style.addTrustedServerForm__wrapper">
54+
<NcTextField
55+
v-model="newServerUrl"
56+
:label="t('federation', 'Server url')"
57+
placeholder="https://…"
58+
required
59+
type="url" />
60+
<NcButton
61+
:class="$style.addTrustedServerForm__submitButton"
62+
:aria-label="t('federation', 'Add')"
63+
:title="t('federation', 'Add')"
64+
type="submit"
65+
variant="primary">
66+
<template #icon>
67+
<NcIconSvgWrapper :path="mdiPlus" />
68+
</template>
69+
</NcButton>
70+
</div>
71+
</form>
72+
</template>
73+
74+
<style module>
75+
.addTrustedServerForm__heading {
76+
font-size: 1.2rem;
77+
margin-block: 0.5lh 0.25lh;
78+
}
79+
80+
.addTrustedServerForm__wrapper {
81+
display: flex;
82+
gap: var(--default-grid-baseline);
83+
align-items: end;
84+
max-width: 600px;
85+
}
86+
87+
.addTrustedServerForm__submitButton {
88+
max-height: var(--default-clickable-area);
89+
}
90+
</style>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<!--
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<script setup lang="ts">
7+
import type { ITrustedServer } from '../services/api.ts'
8+
9+
import { mdiCheckNetworkOutline, mdiCloseNetworkOutline, mdiHelpNetworkOutline, mdiTrashCanOutline } from '@mdi/js'
10+
import { showError } from '@nextcloud/dialogs'
11+
import { t } from '@nextcloud/l10n'
12+
import { computed, ref } from 'vue'
13+
import NcButton from '@nextcloud/vue/components/NcButton'
14+
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
15+
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
16+
import { TrustedServerStatus } from '../services/api.ts'
17+
import { deleteServer } from '../services/api.ts'
18+
import { logger } from '../services/logger.ts'
19+
20+
const props = defineProps<{
21+
server: ITrustedServer
22+
}>()
23+
24+
const emit = defineEmits<{
25+
delete: [ITrustedServer]
26+
}>()
27+
28+
const isLoading = ref(false)
29+
30+
const hasError = computed(() => props.server.status === TrustedServerStatus.STATUS_FAILURE)
31+
const serverIcon = computed(() => {
32+
switch (props.server.status) {
33+
case TrustedServerStatus.STATUS_OK:
34+
return mdiCheckNetworkOutline
35+
case TrustedServerStatus.STATUS_PENDING:
36+
case TrustedServerStatus.STATUS_ACCESS_REVOKED:
37+
return mdiHelpNetworkOutline
38+
case TrustedServerStatus.STATUS_FAILURE:
39+
default:
40+
return mdiCloseNetworkOutline
41+
}
42+
})
43+
44+
const serverStatus = computed(() => {
45+
switch (props.server.status) {
46+
case TrustedServerStatus.STATUS_OK:
47+
return [t('federation', 'Server ok'), t('federation', 'User list was exchanged at least once successfully with the remote server.')]
48+
case TrustedServerStatus.STATUS_PENDING:
49+
return [t('federation', 'Server pending'), t('federation', 'Waiting for shared secret or initial user list exchange.')]
50+
case TrustedServerStatus.STATUS_ACCESS_REVOKED:
51+
return [t('federation', 'Server access revoked'), t('federation', 'Server access revoked')]
52+
case TrustedServerStatus.STATUS_FAILURE:
53+
default:
54+
return [t('federation', 'Server failure'), t('federation', 'Connection to the remote server failed or the remote server is misconfigured.')]
55+
}
56+
})
57+
58+
/**
59+
* Emit delete event
60+
*/
61+
async function onDelete() {
62+
try {
63+
isLoading.value = true
64+
await deleteServer(props.server.id)
65+
emit('delete', props.server)
66+
} catch (error) {
67+
isLoading.value = false
68+
logger.error('Failed to delete trusted server', { error })
69+
showError(t('federation', 'Failed to delete trusted server. Please try again later.'))
70+
}
71+
}
72+
</script>
73+
74+
<template>
75+
<li :class="$style.trustedServer">
76+
<NcIconSvgWrapper
77+
:class="{
78+
[$style.trustedServer__icon_error]: hasError,
79+
}"
80+
:path="serverIcon"
81+
:name="serverStatus[0]"
82+
:title="serverStatus[1]" />
83+
84+
<code :class="$style.trustedServer__url" v-text="server.url" />
85+
86+
<NcButton
87+
:aria-label="t('federation', 'Delete')"
88+
:title="t('federation', 'Delete')"
89+
:disabled="isLoading"
90+
@click="onDelete">
91+
<template #icon>
92+
<NcLoadingIcon v-if="isLoading" />
93+
<NcIconSvgWrapper v-else :path="mdiTrashCanOutline" />
94+
</template>
95+
</NcButton>
96+
</li>
97+
</template>
98+
99+
<style module>
100+
.trustedServer {
101+
display: flex;
102+
flex-direction: row;
103+
gap: var(--default-grid-baseline);
104+
align-items: center;
105+
border-radius: var(--border-radius-element);
106+
padding-inline-start: var(--default-grid-baseline);
107+
}
108+
109+
.trustedServer:hover {
110+
background-color: var(--color-background-hover);
111+
}
112+
113+
.trustedServer__icon_error {
114+
color: var(--color-element-error);
115+
}
116+
117+
.trustedServer__url {
118+
padding-inline: 1ch;
119+
flex: 1 0 auto;
120+
}
121+
</style>

0 commit comments

Comments
 (0)