UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

749 lines (740 loc) 33.6 kB
import * as i0 from '@angular/core'; import { Injectable, Optional } from '@angular/core'; import * as i2 from '@c8y/ngx-components'; import { colorValidator } from '@c8y/ngx-components'; import { applyBrandingOptions, getOptionsToMerge, mergeOptions } from '@c8y/bootstrap'; import chroma from 'chroma-js'; import * as i1 from '@c8y/client'; import { ApplicationAvailability, ApplicationType } from '@c8y/client'; import { BehaviorSubject, defer } from 'rxjs'; import { switchMap, map } from 'rxjs/operators'; import { uniq, cloneDeep } from 'lodash-es'; import * as i4 from '@c8y/ngx-components/static-assets/data'; class ApplyBrandingLocallyService { constructor(options) { this.options = options; } applyBranding(optionsJson) { if (!this.keysToRemove) { this.keysToRemove = Object.keys(this.combineOptions()); } const combinedOptions = this.combineOptions(optionsJson); const newKeysToRemove = Object.keys(combinedOptions); // avoid to remove keys that would actually be set again afterwards const keysToActuallyRemove = this.keysToRemove.filter(key => !newKeysToRemove.includes(key)); this.removeKeysFromOptions(keysToActuallyRemove); this.keysToRemove = newKeysToRemove; applyBrandingOptions(combinedOptions); this.applyApplicationOptions(combinedOptions); } resetBranding() { this.applyBranding(); } applyApplicationOptions(optionsJson) { Object.entries(optionsJson).forEach(([key, value]) => { this.options.set(key, value); }); } removeKeysFromOptions(keys) { for (const key of keys) { this.options.delete(key); } } combineOptions(optionsJson) { const optionsToMerge = getOptionsToMerge(); if (!optionsToMerge) { // should never happen as the options should be set quite early in bootstrapping process. throw Error(`Failed to retrieve options for merging`); } if (optionsJson) { optionsToMerge.dynamicOptions = optionsJson; } return mergeOptions(optionsToMerge); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplyBrandingLocallyService, deps: [{ token: i2.OptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplyBrandingLocallyService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplyBrandingLocallyService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i2.OptionsService }] }); class BrandingShadesService { getShadeColorBrandingCssVars(newBrandPrimary) { const shades = this.generateShades(newBrandPrimary); return this.shadesToObject(shades); } isValidShadeColor(color) { try { return chroma.valid(color); } catch { return false; } } hasCustomShadesSet(previousBrandPrimary, otherVars) { if (previousBrandPrimary && otherVars) { const oldShades = this.generateShades(previousBrandPrimary); const oldShadesObj = this.shadesToObject(oldShades); for (const shadeKey of Object.keys(oldShadesObj)) { const fromVars = otherVars[shadeKey]; const generated = oldShadesObj[shadeKey]; if (fromVars === null || fromVars === undefined) { continue; } if (fromVars !== generated) { return true; } } } return false; } shadesToObject(shades) { const brandingCssVars = {}; let i = 1; for (const shade of shades) { const key = `c8y-brand-${i}0`; brandingCssVars[key] = shade; i++; } return brandingCssVars; } generateShades(inputColor) { const referenceShades = [ '#134158', '#1C5569', '#058192', // primary color '#22A6AA', '#3CC1B7', '#8ADBD5', '#C5EDEA', '#EBF9F8' ]; // Calculate the luminance of the reference shades const referenceLuminances = referenceShades.map(color => chroma(color).luminance()); const inputColorAsHex = chroma(inputColor); // Generate shades of the input color with the same luminance as the reference shades const generatedShades = referenceLuminances.map(luminance => chroma(inputColor).luminance(luminance).hex('rgb')); // Calculate the distance between the input color and each color in the generatedShades array const distances = generatedShades.map(color => chroma.deltaE(inputColorAsHex, color)); // Find the index of the color with the smallest distance const index = distances.indexOf(Math.min(...distances)); generatedShades[index] = inputColorAsHex.hex('rgb'); return generatedShades; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingShadesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingShadesService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingShadesService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * Service for creating and manipulating branding versions. */ class BrandingVersionService { static { this.nameAndIterationSeparator = '-'; } /** * Creates the initial branding version for a given name. * @param name The name of the branding. * @returns The initial branding version. */ createInitialBrandingVersion(name) { return `${name}${BrandingVersionService.nameAndIterationSeparator}${1}`; } /** * Splits a branding version into its name and iteration. * @param version The branding version to split. * @returns The name and iteration of the branding version. * * Errors are thrown if the version is not in the expected format. */ splitBrandingIntoNameAndIteration(version) { const splitted = version.split(BrandingVersionService.nameAndIterationSeparator); if (splitted.length < 2) { throw Error(`A valid version should at least conatin one '${BrandingVersionService.nameAndIterationSeparator}', this is not the case for '${version}'`); } const lastValueOfSplittedArray = splitted[splitted.length - 1]; if (lastValueOfSplittedArray === '' || !/[0-9]+/.test(lastValueOfSplittedArray)) { throw Error(`The second part of the version should be a positive integer, this is not the case for '${lastValueOfSplittedArray}' from '${version}'`); } const iteration = Number.parseInt(lastValueOfSplittedArray); if (Number.isNaN(iteration) && iteration <= 0) { throw Error(`The second part of the version should be a positive integer, this is not the case for '${iteration}' from '${version}'`); } const name = splitted.slice(0, -1).join(BrandingVersionService.nameAndIterationSeparator); if (!name) { throw Error(`The first part of the version should not be empty, this is the case for '${name}' from '${version}'`); } return { iteration, name }; } /** * Bumps the iteration of a branding version. * @param version The branding version to bump. * @returns The bumped branding version. * * Errors are thrown if the version is not in the expected format. */ bumpBrandingIteration(version) { const { name, iteration } = this.splitBrandingIntoNameAndIteration(version); return `${name}${BrandingVersionService.nameAndIterationSeparator}${iteration + 1}`; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingVersionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingVersionService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingVersionService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); const brandingFormGroupTopLevelEntries = [ 'cookieBanner', 'genericApplicationOptions', 'darkThemeAvailable', 'messageBanner' ]; const brandingFormGroupTopLevelEntriesToUnpack = [ 'genericApplicationOptions' ]; const numberBrandingVars = ['brand-logo-img-height', 'btn-border-radius-base']; const colorBrandingVars = [ 'brand-dark', 'brand-light', 'brand-primary', 'c8y-brand-10', 'c8y-brand-20', 'c8y-brand-30', 'c8y-brand-40', 'c8y-brand-50', 'c8y-brand-60', 'c8y-brand-70', 'c8y-brand-80', 'palette-status-info', 'palette-status-warning', 'palette-status-success', 'palette-status-danger', 'palette-status-info-light', 'palette-status-warning-light', 'palette-status-success-light', 'palette-status-danger-light', 'palette-status-info-dark', 'palette-status-warning-dark', 'palette-status-success-dark', 'palette-status-danger-dark', 'body-background-color', 'text-color', 'text-muted', 'link-color', 'link-hover-color', 'action-bar-background-default', 'action-bar-color-actions-hover', 'action-bar-color-actions', 'action-bar-color-default', 'action-bar-icon-color', 'header-color', 'header-text-color', 'header-hover-color', 'navigator-bg-color', 'navigator-active-bg', 'navigator-border-active', 'navigator-header-bg', 'navigator-title-color', 'navigator-separator-color', 'navigator-text-color', 'navigator-color-active', 'right-drawer-background-default', 'right-drawer-text-color-default', 'right-drawer-separator-color', 'right-drawer-link-color', 'right-drawer-link-color-hover', 'right-drawer-text-color-muted' ]; const stringBrandingVars = [ 'brand-logo-img', 'navigator-platform-logo', 'login-platform-animation-img' ]; const stringOrNumberBrandingVars = ['navigator-platform-logo-height']; const allBrandingCSSVars = [ ...numberBrandingVars, ...stringBrandingVars, ...colorBrandingVars ]; function createGenericBrandingForm(formBuilder) { const form = formBuilder.group({ darkThemeAvailable: formBuilder.control(false), cookieBanner: formBuilder.group({ cookieBannerTitle: formBuilder.control(undefined), cookieBannerText: formBuilder.control(undefined), cookieBannerDisabled: formBuilder.control(false), policyUrl: formBuilder.control(undefined), policyVersion: formBuilder.control(undefined) }), messageBanner: formBuilder.group({ messageBannerEnabled: formBuilder.control(false), messageBannerContent: formBuilder.control(''), messageBannerType: formBuilder.control('info') }), baseTypography: formBuilder.group({ 'font-url': formBuilder.control(undefined), 'font-family-base': formBuilder.control(undefined) }), headingsAndNavigatorTypography: formBuilder.group({ 'font-family-headings': formBuilder.control(undefined), 'navigator-font-family': formBuilder.control('var(--font-family-base)') }), genericApplicationOptions: formBuilder.group({ globalTitle: formBuilder.control(undefined), faviconUrl: formBuilder.control(undefined) }) }); return form; } function createBrandingForm(formBuilder) { const colorControls = colorBrandingVars.reduce((acc, key) => { acc[key] = formBuilder.control(undefined, { asyncValidators: [colorValidator()] }); return acc; }, {}); const stringControls = stringBrandingVars.reduce((acc, key) => { acc[key] = formBuilder.control(undefined); return acc; }, {}); const numberControls = numberBrandingVars.reduce((acc, key) => { acc[key] = formBuilder.control(undefined); return acc; }, {}); const stringOrNumberControls = stringOrNumberBrandingVars.reduce((acc, key) => { acc[key] = formBuilder.control(undefined); return acc; }, {}); const form = formBuilder.group({ ...colorControls, ...stringControls, ...numberControls, ...stringOrNumberControls }); return form; } class BrandingTrackingService { constructor(gainsight) { this.gainsight = gainsight; this.prefix = 'brandingManager'; } getStartedUsingBranding() { this.triggerEvent('getStartedUsingBranding'); } deleteAllBrandings() { this.triggerEvent('deleteAllBrandings'); } exportBranding() { this.triggerEvent('exportBranding'); } addNewVersion() { this.triggerEvent('addNewVersion'); } duplicateVersion() { this.triggerEvent('duplicateVersion'); } applyToApps(apps) { this.triggerEvent('applyToApps', { apps }); } importBranding() { this.triggerEvent('importBranding'); } deleteBrandingVariant() { this.triggerEvent('deleteBrandingVariant'); } openPreviewForBranding() { this.triggerEvent('openPreviewForBranding'); } triggerEvent(action, props) { if (!this.gainsight) { return; } const finalProps = { ...props, action }; return this.gainsight.triggerEvent(this.prefix, finalProps); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingTrackingService, deps: [{ token: i2.GainsightService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingTrackingService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BrandingTrackingService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i2.GainsightService, decorators: [{ type: Optional }] }] }); /** * Service to load and store the branding of the tenant. */ class StoreBrandingService { constructor(applicationService, inventory, binary, zip, fetch, brandingVersionService, appState, staticAssets, themeSwitcher, brandingTracking) { this.applicationService = applicationService; this.inventory = inventory; this.binary = binary; this.zip = zip; this.fetch = fetch; this.brandingVersionService = brandingVersionService; this.appState = appState; this.staticAssets = staticAssets; this.themeSwitcher = themeSwitcher; this.brandingTracking = brandingTracking; this.fileNames = { options: 'options.json', manifest: 'cumulocity.json', exportZipName: 'public-options.zip' }; this.manifestValues = { name: 'public-options', contextPath: 'public-options', key: 'public-options-key', description: 'Application containing static assets used by e.g. branding.', noAppSwitcher: true, type: ApplicationType.HOSTED, availability: ApplicationAvailability.SHARED }; this.refreshTriggerBrandingVariants = new BehaviorSubject(null); } /** * Sets the `latest` tag on the provided branding version. Making it the global active branding. */ async markAsActive(brandingVersion, app) { const publicOptions = app || (await this.getPublicOptionsApp()); const tags = brandingVersion.tags || []; const version = brandingVersion.version; await this.applicationService.setPackageVersionTag(publicOptions, version, [...tags, 'latest']); } /** * Opens a new tab with to preview the branding. The branding must have been saved beforehand. * @param brandingName the name of the branding to be previewed */ openPreviewForBranding(brandingName) { this.brandingTracking.openPreviewForBranding(); window.open(`/apps/${this.appState.currentApplication.value?.contextPath || 'cockpit'}/index.html?brandingPreview=true&dynamicOptionsUrl=/apps/public/public-options@${brandingName}/options.json`, '_blank', 'noopener,noreferrer'); } /** * Returns the brandings of the tenant. * If no public options app is found, publicOptions will be undefined and variants an empty array. * For old brandings (created without versioning) a default version is returned. */ async loadBrandingVariants(app) { const publicOptions = app || (await this.getPublicOptionsApp()); if (!publicOptions) { return { publicOptions: undefined, variants: [] }; } const { data: versions } = await this.applicationService.listVersions(publicOptions); let mappedVersions = versions ?.map(tmp => { try { const { name, iteration } = this.brandingVersionService.splitBrandingIntoNameAndIteration(tmp.version); return { revision: iteration, name: name, id: tmp.binaryId, version: tmp.version, tags: tmp.tags || [], publicOptionsApp: publicOptions }; } catch (e) { console.warn('Failed to parse version', tmp, e); return undefined; } }) ?.filter(Boolean) || []; if (!versions && publicOptions.activeVersionId) { mappedVersions = [ { name: 'default', id: publicOptions.activeVersionId, version: 'default-1', revision: 1, tags: ['latest', 'default'], publicOptionsApp: publicOptions } ]; } const variants = await this.getMetadataOfBrandingBinaries(mappedVersions); return { publicOptions, variants }; } /** * As the branding is not immediately available after creation, this method will wait for the branding to be present. * @param version The version of the branding to be retrieved. */ async waitForBrandingToBePresent(version) { const numberOfAttempts = 120; const sleepDurationInSeconds = 1; for (let i = 0; i < numberOfAttempts; i++) { try { // do not sleep before the first attempt if (i !== 0) { await new Promise(resolve => setTimeout(resolve, sleepDurationInSeconds * 1_000)); } await this.getBrandingOptionsForVersion(version); console.info(`Branding "${version}" available now.`); return; } catch (e) { console.warn(`Branding "${version}" not yet present, retrying in ${sleepDurationInSeconds} seconds...`, e); } } throw new Error(`Branding "${version}" not available after ${numberOfAttempts * sleepDurationInSeconds} seconds, giving up.`); } /** * Will create a the initial branding based on the currently applied CSS variables. */ async getStartedUsingBranding() { const allVariables = {}; const themeToRetrieveVars = ['light', 'dark']; const unretrievableVars = new Array(); for (const theme of themeToRetrieveVars) { this.themeSwitcher.temporaryChangeTheme(theme); const styles = getComputedStyle(document.body); const variablesToSkip = [ 'navigator-platform-logo', 'brand-logo-img' ]; const values = allBrandingCSSVars .filter(cssVar => !variablesToSkip.includes(cssVar)) .reduce((prev, key) => { const directValue = styles.getPropertyValue(`--${key}`); const c8yPrefixedValue = styles.getPropertyValue(`--c8y-${key}`); const newKey = theme === 'light' ? key : `dark-${key}`; if (!directValue && !c8yPrefixedValue) { unretrievableVars.push(newKey); return prev; } let value = directValue || c8yPrefixedValue; if (numberBrandingVars.includes(key)) { try { value = Number.parseFloat(value.replace(/[A-Za-z]/g, '').trim()); } catch (e) { console.warn(`Failed to parse number for "${key}" value that failed to parse: "${value}"`, e); return prev; } } return Object.assign(prev, { [newKey]: value }); }, {}); Object.assign(allVariables, values); } this.themeSwitcher.resetTemporaryTheme(); try { await this.createPublicOptionsAppFromInheritedOptions(allVariables); } catch (e) { console.warn(e); } } getZipForBinary(binaryId, fileName = this.fileNames.exportZipName) { return defer(() => this.binary.download(binaryId)).pipe(switchMap(response => response.blob()), map(blob => new File([blob], fileName))); } /** * Deletes the public options app and therefore all brandings. * The public options app can be optionally provided to avoid another request for it. */ async deleteAllBrandings(publicOptions) { publicOptions = publicOptions || (await this.getPublicOptionsApp()); await this.applicationService.delete(publicOptions); } /** * Enhances the provided branding versions with metadata from the linked binaries. * It will add the owner and lastUpdated fields to the versions. * The provided array is altered. */ async getMetadataOfBrandingBinaries(versions) { const binaryIds = uniq(versions.map(tmp => tmp.id)); if (!binaryIds.length) { return versions; } const { data: metadata } = await this.inventory.list({ ids: binaryIds.join(','), pageSize: 2000 }); return versions.map(version => { const metadataForVersion = metadata.find(tmp => tmp.id === version.id) || {}; const { owner, lastUpdated } = metadataForVersion; return Object.assign(version, { owner, lastUpdated }); }); } /** * Saves the provided branding as a new version for the public options app. * The public options app can be optionally provided to avoid another request for it. */ async saveBranding(blob, version, tags = [], publicOptionsApp) { const file = blob instanceof File ? blob : new File([blob], `public-options-${version}.zip`); const publicOptions = publicOptionsApp || (await this.getPublicOptionsApp()); const { data: binary } = await this.applicationService .binary(publicOptions) .uploadApplicationVersion(file, version, tags); if (!publicOptions.activeVersionId || tags.includes('latest')) { await this.applicationService.update({ id: publicOptions.id, activeVersionId: `${binary.binaryId}` }); } this.refreshTriggerBrandingVariants.next(); return { version, binary, tags }; } /** * Removes a branding version from the public options app. * The public options app can be optionally provided to avoid another request for it. */ async deleteBrandingVersion(version, publicOptions) { publicOptions = publicOptions || (await this.getPublicOptionsApp()); await this.applicationService.deleteVersionPackage(publicOptions, { version }); this.refreshTriggerBrandingVariants.next(); } /** * Returns the blob of a zip file containing the provided branding options (options.json) and the manifest (cumulocity.json). */ async getBrandingZip(content = {}) { content.lastUpdated = new Date().toISOString(); const contentAsString = JSON.stringify(content); const zip = await this.zip.createZip([ { fileName: this.fileNames.options, blob: new Blob([contentAsString]) }, { fileName: this.fileNames.manifest, blob: new Blob([JSON.stringify(this.manifestValues)]) } ]); return zip; } /** * Adds a new branding version to the public options app. * The public options app can be optionally provided to avoid another request for it. */ async addBranding(version, content = {}, tags = [], publicOptionsApp) { const zip = await this.getBrandingZip(content); return await this.saveBranding(zip, version, tags, publicOptionsApp); } /** * Returns the branding options for the provided version. * If no branding was found (e.g. status 404), an error is thrown. */ async getBrandingOptionsForVersion(version) { const url = `/apps/public/public-options${version ? `@${version}` : ''}/${this.fileNames.options}?nocache=${new Date().getTime()}`; const response = await this.fetch.fetch(url); if (response.status !== 200) { throw Error(`Unexpected status code: ${response.status}`); } const content = await response.json(); return content; } /** * Saves a new iteration of an already existing branding. */ async saveExistingBranding(branding, currentVersion, tagsOfCurrentVersion = [], newVersion) { const publicOptions = await this.getPublicOptionsApp(); const versionToBeSet = newVersion ? this.brandingVersionService.createInitialBrandingVersion(newVersion) : this.brandingVersionService.bumpBrandingIteration(currentVersion); const finalTags = tagsOfCurrentVersion; // only apply latest tag directly // there seems to be some special handling for the latest tag in the backend, that allows to directly move it while uploading the new version. // for all other tags this results in a 409 conflict. We therefore need to first delete the old version, before setting the other tags on the new version. if (!newVersion) { tagsOfCurrentVersion = tagsOfCurrentVersion.filter(tag => tag === 'latest'); } await this.addBranding(versionToBeSet, branding, tagsOfCurrentVersion, publicOptions); if (!newVersion) { try { await this.deleteBrandingVersion(currentVersion, publicOptions); } catch (e) { if (e.res.status !== 404) { throw e; } } await this.applicationService.setPackageVersionTag(publicOptions, versionToBeSet, finalTags); } return versionToBeSet; } /** * Combines current branding options with the provided branding variables and creates a new public options app. * Any assets in the branding will be cloned. */ async createPublicOptionsAppFromInheritedOptions(brandingVars) { let currentlyAppliedBranding; let fallBackBranding = {}; try { currentlyAppliedBranding = await this.getBrandingOptionsForVersion(); fallBackBranding = cloneDeep(currentlyAppliedBranding); } catch (e) { console.warn('Failed to get currently applied branding, proceeding with empty branding.', e); } if (brandingVars) { currentlyAppliedBranding = currentlyAppliedBranding || {}; const brandingCssVars = currentlyAppliedBranding.brandingCssVars || {}; Object.assign(brandingCssVars, brandingVars); currentlyAppliedBranding.brandingCssVars = brandingCssVars; } if (currentlyAppliedBranding) { try { const { oldAssets, newAssets } = await this.staticAssets.cloneAssetsIntoTenant('branding'); currentlyAppliedBranding = this.replaceBrandingAssetsInBrandingOptions(currentlyAppliedBranding, oldAssets, newAssets); } catch (e) { console.warn('Failed to relocate branding assets into current tenant.', e); } } const publicOptionsApp = await this.createPublicOptionsApp(); const defaultBrandingName = `default`; const result = await this.addBranding(this.brandingVersionService.createInitialBrandingVersion(defaultBrandingName), currentlyAppliedBranding || {}, ['latest', defaultBrandingName], publicOptionsApp); const fallbackBrandingName = `fallback`; await this.addBranding(this.brandingVersionService.createInitialBrandingVersion(fallbackBrandingName), fallBackBranding, [fallbackBrandingName], publicOptionsApp); return result; } /** * Replaces the assets in the branding options with the new assets. * Goes through the provided `oldAssets` and replaces their occurrences in the branding with the corresponding `newAssets` entry sharing the same fileName. * Returns the updated branding options. */ replaceBrandingAssetsInBrandingOptions(branding, oldAssets, newAssets) { let brandingAsJSONString = JSON.stringify(branding); for (const oldAsset of oldAssets) { const newLocatedAsset = newAssets.find(tmp => tmp.fileName === oldAsset.fileName); if (!newLocatedAsset) { continue; } // if the path is the same, we don't need to replace it. if (oldAsset.path === newLocatedAsset.path) { continue; } // TODO: use proper replaceAll once it's available with es2021 brandingAsJSONString = brandingAsJSONString.split(oldAsset.path).join(newLocatedAsset.path); } return JSON.parse(brandingAsJSONString); } async getPublicOptionsApp() { try { const { data: manifest } = await this.applicationService.getManifestOfContextPath(this.manifestValues.contextPath); const { data: app } = await this.applicationService.detail(manifest.id); if (app.owner.tenant.id !== this.appState.currentTenant.value?.name) { return undefined; } return app; } catch (e) { // e.g. reached when no app with the given context path exists return undefined; } } async createPublicOptionsApp() { const { data: app } = await this.applicationService.create(this.manifestValues); return app; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StoreBrandingService, deps: [{ token: i1.ApplicationService }, { token: i1.InventoryService }, { token: i1.InventoryBinaryService }, { token: i2.ZipService }, { token: i1.FetchClient }, { token: BrandingVersionService }, { token: i2.AppStateService }, { token: i4.StaticAssetsService }, { token: i2.ThemeSwitcherService }, { token: BrandingTrackingService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StoreBrandingService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StoreBrandingService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.ApplicationService }, { type: i1.InventoryService }, { type: i1.InventoryBinaryService }, { type: i2.ZipService }, { type: i1.FetchClient }, { type: BrandingVersionService }, { type: i2.AppStateService }, { type: i4.StaticAssetsService }, { type: i2.ThemeSwitcherService }, { type: BrandingTrackingService }] }); /** * Generated bundle index. Do not edit. */ export { ApplyBrandingLocallyService, BrandingShadesService, BrandingTrackingService, BrandingVersionService, StoreBrandingService, allBrandingCSSVars, brandingFormGroupTopLevelEntries, brandingFormGroupTopLevelEntriesToUnpack, colorBrandingVars, createBrandingForm, createGenericBrandingForm, numberBrandingVars, stringBrandingVars, stringOrNumberBrandingVars }; //# sourceMappingURL=c8y-ngx-components-branding-shared-data.mjs.map