diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php
index c4954948a72..b77c76acf5a 100644
--- a/apps/federatedfilesharing/lib/AppInfo/Application.php
+++ b/apps/federatedfilesharing/lib/AppInfo/Application.php
@@ -16,12 +16,14 @@ use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
-use OCP\AppFramework\IAppContainer;
use OCP\Federation\ICloudFederationProviderManager;
class Application extends App implements IBootstrap {
+
+ public const APP_ID = 'federatedfilesharing';
+
public function __construct() {
- parent::__construct('federatedfilesharing');
+ parent::__construct(self::APP_ID);
}
public function register(IRegistrationContext $context): void {
@@ -33,14 +35,13 @@ class Application extends App implements IBootstrap {
$context->injectFn(Closure::fromCallable([$this, 'registerCloudFederationProvider']));
}
- private function registerCloudFederationProvider(ICloudFederationProviderManager $manager,
- IAppContainer $appContainer): void {
+ private function registerCloudFederationProvider(ICloudFederationProviderManager $manager): void {
$fileResourceTypes = ['file', 'folder'];
foreach ($fileResourceTypes as $type) {
$manager->addCloudFederationProvider($type,
'Federated Files Sharing',
- function () use ($appContainer): CloudFederationProviderFiles {
- return $appContainer->get(CloudFederationProviderFiles::class);
+ function (): CloudFederationProviderFiles {
+ return \OCP\Server::get(CloudFederationProviderFiles::class);
});
}
}
diff --git a/apps/federatedfilesharing/lib/Listeners/LoadAdditionalScriptsListener.php b/apps/federatedfilesharing/lib/Listeners/LoadAdditionalScriptsListener.php
index 34fbd85db5a..b8a4a7d03e7 100644
--- a/apps/federatedfilesharing/lib/Listeners/LoadAdditionalScriptsListener.php
+++ b/apps/federatedfilesharing/lib/Listeners/LoadAdditionalScriptsListener.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
*/
namespace OCA\FederatedFileSharing\Listeners;
+use OCA\FederatedFileSharing\AppInfo\Application;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCP\App\IAppManager;
@@ -35,7 +36,8 @@ class LoadAdditionalScriptsListener implements IEventListener {
if ($this->federatedShareProvider->isIncomingServer2serverShareEnabled()) {
$this->initialState->provideInitialState('notificationsEnabled', $this->appManager->isEnabledForUser('notifications'));
- Util::addInitScript('federatedfilesharing', 'external');
+ Util::addStyle(Application::APP_ID, 'init-files');
+ Util::addInitScript(Application::APP_ID, 'init-files');
}
}
}
diff --git a/apps/federatedfilesharing/lib/Settings/Admin.php b/apps/federatedfilesharing/lib/Settings/Admin.php
index fc685f952c7..e66f1a1e417 100644
--- a/apps/federatedfilesharing/lib/Settings/Admin.php
+++ b/apps/federatedfilesharing/lib/Settings/Admin.php
@@ -6,6 +6,7 @@
*/
namespace OCA\FederatedFileSharing\Settings;
+use OCA\FederatedFileSharing\AppInfo\Application;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
@@ -43,7 +44,9 @@ class Admin implements IDelegatedSettings {
$this->initialState->provideInitialState('lookupServerUploadEnabled', $this->fedShareProvider->isLookupServerUploadEnabled());
$this->initialState->provideInitialState('federatedTrustedShareAutoAccept', $this->fedShareProvider->isFederatedTrustedShareAutoAccept());
- return new TemplateResponse('federatedfilesharing', 'settings-admin', [], '');
+ \OCP\Util::addStyle(Application::APP_ID, 'settings-admin');
+ \OCP\Util::addScript(Application::APP_ID, 'settings-admin');
+ return new TemplateResponse(Application::APP_ID, 'settings-admin', renderAs: '');
}
/**
diff --git a/apps/federatedfilesharing/lib/Settings/Personal.php b/apps/federatedfilesharing/lib/Settings/Personal.php
index 2889fb77c1f..fc401c404d4 100644
--- a/apps/federatedfilesharing/lib/Settings/Personal.php
+++ b/apps/federatedfilesharing/lib/Settings/Personal.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
*/
namespace OCA\FederatedFileSharing\Settings;
+use OCA\FederatedFileSharing\AppInfo\Application;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
@@ -41,7 +42,9 @@ class Personal implements ISettings {
$this->initialState->provideInitialState('cloudId', $cloudID);
$this->initialState->provideInitialState('docUrlFederated', $this->urlGenerator->linkToDocs('user-sharing-federated'));
- return new TemplateResponse('federatedfilesharing', 'settings-personal', [], TemplateResponse::RENDER_AS_BLANK);
+ \OCP\Util::addStyle(Application::APP_ID, 'settings-personal');
+ \OCP\Util::addScript(Application::APP_ID, 'settings-personal');
+ return new TemplateResponse(Application::APP_ID, 'settings-personal', renderAs: TemplateResponse::RENDER_AS_BLANK);
}
/**
diff --git a/apps/federatedfilesharing/src/components/AdminSettings.vue b/apps/federatedfilesharing/src/components/AdminSettings.vue
index fad255c87ec..a9546d276c7 100644
--- a/apps/federatedfilesharing/src/components/AdminSettings.vue
+++ b/apps/federatedfilesharing/src/components/AdminSettings.vue
@@ -2,38 +2,184 @@
- SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
+
+
+
+ v-model="state.outgoingServer2serverShareEnabled"
+ type="switch">
{{ t('federatedfilesharing', 'Allow people on this server to send shares to other servers (this option also allows WebDAV access to public shares)') }}
+ v-model="state.incomingServer2serverShareEnabled"
+ type="switch">
{{ t('federatedfilesharing', 'Allow people on this server to receive shares from other servers') }}
+ v-if="state.federatedGroupSharingSupported"
+ v-model="state.outgoingServer2serverGroupShareEnabled"
+ type="switch">
{{ t('federatedfilesharing', 'Allow people on this server to send shares to groups on other servers') }}
+ v-if="state.federatedGroupSharingSupported"
+ v-model="state.incomingServer2serverGroupShareEnabled"
+ type="switch">
{{ t('federatedfilesharing', 'Allow people on this server to receive group shares from other servers') }}
@@ -42,17 +188,17 @@
+ @update:model-value="showLookupServerConfirmation">
{{ t('federatedfilesharing', 'Search global and public address book for people') }}
+ @update:model-value="showLookupServerUploadConfirmation">
{{ t('federatedfilesharing', 'Allow people to publish their data to a global and public address book') }}
@@ -63,147 +209,14 @@
{{ t('federatedfilesharing', 'Trusted federation') }}
+ v-model="state.federatedTrustedShareAutoAccept"
+ type="switch">
{{ t('federatedfilesharing', 'Automatically accept shares from trusted federated accounts and groups by default') }}
-
-
diff --git a/apps/federatedfilesharing/src/external.js b/apps/federatedfilesharing/src/init-files.js
similarity index 95%
rename from apps/federatedfilesharing/src/external.js
rename to apps/federatedfilesharing/src/init-files.js
index d42947f7880..4efcb2b699b 100644
--- a/apps/federatedfilesharing/src/external.js
+++ b/apps/federatedfilesharing/src/init-files.js
@@ -13,33 +13,6 @@ import { generateUrl } from '@nextcloud/router'
import { showRemoteShareDialog } from './services/dialogService.ts'
import logger from './services/logger.ts'
-window.OCA.Sharing = window.OCA.Sharing ?? {}
-
-/**
- * Shows "add external share" dialog.
- *
- * @param {object} share the share
- * @param {string} share.remote remote server URL
- * @param {string} share.owner owner name
- * @param {string} share.name name of the shared folder
- * @param {string} share.token authentication token
- * @param {boolean} passwordProtected true if the share is password protected
- * @param {Function} callback the callback
- */
-window.OCA.Sharing.showAddExternalDialog = function(share, passwordProtected, callback) {
- const owner = share.ownerDisplayName || share.owner
- const name = share.name
-
- // Clean up the remote URL for display
- const remote = share.remote
- .replace(/^https?:\/\//, '') // remove http:// or https://
- .replace(/\/$/, '') // remove trailing slash
-
- showRemoteShareDialog(name, owner, remote, passwordProtected)
- .then((password) => callback(true, { ...share, password }))
- .catch(() => callback(false, share))
-}
-
window.addEventListener('DOMContentLoaded', () => {
processIncomingShareFromUrl()
@@ -118,7 +91,7 @@ function processIncomingShareFromUrl() {
// clear hash, it is unlikely that it contain any extra parameters
location.hash = ''
params.passwordProtected = parseInt(params.protected, 10) === 1
- window.OCA.Sharing.showAddExternalDialog(
+ showAddExternalDialog(
params,
params.passwordProtected,
callbackAddShare,
@@ -133,7 +106,7 @@ async function processSharesToConfirm() {
// check for new server-to-server shares which need to be approved
const { data: shares } = await axios.get(generateUrl('/apps/files_sharing/api/externalShares'))
for (let index = 0; index < shares.length; ++index) {
- window.OCA.Sharing.showAddExternalDialog(
+ showAddExternalDialog(
shares[index],
false,
function(result, share) {
@@ -149,3 +122,28 @@ async function processSharesToConfirm() {
)
}
}
+
+/**
+ * Shows "add external share" dialog.
+ *
+ * @param {object} share the share
+ * @param {string} share.remote remote server URL
+ * @param {string} share.owner owner name
+ * @param {string} share.name name of the shared folder
+ * @param {string} share.token authentication token
+ * @param {boolean} passwordProtected true if the share is password protected
+ * @param {Function} callback the callback
+ */
+function showAddExternalDialog(share, passwordProtected, callback) {
+ const owner = share.ownerDisplayName || share.owner
+ const name = share.name
+
+ // Clean up the remote URL for display
+ const remote = share.remote
+ .replace(/^https?:\/\//, '') // remove http:// or https://
+ .replace(/\/$/, '') // remove trailing slash
+
+ showRemoteShareDialog(name, owner, remote, passwordProtected)
+ .then((password) => callback(true, { ...share, password }))
+ .catch(() => callback(false, share))
+}
diff --git a/apps/federatedfilesharing/src/main-personal.js b/apps/federatedfilesharing/src/main-personal.js
deleted file mode 100644
index f4317ac4170..00000000000
--- a/apps/federatedfilesharing/src/main-personal.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-import { getCSPNonce } from '@nextcloud/auth'
-import { translate as t } from '@nextcloud/l10n'
-import Vue from 'vue'
-import PersonalSettings from './components/PersonalSettings.vue'
-
-__webpack_nonce__ = getCSPNonce()
-
-Vue.mixin({
- methods: {
- t,
- },
-})
-
-const PersonalSettingsView = Vue.extend(PersonalSettings)
-new PersonalSettingsView().$mount('#vue-personal-federated')
diff --git a/apps/federatedfilesharing/src/services/dialogService.spec.ts b/apps/federatedfilesharing/src/services/dialogService.spec.ts
index 368dcd929f3..58dd44e37ca 100644
--- a/apps/federatedfilesharing/src/services/dialogService.spec.ts
+++ b/apps/federatedfilesharing/src/services/dialogService.spec.ts
@@ -47,7 +47,7 @@ describe('federatedfilesharing: dialog service', () => {
}
}
- expect(await promise).toBe('')
+ await expect(promise).resolves.toBe('')
})
it('rejects if cancelled', async () => {
@@ -60,6 +60,6 @@ describe('federatedfilesharing: dialog service', () => {
}
}
- expect(async () => await promise).rejects.toThrow()
+ await expect(promise).rejects.toThrow()
})
})
diff --git a/apps/federatedfilesharing/src/services/dialogService.ts b/apps/federatedfilesharing/src/services/dialogService.ts
index d02b2aaf310..807011583b6 100644
--- a/apps/federatedfilesharing/src/services/dialogService.ts
+++ b/apps/federatedfilesharing/src/services/dialogService.ts
@@ -14,23 +14,24 @@ import RemoteShareDialog from '../components/RemoteShareDialog.vue'
* @param remote The remote address
* @param passwordRequired True if the share is password protected
*/
-export function showRemoteShareDialog(
+export async function showRemoteShareDialog(
name: string,
owner: string,
remote: string,
passwordRequired = false,
): Promise {
- const { promise, reject, resolve } = Promise.withResolvers()
-
- spawnDialog(RemoteShareDialog, { name, owner, remote, passwordRequired }, (status, password) => {
- if (passwordRequired && status) {
- resolve(password as string)
- } else if (status) {
- resolve(undefined)
- } else {
- reject()
- }
+ const [status, password] = await spawnDialog(RemoteShareDialog, {
+ name,
+ owner,
+ remote,
+ passwordRequired,
})
- return promise
+ if (passwordRequired && status) {
+ return password as string
+ } else if (status) {
+ return
+ } else {
+ throw new Error('Dialog was cancelled')
+ }
}
diff --git a/apps/federatedfilesharing/src/main-admin.js b/apps/federatedfilesharing/src/settings-admin.ts
similarity index 53%
rename from apps/federatedfilesharing/src/main-admin.js
rename to apps/federatedfilesharing/src/settings-admin.ts
index 14cee69fb1a..9a2a1908dcf 100644
--- a/apps/federatedfilesharing/src/main-admin.js
+++ b/apps/federatedfilesharing/src/settings-admin.ts
@@ -3,23 +3,15 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { getCSPNonce } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
-import { translate as t } from '@nextcloud/l10n'
-import Vue from 'vue'
+import { createApp } from 'vue'
import AdminSettings from './components/AdminSettings.vue'
-__webpack_nonce__ = getCSPNonce()
-
-Vue.mixin({
- methods: {
- t,
- },
-})
+import 'vite/modulepreload-polyfill'
const internalOnly = loadState('federatedfilesharing', 'internalOnly', false)
if (!internalOnly) {
- const AdminSettingsView = Vue.extend(AdminSettings)
- new AdminSettingsView().$mount('#vue-admin-federated')
+ const app = createApp(AdminSettings)
+ app.mount('#vue-admin-federated')
}
diff --git a/apps/federatedfilesharing/src/settings-personal.ts b/apps/federatedfilesharing/src/settings-personal.ts
new file mode 100644
index 00000000000..74be7cab422
--- /dev/null
+++ b/apps/federatedfilesharing/src/settings-personal.ts
@@ -0,0 +1,12 @@
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { createApp } from 'vue'
+import PersonalSettings from './components/PersonalSettings.vue'
+
+import 'vite/modulepreload-polyfill'
+
+const app = createApp(PersonalSettings)
+app.mount('#vue-personal-federated')
diff --git a/apps/federatedfilesharing/templates/settings-admin.php b/apps/federatedfilesharing/templates/settings-admin.php
index 786dcdf2165..641228524e6 100644
--- a/apps/federatedfilesharing/templates/settings-admin.php
+++ b/apps/federatedfilesharing/templates/settings-admin.php
@@ -3,8 +3,6 @@
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
-\OCP\Util::addScript('federatedfilesharing', 'vue-settings-admin');
?>
diff --git a/apps/federatedfilesharing/templates/settings-personal.php b/apps/federatedfilesharing/templates/settings-personal.php
index dffd5712b7e..1e4bdaf9b5c 100644
--- a/apps/federatedfilesharing/templates/settings-personal.php
+++ b/apps/federatedfilesharing/templates/settings-personal.php
@@ -3,8 +3,6 @@
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
-\OCP\Util::addScript('federatedfilesharing', 'vue-settings-personal');
?>
diff --git a/build/frontend-legacy/webpack.modules.cjs b/build/frontend-legacy/webpack.modules.cjs
index fb396aae90a..6309857c1ae 100644
--- a/build/frontend-legacy/webpack.modules.cjs
+++ b/build/frontend-legacy/webpack.modules.cjs
@@ -57,11 +57,6 @@ module.exports = {
oauth2: {
oauth2: path.join(__dirname, 'apps/oauth2/src', 'main.js'),
},
- federatedfilesharing: {
- external: path.join(__dirname, 'apps/federatedfilesharing/src', 'external.js'),
- 'vue-settings-admin': path.join(__dirname, 'apps/federatedfilesharing/src', 'main-admin.js'),
- 'vue-settings-personal': path.join(__dirname, 'apps/federatedfilesharing/src', 'main-personal.js'),
- },
profile: {
main: path.join(__dirname, 'apps/profile/src', 'main.ts'),
},
diff --git a/build/frontend-legacy/apps/federatedfilesharing b/build/frontend/apps/federatedfilesharing
similarity index 100%
rename from build/frontend-legacy/apps/federatedfilesharing
rename to build/frontend/apps/federatedfilesharing
diff --git a/build/frontend/vite.config.mts b/build/frontend/vite.config.mts
index fe3667df0cc..b86568f2b9d 100644
--- a/build/frontend/vite.config.mts
+++ b/build/frontend/vite.config.mts
@@ -12,6 +12,11 @@ const modules = {
'settings-admin-example-content': resolve(import.meta.dirname, 'apps/dav/src', 'settings-admin-example-content.ts'),
'settings-personal-availability': resolve(import.meta.dirname, 'apps/dav/src', 'settings-personal-availability.ts'),
},
+ federatedfilesharing: {
+ 'init-files': resolve(import.meta.dirname, 'apps/federatedfilesharing/src', 'init-files.js'),
+ 'settings-admin': resolve(import.meta.dirname, 'apps/federatedfilesharing/src', 'settings-admin.ts'),
+ 'settings-personal': resolve(import.meta.dirname, 'apps/federatedfilesharing/src', 'settings-personal.ts'),
+ },
files_reminders: {
init: resolve(import.meta.dirname, 'apps/files_reminders/src', 'files-init.ts'),
},
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 712dc3bc3bb..10621144e8d 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -1209,11 +1209,6 @@
)]]>
-
-
-
-
-
diff --git a/tsconfig.json b/tsconfig.json
index 86896bbbe36..4cda8f05a10 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,7 +3,7 @@
"include": ["./apps/**/*.ts", "./apps/**/*.vue", "./core/**/*.ts", "./core/**/*.vue", "./*.d.ts"],
"exclude": ["./**/*.cy.ts"],
"compilerOptions": {
- "lib": ["DOM", "ESNext"],
+ "lib": ["DOM", "DOM.Iterable", "DOM.AsyncIterable", "ESNext"],
"outDir": "./dist/",
"target": "ESNext",
"module": "ESNext",
diff --git a/vitest.config.ts b/vitest.config.ts
index 70fa4ea84ac..1ce29c6770d 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -3,5 +3,11 @@
* SPDX-License-Identifier: CC0-1.0
*/
+import { defineConfig } from 'vitest/config'
+
// stub - for the moment see build/frontend/vitest.config.ts
-export default {}
+export default defineConfig({
+ test: {
+ projects: ['build/frontend*'],
+ },
+})