Skip to content

Commit 7791b48

Browse files
authored
Merge pull request #41341 from nextcloud/fix/apporder-on-closures
fix: Allow to set app order on navigation entries added by closures
2 parents d6af8c8 + 927e7fc commit 7791b48

13 files changed

+84
-45
lines changed

apps/theming/lib/Listener/BeforePreferenceListener.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ public function handle(Event $event): void {
4646
}
4747

4848
switch ($event->getAppId()) {
49-
case Application::APP_ID: $this->handleThemingValues($event); break;
50-
case 'core': $this->handleCoreValues($event); break;
49+
case Application::APP_ID: $this->handleThemingValues($event);
50+
break;
51+
case 'core': $this->handleCoreValues($event);
52+
break;
5153
}
5254
}
5355

@@ -78,8 +80,8 @@ private function handleCoreValues(BeforePreferenceSetEvent|BeforePreferenceDelet
7880

7981
$value = json_decode($event->getConfigValue(), true, flags:JSON_THROW_ON_ERROR);
8082
if (is_array(($value))) {
81-
foreach ($value as $appName => $order) {
82-
if (!$this->appManager->isEnabledForUser($appName) || !is_array($order) || empty($order) || !is_numeric($order[key($order)])) {
83+
foreach ($value as $id => $info) {
84+
if (!is_array($info) || empty($info) || !isset($info['app']) || !$this->appManager->isEnabledForUser($info['app']) || !is_numeric($info['order'] ?? '')) {
8385
// Invalid config value, refuse the change
8486
return;
8587
}

apps/theming/src/components/AppOrderSelector.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ export interface IApp {
3737
icon: string // path to the icon svg
3838
label: string // display name
3939
default?: boolean // force app as default app
40-
app: string
41-
key: number
40+
app?: string
4241
}
4342
4443
export default defineComponent({

apps/theming/src/components/UserAppMenuSection.vue

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,11 @@ interface INavigationEntry {
5858
/** Whether this is the default app */
5959
default?: boolean
6060
/** App that registered this navigation entry (not necessarly the same as the id) */
61-
app: string
62-
/** The key used to identify this entry in the navigations entries */
63-
key: number
61+
app?: string
6462
}
6563
6664
/** The app order user setting */
67-
type IAppOrder = Record<string, Record<number, number>>
65+
type IAppOrder = Record<string, { order: number, app?: string }>
6866
6967
/** OCS responses */
7068
interface IOCSResponse<T> {
@@ -131,8 +129,8 @@ export default defineComponent({
131129
*/
132130
const updateAppOrder = (value: IApp[]) => {
133131
const order: IAppOrder = {}
134-
value.forEach(({ app, key }, index) => {
135-
order[app] = { ...order[app], [key]: index }
132+
value.forEach(({ app, id }, index) => {
133+
order[id] = { order: index, app }
136134
})
137135
138136
saveSetting('apporder', order)

dist/theming-admin-theming.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/theming-admin-theming.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/theming-personal-theming.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/theming-personal-theming.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/private/App/AppManager.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,12 @@ public function getDefaultAppForUser(?IUser $user = null, bool $withFallbacks =
838838
/* Fallback on user defined apporder */
839839
$customOrders = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR);
840840
if (!empty($customOrders)) {
841-
$customOrders = array_map('min', $customOrders);
842-
asort($customOrders);
843-
$defaultApps = array_keys($customOrders);
841+
// filter only entries with app key (when added using closures or NavigationManager::add the app is not guranteed to be set)
842+
$customOrders = array_filter($customOrders, fn ($entry) => isset($entry['app']));
843+
// sort apps by order
844+
usort($customOrders, fn ($a, $b) => $a['order'] - $b['order']);
845+
// set default apps to sorted apps
846+
$defaultApps = array_map(fn ($entry) => $entry['app'], $customOrders);
844847
}
845848
}
846849
}

lib/private/NavigationManager.php

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ class NavigationManager implements INavigationManager {
6565
private $groupManager;
6666
/** @var IConfig */
6767
private $config;
68+
/** The default app for the current user (cached for the `add` function) */
69+
private ?string $defaultApp;
70+
/** User defined app order (cached for the `add` function) */
71+
private array $customAppOrder;
6872

6973
public function __construct(IAppManager $appManager,
7074
IURLGenerator $urlGenerator,
@@ -78,6 +82,8 @@ public function __construct(IAppManager $appManager,
7882
$this->userSession = $userSession;
7983
$this->groupManager = $groupManager;
8084
$this->config = $config;
85+
86+
$this->defaultApp = null;
8187
}
8288

8389
/**
@@ -102,6 +108,12 @@ public function add($entry) {
102108

103109
$id = $entry['id'];
104110
$entry['unread'] = $this->unreadCounters[$id] ?? 0;
111+
if ($entry['type'] === 'link') {
112+
// This is the default app that will always be shown first
113+
$entry['default'] = ($entry['app'] ?? false) === $this->defaultApp;
114+
// Set order from user defined app order
115+
$entry['order'] = $this->customAppOrder[$id]['order'] ?? $entry['order'] ?? 100;
116+
}
105117

106118
$this->entries[$id] = $entry;
107119
}
@@ -218,6 +230,12 @@ private function init() {
218230
]);
219231
}
220232

233+
if ($this->appManager === 'null') {
234+
return;
235+
}
236+
237+
$this->defaultApp = $this->appManager->getDefaultAppForUser($this->userSession->getUser(), false);
238+
221239
if ($this->userSession->isLoggedIn()) {
222240
// Profile
223241
$this->add([
@@ -311,22 +329,15 @@ private function init() {
311329
}
312330
}
313331

314-
if ($this->appManager === 'null') {
315-
return;
316-
}
317-
318332
if ($this->userSession->isLoggedIn()) {
319333
$user = $this->userSession->getUser();
320334
$apps = $this->appManager->getEnabledAppsForUser($user);
321-
$customOrders = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR);
335+
$this->customAppOrder = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR);
322336
} else {
323337
$apps = $this->appManager->getInstalledApps();
324-
$customOrders = [];
338+
$this->customAppOrder = [];
325339
}
326340

327-
// The default app of the current user without fallbacks
328-
$defaultApp = $this->appManager->getDefaultAppForUser($this->userSession->getUser(), false);
329-
330341
foreach ($apps as $app) {
331342
if (!$this->userSession->isLoggedIn() && !$this->appManager->isEnabledForUser($app, $this->userSession->getUser())) {
332343
continue;
@@ -352,7 +363,7 @@ private function init() {
352363
}
353364
$l = $this->l10nFac->get($app);
354365
$id = $nav['id'] ?? $app . ($key === 0 ? '' : $key);
355-
$order = $customOrders[$app][$key] ?? $nav['order'] ?? 100;
366+
$order = $nav['order'] ?? 100;
356367
$type = $nav['type'];
357368
$route = !empty($nav['route']) ? $this->urlGenerator->linkToRoute($nav['route']) : '';
358369
$icon = $nav['icon'] ?? 'app.svg';
@@ -382,12 +393,8 @@ private function init() {
382393
// Localized name of the navigation entry
383394
'name' => $l->t($nav['name']),
384395
], $type === 'link' ? [
385-
// This is the default app that will always be shown first
386-
'default' => $defaultApp === $id,
387396
// App that registered this navigation entry (not necessarly the same as the id)
388397
'app' => $app,
389-
// The key used to identify this entry in the navigations entries
390-
'key' => $key,
391398
] : []
392399
));
393400
}

lib/public/App/IAppManager.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ public function getAppRestriction(string $appId): array;
250250
*
251251
* @param ?IUser $user User to query default app for
252252
* @param bool $withFallbacks Include fallback values if no default app was configured manually
253+
* Before falling back to predefined default apps,
254+
* the user defined app order is considered and the first app would be used as the fallback.
253255
*
254256
* @since 25.0.6
255257
* @since 28.0.0 Added optional $withFallbacks parameter

0 commit comments

Comments
 (0)