Merge pull request #57791 from nextcloud/refactor/settings-navigation-vue
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Integration sqlite / changes (push) Waiting to run
Integration sqlite / integration-sqlite (master, 8.4, main, --tags ~@large files_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, capabilities_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, collaboration_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, comments_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, dav_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, federation_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, file_conversions) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, files_reminders) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, filesdrop_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, ldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, openldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, openldap_numerical_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, remoteapi_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, routing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, setup_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, sharees_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, sharing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, theming_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (master, 8.4, main, videoverification_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite-summary (push) Blocked by required conditions
Psalm static code analysis / static-code-analysis (push) Waiting to run
Psalm static code analysis / static-code-analysis-security (push) Waiting to run
Psalm static code analysis / static-code-analysis-ocp (push) Waiting to run
Psalm static code analysis / static-code-analysis-ncu (push) Waiting to run

refactor(settings): use `NcAppNavigation` for the settings navigation
This commit is contained in:
Ferdinand Thiessen 2026-01-27 03:48:39 +01:00 committed by GitHub
commit 50cc3439af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 277 additions and 153 deletions

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["settings.scss","../../../core/css/variables.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCEA;AAAA;AAAA;AAAA,GCFA;AAAA;AAAA;AAAA,GFWC,0BACC,WAKF,OACC,WAID,4BE0BC,2CFtBD,mBEsBC,kDFlBD,qBEkBC,yCFdD,0BEcC,wCFVD,oEEUC,2CFND,oCACC,oBACA,0BACA,+BACA,mBAGD,4BACC,oBACA,kCAGD,yBACC,WAIA,wCACC,kBACA,yDACC,gBAIA,mOACC,WAKH,uCACC,aAGD,sCACC,WAED,uDACC,WAKD,gBACC,WAIF,mBACC,aACA,aACA,iBACA,uEACA,gBAEA,4BACC,kBACA,SAEA,+BACC,mBAIA,qCACC,iBAKH,kCACC,sBACA,mBACA,gBAGD,mGACC,4BACA,0BACA,WAMF,oBACC,kBACA,wCACC,0BAIF,aACC,oBACA,4CACA,kFACA,8CACA,wCACA,2CACA,8CACA,6CACA,mBACA,yCAEA,sCAEC,oDAGD,+CAEC,6DACA,oDAGD,6BACC,qCACA,WACA,YAIF,6BACC,oBACA,kCAEA,mCACC,WAIA,oCACC,kBACA,oBACA,iBACA,2BACA,WACA,mBACA,QAEA,0CACC,mBACA,uBACA,gBAKD,gIACC,kBACA,qBACA,UACA,oBACA,YAKH,qCACC,kBACA,wBACA,MACA,SAEA,yCACC,qBAIF,4CACC,eAGD,4CACC,sBACA,WACA,YACA,YAMF,qBACC,aACA,sBACA,SACA,YAEA,uBACC,aAGD,uCACC,sBACA,cACA,yBAIF,gBACC,YAIA,2BACC,kCAGD,mBACC,YAIF,sCAEC,aAGD,eACC,WAGD,YACC,qBAIA,aACC,WACA,yBACA,YAGD,WACC,WACA,yBACA,YAMD,oBACC,sBAGD,iBACC,eAOD,oBACC,gBAGD,wBACC,yBAGD,oDACC,WACA,YACA,wCAOD,oBACC,UACA,cACA,gBACA,uBAGD,2BACC,UAKD,oCAEC,cAKD,wEAEC,aAIF,gBACC,kBACA,QACA,mBAEA,sBACC,YAGD,sBACC,iBAKF,WACC,WAEA,cACC,WACA,UACA,uBACA,4CACA,iBACA,mBAGD,cACC,4CACA,UACA,uBACA,iBACA,mBAKD,gBACC,0BACA,cACA,eACA,uBACA,gBAGD,wBACC,0BAEA,gCACC,kBAIF,sCACC,kBAGD,sDAEC,cACA,eACA,eAEA,0EACC,UACA,qBACA,uBACA,gBAIF,8BACC,eAGD,kCACC,wBACA,cAIF,2BACC,mBAMA,oBACC,mBACA,sBACA,WAGD,gCACC,0BAIA,gGACC,cAOH,SACC,gBAEA,0BACC,4CAID,YACC,oBACA,mBACA,uBACA,eACA,iBACA,gBACA,aAEA,uBACC,aACA,mBACA,uBACA,oCACA,qCACA,yDACA,sBACA,oCAKF,WACC,kBACA,kBACA,oCACA,gBAKF,KACC,mBACA,mBAGD,SACC,aAGD,mBACC,mBAGD,eACC,gBAIA,sBACC,aAGD,YACC,oBAGD,kBACC,0BAGD,yBACC,0BAGD,sBACC,0BAGD,oCACC,uBAIF,yCACC,uBAGD,wBACC,qBAGD,2BACC,wBAEA,gBACA,aACA,yBACA,sBAKD,WACC,kBACA,2BACA,WAGD,2DAGC,qBAIA,mCACC,qBACA,YACA,eAGD,+EAEC,YAIF,yBACC,mCACC,YACA,iBACA,cACA,iDAIF,eACC,WAGD,SACC,yBAGD,QACC,qBACA,YACA,WACA,2BAEA,gBACC,kBAIF,qBACC,sBACA,qBACA,YACA,iBAGD,kBACC,qBACA,gBAIA,aACC,sCACA,mCAGD,WACC,oCAGD,mBACC,sCACA,oBAMF,8CACC,yBACA,YAGD,wBACC,WACA,YACA,mBACA,kBACA,+DAGD,SACC,UAGD,eACC,oCACA,wBAGD,UACI,+CAGJ,2BACE,GACE,YAGJ,mCACE,GACE,WAKH,wBACC,qBACA,eACA,mCACA","file":"settings.css"}
{"version":3,"sourceRoot":"","sources":["settings.scss","../../../core/css/variables.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCEA;AAAA;AAAA;AAAA,GCFA;AAAA;AAAA;AAAA,GFWC,0BACC,WAKF,OACC,WAGD,oCACC,oBACA,0BACA,+BACA,mBAGD,4BACC,oBACA,kCAGD,yBACC,WAIA,wCACC,kBACA,yDACC,gBAIA,mOACC,WAKH,uCACC,aAGD,sCACC,WAED,uDACC,WAKD,gBACC,WAIF,mBACC,aACA,aACA,iBACA,uEACA,gBAEA,4BACC,kBACA,SAEA,+BACC,mBAIA,qCACC,iBAKH,kCACC,sBACA,mBACA,gBAGD,mGACC,4BACA,0BACA,WAMF,oBACC,kBACA,wCACC,0BAIF,aACC,oBACA,4CACA,kFACA,8CACA,wCACA,2CACA,8CACA,6CACA,mBACA,yCAEA,sCAEC,oDAGD,+CAEC,6DACA,oDAGD,6BACC,qCACA,WACA,YAIF,6BACC,oBACA,kCAEA,mCACC,WAIA,oCACC,kBACA,oBACA,iBACA,2BACA,WACA,mBACA,QAEA,0CACC,mBACA,uBACA,gBAKD,gIACC,kBACA,qBACA,UACA,oBACA,YAKH,qCACC,kBACA,wBACA,MACA,SAEA,yCACC,qBAIF,4CACC,eAGD,4CACC,sBACA,WACA,YACA,YAMF,qBACC,aACA,sBACA,SACA,YAEA,uBACC,aAGD,uCACC,sBACA,cACA,yBAIF,gBACC,YAIA,2BACC,kCAGD,mBACC,YAIF,sCAEC,aAGD,eACC,WAGD,YACC,qBAIA,aACC,WACA,yBACA,YAGD,WACC,WACA,yBACA,YAMD,oBACC,sBAGD,iBACC,eAOD,oBACC,gBAGD,wBACC,yBAGD,oDACC,WACA,YACA,wCAOD,oBACC,UACA,cACA,gBACA,uBAGD,2BACC,UAIF,gBACC,kBACA,QACA,mBAEA,sBACC,YAGD,sBACC,iBAKF,WACC,WAEA,cACC,WACA,UACA,uBACA,4CACA,iBACA,mBAGD,cACC,4CACA,UACA,uBACA,iBACA,mBAKD,gBACC,0BACA,cACA,eACA,uBACA,gBAGD,wBACC,0BAEA,gCACC,kBAIF,sCACC,kBAGD,sDAEC,cACA,eACA,eAEA,0EACC,UACA,qBACA,uBACA,gBAIF,8BACC,eAGD,kCACC,wBACA,cAIF,2BACC,mBAKD,SACC,gBAEA,0BACC,4CAID,YACC,oBACA,mBACA,uBACA,eACA,iBACA,gBACA,aAEA,uBACC,aACA,mBACA,uBACA,oCACA,qCACA,yDACA,sBACA,oCAKF,WACC,kBACA,kBACA,oCACA,gBAKF,KACC,mBACA,mBAGD,SACC,aAGD,mBACC,mBAGD,eACC,gBAIA,sBACC,aAGD,YACC,oBAGD,kBACC,0BAGD,yBACC,0BAGD,sBACC,0BAGD,oCACC,uBAIF,yCACC,uBAGD,wBACC,qBAGD,2BACC,wBAEA,gBACA,aACA,yBACA,sBAKD,WACC,kBACA,2BACA,WAGD,2DAGC,qBAIA,mCACC,qBACA,YACA,eAGD,+EAEC,YAIF,yBACC,mCACC,YACA,iBACA,cACA,iDAIF,eACC,WAGD,SACC,yBAGD,QACC,qBACA,YACA,WACA,2BAEA,gBACC,kBAIF,qBACC,sBACA,qBACA,YACA,iBAGD,kBACC,qBACA,gBAIA,aACC,sCACA,mCAGD,WACC,oCAGD,mBACC,sCACA,oBAMF,8CACC,yBACA,YAGD,wBACC,WACA,YACA,mBACA,kBACA,+DAGD,SACC,UAGD,eACC,oCACA,wBAGD,UACI,+CAGJ,2BACE,GACE,YAGJ,mCACE,GACE,WAKH,wBACC,qBACA,eACA,mCACA","file":"settings.css"}

View file

@ -19,27 +19,6 @@ input {
clear: both;
}
/* icons for sidebar */
.nav-icon-personal-settings {
@include functions.icon-color('personal', 'settings', variables.$color-black);
}
.nav-icon-security {
@include functions.icon-color('toggle-filelist', 'settings', variables.$color-black);
}
.nav-icon-clientsbox {
@include functions.icon-color('change', 'settings', variables.$color-black);
}
.nav-icon-federated-cloud {
@include functions.icon-color('share', 'settings', variables.$color-black);
}
.nav-icon-second-factor-backup-codes, .nav-icon-ssl-root-certificate {
@include functions.icon-color('password', 'settings', variables.$color-black);
}
#personal-settings-avatar-container {
display: inline-grid;
grid-template-columns: 1fr;
@ -325,20 +304,6 @@ table.nostyle {
}
}
li.active {
.delete,
.rename {
display: block;
}
}
.app-navigation-entry-utils {
.delete,
.rename {
display: none;
}
}
#usersearchform {
position: absolute;
top: 2px;
@ -424,26 +389,6 @@ span.usersLastLoginTooltip {
white-space: nowrap;
}
/* SETTINGS NAVIGATION */
#app-navigation {
/* Navigation icons */
img {
margin-bottom: -3px;
margin-inline-end: 6px;
width: 16px;
}
li span.no-icon {
padding-inline-start: 32px;
}
ul li.active > span.utils {
.delete, .rename {
display: block;
}
}
}
/* SETTINGS SECTIONS */
// to match with NcSettingsSection component
.section {

View file

@ -49,22 +49,10 @@ trait CommonSettingsTrait {
/** @var IInitialState */
private $initialState;
/**
* @return array{forms: array{personal: array, admin: array}}
*/
private function getNavigationParameters(string $currentType, string $currentSection): array {
return [
'forms' => [
'personal' => $this->formatPersonalSections($currentType, $currentSection),
'admin' => $this->formatAdminSections($currentType, $currentSection),
],
];
}
/**
* @param IIconSection[][] $sections
* @psalm-param 'admin'|'personal' $type
* @return list<array{anchor: string, section-name: string, active: bool, icon: string}>
* @return list<array{id: string, name: string, active: bool, icon: string}>
*/
protected function formatSections(array $sections, string $currentSection, string $type, string $currentType): array {
$templateParameters = [];
@ -89,8 +77,8 @@ trait CommonSettingsTrait {
&& $type === $currentType;
$templateParameters[] = [
'anchor' => $section->getID(),
'section-name' => $section->getName(),
'id' => $section->getID(),
'name' => $section->getName(),
'active' => $active,
'icon' => $icon,
];
@ -99,11 +87,17 @@ trait CommonSettingsTrait {
return $templateParameters;
}
/**
* @return list<array{id: string, name: string, active: bool, icon: string}>
*/
protected function formatPersonalSections(string $currentType, string $currentSection): array {
$sections = $this->settingsManager->getPersonalSections();
return $this->formatSections($sections, $currentSection, 'personal', $currentType);
}
/**
* @return list<array{id: string, name: string, active: bool, icon: string}>
*/
protected function formatAdminSections(string $currentType, string $currentSection): array {
$sections = $this->settingsManager->getAdminSections();
return $this->formatSections($sections, $currentSection, 'admin', $currentType);
@ -175,9 +169,13 @@ trait CommonSettingsTrait {
$this->initialState->provideInitialState('declarative-settings-forms', $declarativeSettings);
}
$this->initialState->provideInitialState('sections', [
'personal' => $this->formatPersonalSections($type, $section),
'admin' => $this->formatAdminSections($type, $section),
]);
$settings = array_merge(...$settings);
$templateParams = $this->formatSettings($settings, $declarativeSettings);
$templateParams = array_merge($templateParams, $this->getNavigationParameters($type, $section));
$activeSection = $this->settingsManager->getSection($type, $section);
if ($activeSection) {
@ -186,6 +184,7 @@ trait CommonSettingsTrait {
$templateParams['activeSectionType'] = $type;
}
Util::addScript(Application::APP_ID, 'main', prepend: true);
return new TemplateResponse('settings', 'settings/frame', $templateParams);
}
}

View file

@ -0,0 +1,54 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { generateUrl } from '@nextcloud/router'
import { computed } from 'vue'
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
export interface ISettingsSection {
id: string
name: string
icon?: string
active: boolean
}
const props = defineProps<{
section: ISettingsSection
type: 'admin' | 'personal'
}>()
const href = computed(() => generateUrl('/settings/{type}/{section}', {
type: props.type === 'personal' ? 'user' : 'admin',
section: props.section.id,
}))
</script>
<template>
<NcAppNavigationItem
:name="section.name"
:active="section.active"
:href="href">
<template v-if="section.icon" #icon>
<img
:class="$style.settingsNavigationItem__icon"
:src="section.icon"
alt="">
</template>
</NcAppNavigationItem>
</template>
<style module>
.settingsNavigationItem__icon {
width: var(--default-font-size);
height: var(--default-font-size);
object-fit: contain;
filter: var(--background-invert-if-dark);
}
:global(.active) .settingsNavigationItem__icon {
filter: var(--primary-invert-if-dark);
}
</style>

View file

@ -0,0 +1,13 @@
/*!
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { getCSPNonce } from '@nextcloud/auth'
import Vue from 'vue'
import SettingsNavigation from './views/SettingsNavigation.vue'
__webpack_nonce__ = getCSPNonce()
const app = new Vue(SettingsNavigation)
app.$mount('#app-navigation')

View file

@ -0,0 +1,51 @@
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import type { ISettingsSection } from '../components/SettingsNavigationItem.vue'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'
import NcAppNavigationCaption from '@nextcloud/vue/components/NcAppNavigationCaption'
import NcAppNavigationList from '@nextcloud/vue/components/NcAppNavigationList'
import SettingsNavigationItem from '../components/SettingsNavigationItem.vue'
const {
personal: personalSections,
admin: adminSections,
} = loadState<{ admin: ISettingsSection[], personal: ISettingsSection[] }>('settings', 'sections')
const hasAdminSections = adminSections.length > 0
</script>
<template>
<NcAppNavigation>
<NcAppNavigationCaption
heading-id="settings-personal_section_heading"
is-heading
:name="t('settings', 'Personal')" />
<NcAppNavigationList aria-labelledby="settings-personal_section_heading">
<SettingsNavigationItem
v-for="section in personalSections"
:key="'personal-section--' + section.id"
:section="section"
type="personal" />
</NcAppNavigationList>
<template v-if="hasAdminSections">
<NcAppNavigationCaption
heading-id="settings-admin_section_heading"
is-heading
:name="t('settings', 'Administration')" />
<NcAppNavigationList aria-labelledby="settings-admin_section_heading">
<SettingsNavigationItem
v-for="section in adminSections"
:key="'admin-section--' + section.id"
:section="section"
type="admin" />
</NcAppNavigationList>
</template>
</NcAppNavigation>
</template>

View file

@ -7,61 +7,7 @@
style('settings', 'settings');
?>
<div id="app-navigation">
<?php if (!empty($_['forms']['admin'])): ?>
<div id="app-navigation-caption-personal" class="app-navigation-caption"><?php p($l->t('Personal')); ?></div>
<?php endif; ?>
<nav class="app-navigation-personal" aria-labelledby="app-navigation-caption-personal">
<ul>
<?php foreach ($_['forms']['personal'] as $form) {
if (isset($form['anchor'])) {
$anchor = \OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('settings.PersonalSettings.index', ['section' => $form['anchor']]);
$class = 'nav-icon-' . $form['anchor'];
$sectionName = $form['section-name']; ?>
<li <?php print_unescaped($form['active'] ? ' class="active"' : ''); ?> data-section-id="<?php print_unescaped($form['anchor']); ?>" data-section-type="personal">
<a href="<?php p($anchor); ?>"<?php print_unescaped($form['active'] ? ' aria-current="page"' : ''); ?>>
<?php if (!empty($form['icon'])) { ?>
<img alt="" src="<?php print_unescaped($form['icon']); ?>">
<span><?php p($form['section-name']); ?></span>
<?php } else { ?>
<span class="no-icon"><?php p($form['section-name']); ?></span>
<?php } ?>
</a>
</li>
<?php
}
}
?>
</ul>
</nav>
<?php if (!empty($_['forms']['admin'])): ?>
<div id="app-navigation-caption-administration" class="app-navigation-caption"><?php p($l->t('Administration')); ?></div>
<?php endif; ?>
<nav class="app-navigation-administration" aria-labelledby="app-navigation-caption-administration">
<ul>
<?php foreach ($_['forms']['admin'] as $form) {
if (isset($form['anchor'])) {
$anchor = \OCP\Server::get(\OCP\IURLGenerator::class)->linkToRoute('settings.AdminSettings.index', ['section' => $form['anchor']]);
$class = 'nav-icon-' . $form['anchor'];
$sectionName = $form['section-name']; ?>
<li <?php print_unescaped($form['active'] ? ' class="active"' : ''); ?> data-section-id="<?php print_unescaped($form['anchor']); ?>" data-section-type="admin">
<a href="<?php p($anchor); ?>"<?php print_unescaped($form['active'] ? ' aria-current="page"' : ''); ?>>
<?php if (!empty($form['icon'])) { ?>
<img alt="" src="<?php print_unescaped($form['icon']); ?>">
<span><?php p($form['section-name']); ?></span>
<?php } else { ?>
<span class="no-icon"><?php p($form['section-name']); ?></span>
<?php } ?>
</a>
</li>
<?php
}
}
?>
</ul>
</nav>
</div>
<div id="app-navigation"></div>
<main id="app-content" <?php if (!empty($_['activeSectionId'])) { ?> data-active-section-id="<?php print_unescaped($_['activeSectionId']) ?>" <?php } if (!empty($_['activeSectionType'])) { ?> data-active-section-type="<?php print_unescaped($_['activeSectionType']) ?>" <?php } ?>>
<?php print_unescaped($_['content']); ?>
</main>

View file

@ -122,12 +122,23 @@ class AdminSettingsControllerTest extends TestCase {
->with($user, 'admin', 'test')
->willReturn([]);
$idx = $this->adminSettingsController->index('test');
$initialState = [];
$this->initialState->expects(self::atLeastOnce())
->method('provideInitialState')
->willReturnCallback(function () use (&$initialState) {
$initialState[] = func_get_args();
});
$expected = new TemplateResponse('settings', 'settings/frame', [
'forms' => ['personal' => [], 'admin' => []],
'content' => ''
]);
$this->assertEquals($expected, $idx);
$expected = new TemplateResponse(
'settings',
'settings/frame',
[
'content' => ''
],
);
$this->assertEquals($expected, $this->adminSettingsController->index('test'));
$this->assertEquals([
['sections', ['admin' => [], 'personal' => []]],
], $initialState);
}
}

View file

@ -54,6 +54,7 @@ module.exports = {
'public-nickname-handler': path.join(__dirname, 'apps/files_sharing/src', 'public-nickname-handler.ts'),
},
settings: {
main: path.join(__dirname, 'apps/settings/src', 'main-settings.ts'),
'vue-settings-admin-overview': path.join(__dirname, 'apps/settings/src', 'main-admin-overview.ts'),
'vue-settings-admin-basic-settings': path.join(__dirname, 'apps/settings/src', 'main-admin-basic-settings.js'),
'vue-settings-admin-ai': path.join(__dirname, 'apps/settings/src', 'main-admin-ai.js'),

View file

@ -28,15 +28,18 @@ describe('Settings: Ensure only administrator can see the administration setting
.click()
cy.url().should('match', /\/settings\/user$/)
cy.get('#app-navigation').should('be.visible').within(() => {
// I see the personal section is NOT shown
cy.get('#app-navigation-caption-personal').should('not.exist')
// I see the admin section is NOT shown
cy.get('#app-navigation-caption-administration').should('not.exist')
cy.findAllByRole('navigation')
.filter('#app-navigation-vue')
.as('appNavigation')
.findByRole('list', { name: 'Personal' })
.should('be.visible')
.findByRole('link', { name: /Personal info/i })
.should('be.visible')
.and('have.attr', 'aria-current', 'page')
// I see that the "Personal info" entry in the settings panel is shown
cy.get('[data-section-id="personal-info"]').should('exist').and('be.visible')
})
cy.get('@appNavigation')
.findByRole('list', { name: 'Administration' })
.should('not.exist')
})
it('Admin users can see admin-level items on the Settings page', () => {
@ -52,14 +55,19 @@ describe('Settings: Ensure only administrator can see the administration setting
.click()
cy.url().should('match', /\/settings\/user$/)
cy.get('#app-navigation').should('be.visible').within(() => {
// I see the personal section is shown
cy.get('#app-navigation-caption-personal').should('be.visible')
// I see the admin section is shown
cy.get('#app-navigation-caption-administration').should('be.visible')
cy.findAllByRole('navigation')
.filter('#app-navigation-vue')
.as('appNavigation')
.findByRole('list', { name: 'Personal' })
.should('be.visible')
.findByRole('link', { name: /Personal info/i })
.should('be.visible')
.and('have.attr', 'aria-current', 'page')
// I see that the "Personal info" entry in the settings panel is shown
cy.get('[data-section-id="personal-info"]').should('exist').and('be.visible')
})
cy.get('@appNavigation')
.findByRole('list', { name: 'Administration' })
.should('be.visible')
.findByRole('link', { name: /Overview/i })
.should('be.visible')
})
})

4
dist/core-common.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/settings-main.js vendored Normal file

File diff suppressed because one or more lines are too long

92
dist/settings-main.js.license vendored Normal file
View file

@ -0,0 +1,92 @@
SPDX-License-Identifier: MIT
SPDX-License-Identifier: ISC
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
SPDX-FileCopyrightText: escape-html developers
SPDX-FileCopyrightText: Tobias Koppers @sokra
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
SPDX-FileCopyrightText: Guillaume Chau <guillaume.b.chau@gmail.com>
SPDX-FileCopyrightText: GitHub Inc.
SPDX-FileCopyrightText: Evan You
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
SPDX-FileCopyrightText: David Clark
SPDX-FileCopyrightText: Christoph Wurst
SPDX-FileCopyrightText: Anthony Fu <https://github.com/antfu>
SPDX-FileCopyrightText: Anthony Fu <anthonyfu117@hotmail.com>
This file is generated from multiple sources. Included packages:
- @nextcloud/auth
- version: 2.5.3
- license: GPL-3.0-or-later
- @nextcloud/browser-storage
- version: 0.5.0
- license: GPL-3.0-or-later
- semver
- version: 7.7.2
- license: ISC
- @nextcloud/event-bus
- version: 3.3.3
- license: GPL-3.0-or-later
- @nextcloud/initial-state
- version: 3.0.0
- license: GPL-3.0-or-later
- @nextcloud/l10n
- version: 3.4.1
- license: GPL-3.0-or-later
- @nextcloud/logger
- version: 3.0.3
- license: GPL-3.0-or-later
- @nextcloud/router
- version: 3.1.0
- license: GPL-3.0-or-later
- @nextcloud/vue
- version: 8.35.3
- license: AGPL-3.0-or-later
- @vueuse/core
- version: 11.3.0
- license: MIT
- @vueuse/shared
- version: 11.3.0
- license: MIT
- css-loader
- version: 7.1.2
- license: MIT
- dompurify
- version: 3.3.1
- license: (MPL-2.0 OR Apache-2.0)
- escape-html
- version: 1.0.3
- license: MIT
- floating-vue
- version: 1.0.0-beta.19
- license: MIT
- focus-trap
- version: 7.8.0
- license: MIT
- process
- version: 0.11.10
- license: MIT
- style-loader
- version: 4.0.0
- license: MIT
- tabbable
- version: 6.4.0
- license: MIT
- vue-demi
- version: 0.14.10
- license: MIT
- vue-loader
- version: 15.11.1
- license: MIT
- vue
- version: 2.7.16
- license: MIT
- webpack
- version: 5.104.1
- license: MIT
- nextcloud
- version: 1.0.0
- license: AGPL-3.0-or-later

1
dist/settings-main.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/settings-main.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
settings-main.js.license