Skip to content

Commit 0f373c9

Browse files
Internal: Migrate display.show_tabs from legacy CSV to JSON (#7392)
1 parent ad64013 commit 0f373c9

5 files changed

Lines changed: 658 additions & 116 deletions

File tree

assets/vue/components/layout/TopbarLoggedIn.vue

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
:url="ticketUrl"
1010
class="item-button"
1111
>
12-
<BaseIcon class="item-button__icon" icon="ticket" />
12+
<BaseIcon
13+
class="item-button__icon"
14+
icon="ticket"
15+
/>
1316
</BaseAppLink>
1417

1518
<BaseAppLink
@@ -18,8 +21,15 @@
1821
:to="{ name: 'MessageList' }"
1922
class="item-button"
2023
>
21-
<BaseIcon class="item-button__icon" icon="inbox" />
22-
<span v-if="btnInboxBadge" class="item-button__badge" v-text="btnInboxBadge" />
24+
<BaseIcon
25+
class="item-button__icon"
26+
icon="inbox"
27+
/>
28+
<span
29+
v-if="btnInboxBadge"
30+
class="item-button__badge"
31+
v-text="btnInboxBadge"
32+
/>
2333
</BaseAppLink>
2434
</div>
2535
<div class="app-topbar__end">
@@ -38,7 +48,10 @@
3848
:to="null"
3949
tabindex="0"
4050
>
41-
<BaseIcon class="item-button__icon" icon="login" />
51+
<BaseIcon
52+
class="item-button__icon"
53+
icon="login"
54+
/>
4255
</BaseAppLink>
4356
</div>
4457
</div>
@@ -118,6 +131,42 @@ const ticketUrl = computed(() => {
118131
return "/main/ticket/tickets.php?" + searchParms.toString()
119132
})
120133
134+
/**
135+
* Read display.show_tabs as a JSON string:
136+
* {
137+
* "menu": { ... },
138+
* "topbar": { "topbar_certificate": true, "topbar_skills": true }
139+
* }
140+
*
141+
* We keep parsing defensive to avoid breaking the UI if the setting is invalid.
142+
*/
143+
const displayShowTabs = computed(() => {
144+
const raw = platformConfigStore.getSetting("display.show_tabs") || ""
145+
146+
// if still empty or not a JSON string, behave like "no extra topbar items".
147+
if ("string" !== typeof raw || "" === raw.trim()) {
148+
return { menu: {}, topbar: {} }
149+
}
150+
151+
try {
152+
const parsed = JSON.parse(raw)
153+
154+
// Ensure structure exists even if JSON is incomplete.
155+
const menu = parsed?.menu && "object" === typeof parsed.menu ? parsed.menu : {}
156+
const topbar = parsed?.topbar && "object" === typeof parsed.topbar ? parsed.topbar : {}
157+
158+
return { menu, topbar }
159+
} catch (e) {
160+
// Don't block the app for a bad JSON: log and fallback.
161+
console.warn("[Topbar] Invalid JSON in display.show_tabs", e)
162+
return { menu: {}, topbar: {} }
163+
}
164+
})
165+
166+
function isTopbarEnabled(key) {
167+
return displayShowTabs.value?.topbar?.[key] === true
168+
}
169+
121170
const loginUrl = "/login"
122171
const elUserSubmenu = ref(null)
123172
const userSubmenuItems = computed(() => {
@@ -140,24 +189,21 @@ const userSubmenuItems = computed(() => {
140189
})
141190
}
142191
143-
const tabs = platformConfigStore.getSetting("display.show_tabs") || ""
144-
if (tabs.indexOf("topbar_certificate") > -1) {
192+
if (isTopbarEnabled("topbar_certificate")) {
145193
items[0].items.push({
146194
label: t("My General Certificate"),
147195
url: "/main/social/my_skills_report.php?a=generate_custom_skill",
148196
})
149197
}
150-
if (tabs.indexOf("topbar_skills") > -1) {
198+
199+
if (isTopbarEnabled("topbar_skills")) {
151200
items[0].items.push({
152201
label: t("My skills"),
153202
url: "/main/social/my_skills_report.php",
154203
})
155204
}
156205
157-
items[0].items.push(
158-
{ separator: true },
159-
{ label: t("Sign out"), url: "/logout", icon: "mdi mdi-logout-variant" },
160-
)
206+
items[0].items.push({ separator: true }, { label: t("Sign out"), url: "/logout", icon: "mdi mdi-logout-variant" })
161207
return items
162208
})
163209

0 commit comments

Comments
 (0)