LCOV - code coverage report
Current view: top level - dashql-app/src/config - flavor_resolution.ts Coverage Total Hit
Test: DashQL d805a4b Lines: 100.0 % 53 53
Test Date: 2026-11-09 20:22:13

            Line data    Source code
       1              : import { AppFlavor, DASHQL_FLAVOR, findFlavor } from './flavors.js';
       2              : 
       3              : /// The query parameter selecting a flavor, e.g. `?flavor=dbcom`, former flavor ids are accepted as well
       4            1 : export const FLAVOR_QUERY_PARAMETER = 'flavor';
       5              : 
       6              : /// The result of resolving the flavor
       7              : export interface FlavorResolution {
       8              :     /// The resolved flavor
       9              :     flavor: AppFlavor;
      10              :     /// A requested flavor id that is not known
      11              :     unknownId?: string;
      12              : }
      13              : 
      14              : /// Resolve the flavor from the query parameter, DashQL is the default
      15            1 : export function resolveFlavor(requested: string | null): FlavorResolution {
      16            1 :     if (requested == null) {
      17            1 :         return { flavor: DASHQL_FLAVOR };
      18              :     }
      19            1 :     const flavor = findFlavor(requested);
      20            1 :     if (flavor == null) {
      21            1 :         return { flavor: DASHQL_FLAVOR, unknownId: requested };
      22              :     }
      23            1 :     return { flavor };
      24            1 : }
      25              : 
      26              : /// Get the flavor requested by the query parameter of this page, null if it requests none.
      27              : /// An unknown flavor requests the default one.
      28            1 : export function getRequestedFlavor(): AppFlavor | null {
      29            1 :     const search = new URLSearchParams(globalThis.location?.search ?? '');
      30            1 :     const requested = search.get(FLAVOR_QUERY_PARAMETER);
      31            1 :     if (requested == null) {
      32            1 :         return null;
      33              :     }
      34            1 :     const resolution = resolveFlavor(requested);
      35            1 :     if (resolution.unknownId !== undefined) {
      36            1 :         console.warn(`unknown app flavor: ${resolution.unknownId}`);
      37              :     }
      38            1 :     return resolution.flavor;
      39            1 : }
      40              : 
      41              : /// Select the flavor of the app.
      42              : /// The flavor requested by the url wins over the flavor of the app settings, DashQL is the default.
      43            1 : export function selectFlavor(requested: AppFlavor | null, settingId: string | undefined): AppFlavor {
      44            1 :     return requested ?? (settingId == null ? null : findFlavor(settingId)) ?? DASHQL_FLAVOR;
      45            1 : }
      46              : 
      47              : /// The url with the query parameter of a flavor, null if it already carries it.
      48              : /// The default flavor needs no query parameter.
      49            1 : export function withFlavorParameter(url: URL, flavor: AppFlavor): URL | null {
      50            1 :     const current = url.searchParams.get(FLAVOR_QUERY_PARAMETER);
      51            1 :     if (flavor.id === DASHQL_FLAVOR.id || (current != null && findFlavor(current) === flavor)) {
      52            1 :         return null;
      53              :     }
      54            1 :     const next = new URL(url);
      55            1 :     next.searchParams.set(FLAVOR_QUERY_PARAMETER, flavor.id);
      56            1 :     return next;
      57            1 : }
      58              : 
      59              : /// The static favicons of the entry pages that a branded flavor replaced
      60            1 : const STATIC_FAVICONS = new WeakMap<Document, Element[]>();
      61              : 
      62              : /// Brand the document of an html entry page with a flavor.
      63              : /// The static entry pages carry the DashQL favicons, they are only replaced for flavors with their own
      64              : /// and restored when switching back to a flavor without.
      65            1 : export function applyFlavorToDocument(flavor: AppFlavor, doc: Document = document) {
      66            1 :     doc.documentElement.dataset.flavor = flavor.id;
      67            1 :     doc.title = flavor.displayName;
      68            1 :     doc.querySelector('meta[name="apple-mobile-web-app-title"]')?.setAttribute('content', flavor.displayName);
      69            1 :     doc.head.querySelector('link[data-flavor-favicon]')?.remove();
      70            1 :     if (flavor.favicon != null) {
      71            1 :         const statics = [...doc.head.querySelectorAll('link[rel~="icon"], link[rel="apple-touch-icon"], link[rel="mask-icon"]')];
      72            1 :         if (statics.length > 0) {
      73            1 :             STATIC_FAVICONS.set(doc, statics);
      74              :         }
      75            1 :         for (const link of statics) {
      76            1 :             link.remove();
      77              :         }
      78            1 :         const icon = doc.createElement('link');
      79            1 :         icon.rel = 'icon';
      80            1 :         icon.href = flavor.favicon.href;
      81            1 :         icon.dataset.flavorFavicon = flavor.id;
      82            1 :         doc.head.appendChild(icon);
      83            1 :     } else {
      84            1 :         for (const link of STATIC_FAVICONS.get(doc) ?? []) {
      85            1 :             doc.head.appendChild(link);
      86              :         }
      87            1 :         STATIC_FAVICONS.delete(doc);
      88            1 :     }
      89            1 : }
        

Generated by: LCOV version 2.0-1