brands: migrate custom CSS to brands (#13172)
* brands: migrate custom CSS to brands Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix missing default Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * simpler migration Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add css to brand form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
		| @ -49,6 +49,7 @@ class BrandSerializer(ModelSerializer): | |||||||
|             "branding_title", |             "branding_title", | ||||||
|             "branding_logo", |             "branding_logo", | ||||||
|             "branding_favicon", |             "branding_favicon", | ||||||
|  |             "branding_custom_css", | ||||||
|             "flow_authentication", |             "flow_authentication", | ||||||
|             "flow_invalidation", |             "flow_invalidation", | ||||||
|             "flow_recovery", |             "flow_recovery", | ||||||
| @ -86,6 +87,7 @@ class CurrentBrandSerializer(PassiveSerializer): | |||||||
|     branding_title = CharField() |     branding_title = CharField() | ||||||
|     branding_logo = CharField(source="branding_logo_url") |     branding_logo = CharField(source="branding_logo_url") | ||||||
|     branding_favicon = CharField(source="branding_favicon_url") |     branding_favicon = CharField(source="branding_favicon_url") | ||||||
|  |     branding_custom_css = CharField() | ||||||
|     ui_footer_links = ListField( |     ui_footer_links = ListField( | ||||||
|         child=FooterLinkSerializer(), |         child=FooterLinkSerializer(), | ||||||
|         read_only=True, |         read_only=True, | ||||||
|  | |||||||
| @ -0,0 +1,35 @@ | |||||||
|  | # Generated by Django 5.0.12 on 2025-02-22 01:51 | ||||||
|  |  | ||||||
|  | from pathlib import Path | ||||||
|  | from django.db import migrations, models | ||||||
|  | from django.apps.registry import Apps | ||||||
|  |  | ||||||
|  | from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def migrate_custom_css(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): | ||||||
|  |     Brand = apps.get_model("authentik_brands", "brand") | ||||||
|  |  | ||||||
|  |     db_alias = schema_editor.connection.alias | ||||||
|  |  | ||||||
|  |     path = Path("/web/dist/custom.css") | ||||||
|  |     if not path.exists(): | ||||||
|  |         return | ||||||
|  |     with path.read_text() as css: | ||||||
|  |         Brand.objects.using(db_alias).update(branding_custom_css=css) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  |  | ||||||
|  |     dependencies = [ | ||||||
|  |         ("authentik_brands", "0007_brand_default_application"), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name="brand", | ||||||
|  |             name="branding_custom_css", | ||||||
|  |             field=models.TextField(blank=True, default=""), | ||||||
|  |         ), | ||||||
|  |         migrations.RunPython(migrate_custom_css), | ||||||
|  |     ] | ||||||
| @ -33,6 +33,7 @@ class Brand(SerializerModel): | |||||||
|  |  | ||||||
|     branding_logo = models.TextField(default="/static/dist/assets/icons/icon_left_brand.svg") |     branding_logo = models.TextField(default="/static/dist/assets/icons/icon_left_brand.svg") | ||||||
|     branding_favicon = models.TextField(default="/static/dist/assets/icons/icon.png") |     branding_favicon = models.TextField(default="/static/dist/assets/icons/icon.png") | ||||||
|  |     branding_custom_css = models.TextField(default="", blank=True) | ||||||
|  |  | ||||||
|     flow_authentication = models.ForeignKey( |     flow_authentication = models.ForeignKey( | ||||||
|         Flow, null=True, on_delete=models.SET_NULL, related_name="brand_authentication" |         Flow, null=True, on_delete=models.SET_NULL, related_name="brand_authentication" | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ class TestBrands(APITestCase): | |||||||
|                 "branding_logo": "/static/dist/assets/icons/icon_left_brand.svg", |                 "branding_logo": "/static/dist/assets/icons/icon_left_brand.svg", | ||||||
|                 "branding_favicon": "/static/dist/assets/icons/icon.png", |                 "branding_favicon": "/static/dist/assets/icons/icon.png", | ||||||
|                 "branding_title": "authentik", |                 "branding_title": "authentik", | ||||||
|  |                 "branding_custom_css": "", | ||||||
|                 "matched_domain": brand.domain, |                 "matched_domain": brand.domain, | ||||||
|                 "ui_footer_links": [], |                 "ui_footer_links": [], | ||||||
|                 "ui_theme": Themes.AUTOMATIC, |                 "ui_theme": Themes.AUTOMATIC, | ||||||
| @ -43,6 +44,7 @@ class TestBrands(APITestCase): | |||||||
|                 "branding_logo": "/static/dist/assets/icons/icon_left_brand.svg", |                 "branding_logo": "/static/dist/assets/icons/icon_left_brand.svg", | ||||||
|                 "branding_favicon": "/static/dist/assets/icons/icon.png", |                 "branding_favicon": "/static/dist/assets/icons/icon.png", | ||||||
|                 "branding_title": "custom", |                 "branding_title": "custom", | ||||||
|  |                 "branding_custom_css": "", | ||||||
|                 "matched_domain": "bar.baz", |                 "matched_domain": "bar.baz", | ||||||
|                 "ui_footer_links": [], |                 "ui_footer_links": [], | ||||||
|                 "ui_theme": Themes.AUTOMATIC, |                 "ui_theme": Themes.AUTOMATIC, | ||||||
| @ -59,6 +61,7 @@ class TestBrands(APITestCase): | |||||||
|                 "branding_logo": "/static/dist/assets/icons/icon_left_brand.svg", |                 "branding_logo": "/static/dist/assets/icons/icon_left_brand.svg", | ||||||
|                 "branding_favicon": "/static/dist/assets/icons/icon.png", |                 "branding_favicon": "/static/dist/assets/icons/icon.png", | ||||||
|                 "branding_title": "authentik", |                 "branding_title": "authentik", | ||||||
|  |                 "branding_custom_css": "", | ||||||
|                 "matched_domain": "fallback", |                 "matched_domain": "fallback", | ||||||
|                 "ui_footer_links": [], |                 "ui_footer_links": [], | ||||||
|                 "ui_theme": Themes.AUTOMATIC, |                 "ui_theme": Themes.AUTOMATIC, | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|         {% block head_before %} |         {% block head_before %} | ||||||
|         {% endblock %} |         {% endblock %} | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject> |         <style>{{ brand.branding_custom_css }}</style> | ||||||
|         <script src="{% versioned_script 'dist/poly-%v.js' %}" type="module"></script> |         <script src="{% versioned_script 'dist/poly-%v.js' %}" type="module"></script> | ||||||
|         <script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script> |         <script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script> | ||||||
|         {% block head %} |         {% block head %} | ||||||
|  | |||||||
| @ -13016,6 +13016,10 @@ | |||||||
|                     "minLength": 1, |                     "minLength": 1, | ||||||
|                     "title": "Branding favicon" |                     "title": "Branding favicon" | ||||||
|                 }, |                 }, | ||||||
|  |                 "branding_custom_css": { | ||||||
|  |                     "type": "string", | ||||||
|  |                     "title": "Branding custom css" | ||||||
|  |                 }, | ||||||
|                 "flow_authentication": { |                 "flow_authentication": { | ||||||
|                     "type": "string", |                     "type": "string", | ||||||
|                     "format": "uuid", |                     "format": "uuid", | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ | |||||||
|         <link rel="shortcut icon" type="image/png" href="/outpost.goauthentik.io/static/dist/assets/icons/icon.png"> |         <link rel="shortcut icon" type="image/png" href="/outpost.goauthentik.io/static/dist/assets/icons/icon.png"> | ||||||
|         <link rel="stylesheet" type="text/css" href="/outpost.goauthentik.io/static/dist/patternfly.min.css"> |         <link rel="stylesheet" type="text/css" href="/outpost.goauthentik.io/static/dist/patternfly.min.css"> | ||||||
|         <link rel="stylesheet" type="text/css" href="/outpost.goauthentik.io/static/dist/authentik.css"> |         <link rel="stylesheet" type="text/css" href="/outpost.goauthentik.io/static/dist/authentik.css"> | ||||||
|         <link rel="stylesheet" type="text/css" href="/outpost.goauthentik.io/static/dist/custom.css"> |  | ||||||
|         <link rel="prefetch" href="/outpost.goauthentik.io/static/dist/assets/images/flow_background.jpg" /> |         <link rel="prefetch" href="/outpost.goauthentik.io/static/dist/assets/images/flow_background.jpg" /> | ||||||
|         <style> |         <style> | ||||||
|             .pf-c-background-image::before { |             .pf-c-background-image::before { | ||||||
|  | |||||||
| @ -41145,6 +41145,8 @@ components: | |||||||
|           type: string |           type: string | ||||||
|         branding_favicon: |         branding_favicon: | ||||||
|           type: string |           type: string | ||||||
|  |         branding_custom_css: | ||||||
|  |           type: string | ||||||
|         flow_authentication: |         flow_authentication: | ||||||
|           type: string |           type: string | ||||||
|           format: uuid |           format: uuid | ||||||
| @ -41204,6 +41206,8 @@ components: | |||||||
|         branding_favicon: |         branding_favicon: | ||||||
|           type: string |           type: string | ||||||
|           minLength: 1 |           minLength: 1 | ||||||
|  |         branding_custom_css: | ||||||
|  |           type: string | ||||||
|         flow_authentication: |         flow_authentication: | ||||||
|           type: string |           type: string | ||||||
|           format: uuid |           format: uuid | ||||||
| @ -42096,6 +42100,8 @@ components: | |||||||
|           type: string |           type: string | ||||||
|         branding_favicon: |         branding_favicon: | ||||||
|           type: string |           type: string | ||||||
|  |         branding_custom_css: | ||||||
|  |           type: string | ||||||
|         ui_footer_links: |         ui_footer_links: | ||||||
|           type: array |           type: array | ||||||
|           items: |           items: | ||||||
| @ -42122,6 +42128,7 @@ components: | |||||||
|           type: string |           type: string | ||||||
|           readOnly: true |           readOnly: true | ||||||
|       required: |       required: | ||||||
|  |       - branding_custom_css | ||||||
|       - branding_favicon |       - branding_favicon | ||||||
|       - branding_logo |       - branding_logo | ||||||
|       - branding_title |       - branding_title | ||||||
| @ -50125,6 +50132,8 @@ components: | |||||||
|         branding_favicon: |         branding_favicon: | ||||||
|           type: string |           type: string | ||||||
|           minLength: 1 |           minLength: 1 | ||||||
|  |         branding_custom_css: | ||||||
|  |           type: string | ||||||
|         flow_authentication: |         flow_authentication: | ||||||
|           type: string |           type: string | ||||||
|           format: uuid |           format: uuid | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -14,6 +14,7 @@ | |||||||
|                 "./packages/*" |                 "./packages/*" | ||||||
|             ], |             ], | ||||||
|             "dependencies": { |             "dependencies": { | ||||||
|  |                 "@codemirror/lang-css": "^6.3.1", | ||||||
|                 "@codemirror/lang-html": "^6.4.9", |                 "@codemirror/lang-html": "^6.4.9", | ||||||
|                 "@codemirror/lang-javascript": "^6.2.2", |                 "@codemirror/lang-javascript": "^6.2.2", | ||||||
|                 "@codemirror/lang-python": "^6.1.6", |                 "@codemirror/lang-python": "^6.1.6", | ||||||
| @ -1039,9 +1040,10 @@ | |||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "node_modules/@codemirror/lang-css": { |         "node_modules/@codemirror/lang-css": { | ||||||
|             "version": "6.3.0", |             "version": "6.3.1", | ||||||
|             "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.0.tgz", |             "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", | ||||||
|             "integrity": "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA==", |             "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", | ||||||
|  |             "license": "MIT", | ||||||
|             "dependencies": { |             "dependencies": { | ||||||
|                 "@codemirror/autocomplete": "^6.0.0", |                 "@codemirror/autocomplete": "^6.0.0", | ||||||
|                 "@codemirror/language": "^6.0.0", |                 "@codemirror/language": "^6.0.0", | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
|     "name": "@goauthentik/web", |     "name": "@goauthentik/web", | ||||||
|     "version": "0.0.0", |     "version": "0.0.0", | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|  |         "@codemirror/lang-css": "^6.3.1", | ||||||
|         "@codemirror/lang-html": "^6.4.9", |         "@codemirror/lang-html": "^6.4.9", | ||||||
|         "@codemirror/lang-javascript": "^6.2.2", |         "@codemirror/lang-javascript": "^6.2.2", | ||||||
|         "@codemirror/lang-python": "^6.1.6", |         "@codemirror/lang-python": "^6.1.6", | ||||||
| @ -182,7 +183,6 @@ | |||||||
|                 "./dist/enterprise/**", |                 "./dist/enterprise/**", | ||||||
|                 "./dist/poly-*.js", |                 "./dist/poly-*.js", | ||||||
|                 "./dist/poly-*.js.map", |                 "./dist/poly-*.js.map", | ||||||
|                 "./dist/custom.css", |  | ||||||
|                 "./dist/theme-dark.css", |                 "./dist/theme-dark.css", | ||||||
|                 "./dist/one-dark.css", |                 "./dist/one-dark.css", | ||||||
|                 "./dist/patternfly.min.css" |                 "./dist/patternfly.min.css" | ||||||
|  | |||||||
| @ -52,7 +52,6 @@ const definitions = Object.fromEntries( | |||||||
| const assetsFileMappings = [ | const assetsFileMappings = [ | ||||||
|     ["node_modules/@patternfly/patternfly/patternfly.min.css", "."], |     ["node_modules/@patternfly/patternfly/patternfly.min.css", "."], | ||||||
|     ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"], |     ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"], | ||||||
|     ["src/custom.css", "."], |  | ||||||
|     ["src/common/styles/**", "."], |     ["src/common/styles/**", "."], | ||||||
|     ["src/assets/images/**", "./assets/images"], |     ["src/assets/images/**", "./assets/images"], | ||||||
|     ["./icons/*", "./assets/icons"], |     ["./icons/*", "./assets/icons"], | ||||||
|  | |||||||
| @ -51,11 +51,7 @@ export class BrandForm extends ModelForm<Brand, string> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderForm(): TemplateResult { |     renderForm(): TemplateResult { | ||||||
|         return html` <ak-form-element-horizontal |         return html` <ak-form-element-horizontal label=${msg("Domain")} required name="domain"> | ||||||
|                 label=${msg("Domain")} |  | ||||||
|                 ?required=${true} |  | ||||||
|                 name="domain" |  | ||||||
|             > |  | ||||||
|                 <input |                 <input | ||||||
|                     type="text" |                     type="text" | ||||||
|                     value="${first(this.instance?.domain, window.location.host)}" |                     value="${first(this.instance?.domain, window.location.host)}" | ||||||
| @ -90,14 +86,10 @@ export class BrandForm extends ModelForm<Brand, string> { | |||||||
|                 </p> |                 </p> | ||||||
|             </ak-form-element-horizontal> |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|             <ak-form-group .expanded=${true}> |             <ak-form-group> | ||||||
|                 <span slot="header"> ${msg("Branding settings")} </span> |                 <span slot="header"> ${msg("Branding settings")} </span> | ||||||
|                 <div slot="body" class="pf-c-form"> |                 <div slot="body" class="pf-c-form"> | ||||||
|                     <ak-form-element-horizontal |                     <ak-form-element-horizontal label=${msg("Title")} required name="brandingTitle"> | ||||||
|                         label=${msg("Title")} |  | ||||||
|                         ?required=${true} |  | ||||||
|                         name="brandingTitle" |  | ||||||
|                     > |  | ||||||
|                         <input |                         <input | ||||||
|                             type="text" |                             type="text" | ||||||
|                             value="${first( |                             value="${first( | ||||||
| @ -111,11 +103,7 @@ export class BrandForm extends ModelForm<Brand, string> { | |||||||
|                             ${msg("Branding shown in page title and several other places.")} |                             ${msg("Branding shown in page title and several other places.")} | ||||||
|                         </p> |                         </p> | ||||||
|                     </ak-form-element-horizontal> |                     </ak-form-element-horizontal> | ||||||
|                     <ak-form-element-horizontal |                     <ak-form-element-horizontal label=${msg("Logo")} required name="brandingLogo"> | ||||||
|                         label=${msg("Logo")} |  | ||||||
|                         ?required=${true} |  | ||||||
|                         name="brandingLogo" |  | ||||||
|                     > |  | ||||||
|                         <input |                         <input | ||||||
|                             type="text" |                             type="text" | ||||||
|                             value="${first(this.instance?.brandingLogo, DefaultBrand.brandingLogo)}" |                             value="${first(this.instance?.brandingLogo, DefaultBrand.brandingLogo)}" | ||||||
| @ -130,7 +118,7 @@ export class BrandForm extends ModelForm<Brand, string> { | |||||||
|                     </ak-form-element-horizontal> |                     </ak-form-element-horizontal> | ||||||
|                     <ak-form-element-horizontal |                     <ak-form-element-horizontal | ||||||
|                         label=${msg("Favicon")} |                         label=${msg("Favicon")} | ||||||
|                         ?required=${true} |                         required | ||||||
|                         name="brandingFavicon" |                         name="brandingFavicon" | ||||||
|                     > |                     > | ||||||
|                         <input |                         <input | ||||||
| @ -148,6 +136,23 @@ export class BrandForm extends ModelForm<Brand, string> { | |||||||
|                             ${msg("Icon shown in the browser tab.")} |                             ${msg("Icon shown in the browser tab.")} | ||||||
|                         </p> |                         </p> | ||||||
|                     </ak-form-element-horizontal> |                     </ak-form-element-horizontal> | ||||||
|  |                     <ak-form-element-horizontal | ||||||
|  |                         label=${msg("Custom CSS")} | ||||||
|  |                         required | ||||||
|  |                         name="brandingCustomCss" | ||||||
|  |                     > | ||||||
|  |                         <ak-codemirror | ||||||
|  |                             mode=${CodeMirrorMode.CSS} | ||||||
|  |                             value="${first( | ||||||
|  |                                 this.instance?.brandingCustomCss, | ||||||
|  |                                 DefaultBrand.brandingCustomCss, | ||||||
|  |                             )}" | ||||||
|  |                         > | ||||||
|  |                         </ak-codemirror> | ||||||
|  |                         <p class="pf-c-form__helper-text"> | ||||||
|  |                             ${msg("Custom CSS to apply to pages when this brand is active.")} | ||||||
|  |                         </p> | ||||||
|  |                     </ak-form-element-horizontal> | ||||||
|                 </div> |                 </div> | ||||||
|             </ak-form-group> |             </ak-form-group> | ||||||
|  |  | ||||||
|  | |||||||
| @ -1 +0,0 @@ | |||||||
| /* User customisable */ |  | ||||||
| @ -24,26 +24,6 @@ type AkInterface = HTMLElement & { | |||||||
| export const rootInterface = <T extends AkInterface>(): T | undefined => | export const rootInterface = <T extends AkInterface>(): T | undefined => | ||||||
|     (document.body.querySelector("[data-ak-interface-root]") as T) ?? undefined; |     (document.body.querySelector("[data-ak-interface-root]") as T) ?? undefined; | ||||||
|  |  | ||||||
| let css: Promise<string[]> | undefined; |  | ||||||
| function fetchCustomCSS(): Promise<string[]> { |  | ||||||
|     if (!css) { |  | ||||||
|         css = Promise.all( |  | ||||||
|             Array.of(...document.head.querySelectorAll<HTMLLinkElement>("link[data-inject]")).map( |  | ||||||
|                 (link) => { |  | ||||||
|                     return fetch(link.href) |  | ||||||
|                         .then((res) => { |  | ||||||
|                             return res.text(); |  | ||||||
|                         }) |  | ||||||
|                         .finally(() => { |  | ||||||
|                             return ""; |  | ||||||
|                         }); |  | ||||||
|                 }, |  | ||||||
|             ), |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|     return css; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const QUERY_MEDIA_COLOR_LIGHT = "(prefers-color-scheme: light)"; | export const QUERY_MEDIA_COLOR_LIGHT = "(prefers-color-scheme: light)"; | ||||||
|  |  | ||||||
| // Ensure themes are converted to a static instance of CSS Stylesheet, otherwise the | // Ensure themes are converted to a static instance of CSS Stylesheet, otherwise the | ||||||
| @ -103,15 +83,12 @@ export class AKElement extends LitElement { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async _initCustomCSS(root: DocumentOrShadowRoot): Promise<void> { |     async _initCustomCSS(root: DocumentOrShadowRoot): Promise<void> { | ||||||
|         const sheets = await fetchCustomCSS(); |         const brand = globalAK().brand; | ||||||
|         sheets.map((css) => { |         if (!brand) { | ||||||
|             if (css === "") { |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|             new CSSStyleSheet().replace(css).then((sheet) => { |         const sheet = await new CSSStyleSheet().replace(brand.brandingCustomCss); | ||||||
|         root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet]; |         root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet]; | ||||||
|             }); |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _applyTheme(root: DocumentOrShadowRoot, theme?: UiThemeEnum): void { |     _applyTheme(root: DocumentOrShadowRoot, theme?: UiThemeEnum): void { | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import { defaultKeymap, history, historyKeymap } from "@codemirror/commands"; | import { defaultKeymap, history, historyKeymap } from "@codemirror/commands"; | ||||||
|  | import { css as cssLang } from "@codemirror/lang-css"; | ||||||
| import { html as htmlLang } from "@codemirror/lang-html"; | import { html as htmlLang } from "@codemirror/lang-html"; | ||||||
| import { javascript } from "@codemirror/lang-javascript"; | import { javascript } from "@codemirror/lang-javascript"; | ||||||
| import { python } from "@codemirror/lang-python"; | import { python } from "@codemirror/lang-python"; | ||||||
| @ -27,6 +28,7 @@ export enum CodeMirrorMode { | |||||||
|     XML = "xml", |     XML = "xml", | ||||||
|     JavaScript = "javascript", |     JavaScript = "javascript", | ||||||
|     HTML = "html", |     HTML = "html", | ||||||
|  |     CSS = "css", | ||||||
|     Python = "python", |     Python = "python", | ||||||
|     YAML = "yaml", |     YAML = "yaml", | ||||||
| } | } | ||||||
| @ -147,6 +149,8 @@ export class CodeMirrorTextarea<T> extends AKElement { | |||||||
|                 return htmlLang(); |                 return htmlLang(); | ||||||
|             case CodeMirrorMode.Python: |             case CodeMirrorMode.Python: | ||||||
|                 return python(); |                 return python(); | ||||||
|  |             case CodeMirrorMode.CSS: | ||||||
|  |                 return cssLang(); | ||||||
|             case CodeMirrorMode.YAML: |             case CodeMirrorMode.YAML: | ||||||
|                 return new LanguageSupport(StreamLanguage.define(yamlMode.yaml)); |                 return new LanguageSupport(StreamLanguage.define(yamlMode.yaml)); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ export const DefaultBrand: CurrentBrand = { | |||||||
|     brandingLogo: "/static/dist/assets/icons/icon_left_brand.svg", |     brandingLogo: "/static/dist/assets/icons/icon_left_brand.svg", | ||||||
|     brandingFavicon: "/static/dist/assets/icons/icon.png", |     brandingFavicon: "/static/dist/assets/icons/icon.png", | ||||||
|     brandingTitle: "authentik", |     brandingTitle: "authentik", | ||||||
|  |     brandingCustomCss: "", | ||||||
|     uiFooterLinks: [], |     uiFooterLinks: [], | ||||||
|     uiTheme: UiThemeEnum.Automatic, |     uiTheme: UiThemeEnum.Automatic, | ||||||
|     matchedDomain: "", |     matchedDomain: "", | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens L.
					Jens L.