@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
749 lines (740 loc) • 33.6 kB
JavaScript
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