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
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" >
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+
121170const loginUrl = " /login"
122171const elUserSubmenu = ref (null )
123172const 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