[IGN-13768] Perspective Custom Theming Not Working After 8.3 Migration

After migrating my project (not in production) to 8.3, my Perspective themes stopped working. The migration added .migrated to my theme folder names. I've tried renaming them back to the original structure and restarted the gateway, but themes still won't load.



Is there a specific migration process for Perspective themes in 8.3? The upgrade guide doesn't mention theming migration.
Before upgrade:

Summary

After:

Summary

I think they should have been migrated to something like $IGNITION/data/config/resources/core/com.inductiveautomation.perspective/config-perspective-(fonts|icons|themes).

Can you at least confirm whether there are resources there or not?

As to why it does or doesn't work if they have been migrated... gonna have to leave that up to somebody who knows better tomorrow.

They're there yes. But not all of them looks like it.

Just to clarify, not all resources migrated to the new location. I’ve had common folders and they’re missing along with individual css files that were in the root folder of themes.

I made a ticket for the incomplete migration, I'll still try to get somebody who knows about this stuff to come by and take a look later today.

1 Like

Are you able to share a .gwbk (private message or otherwise)? It sounds like we just didn't cover all the edge cases in the theme migration process.

1 Like

Check icons too. I was just messing with custom icons to help someone on another post and saw a post about custom icons not working on 8.3. I tried manually creating a custom icon library that I tested in 8.1 and it is not working in my 8.3 beta VM.

I tried adding an "icons" folder and putting the library SVG in various places in that area but the designer doesn't see it.

I'm going to try a few more things but I think it's broken in general.

I've attached the sample icon library to make reproduction easier.

Custom-sample

It won't be detected as a resource until you add a resource.json file, which is different than the behavior of 8.1 - that may be the discrepancy.

1 Like
1 Like

Hi Andrew,

Thanks for bringing this up. We had to restructure the theming system in a couple of ways, in order for it to work with the new config system in 8.3. The migration and theme import resolution logic was formed around the requirement, and assumption, of having a theme file at the root of the themes folder (see readme in themes folder). I believe that’s why we’re seeing issues with imports for “sage_asm-common” and “bis_common," which is used by “sage_asm-light”, “bis-asm-light”, and “bis_asm-light.” At least, mostly.

It appears that the common stylesheet directories, “bis_common," and “sage_asm-common,” aren’t actually meant to be standalone themes, and thus breaks our resolution logic. In an ideal scenario, both of those directories would have had an accompanying “bis_common.css” and “"sage_asm-common.css” file that lived at the root of the themes directory, just like “bis_asm-light.css."

We’re looking into improving our resolution and migration logic. It’s very likely that some small (or maybe large) modifications will be necessary in order to get this to work.

5 Likes

@andrew.budaiev

Thanks again for sharing your custom themes with us to help improve theme migration. The final 8.3.0 release will include these improvements. In order to get your valid themes to work, you and others may need to make some small adjustments to theme import paths. Specifically, make sure themes importing from other themes point to the actual file within that imported theme’s directory. For example, change @import “./light.css" to @import "../light/index.css", just like we’ve done with our derived themes. It’s easiest to do this before the migration, but is still just as easy to do after migration. Check out the new theming readme below. Included is a section on migrating to 8.3 (last section).

A Guide to Theming in Perspective

Overview

Theming in Perspective allows designers to customize the look-and-feel (not layout) of their Perspective projects at a broad level. A projects active theme is defined in a project's session properties. Where applicable, any styles applied using Perspective Style Classes or inline styles within the Designer should still override anything inherited from a theme. It is possible to work around this rule, but that is not something we would recommend. Theming is considered an advanced feature of Perspective. As such, we operate under the assumption that anyone altering these files has some knowledge of CSS. By making use of CSS variables, imports, and descriptive class selectors, you will find that we have provided features and structure to help alleviate some of the frustrations inherent to managing large amounts of CSS.

Available Themes

As of writing this, the following themes have been made available to you, by us. They are bundled with Perspective.

  • light (base theme)
  • light-warm
  • light-cool
  • dark
  • dark-warm
  • dark-cool

Creation and Modification

Themes can be created and modified using either Ignition's OpenAPI HTTP specification (recommended), or directly in the config file system, in the core resource collection. Any modifications done directly in the file system will require a rescan of the file system. There is a button in the Gateway Web UI's projects page (.../system/projects) that can be used to trigger a rescan.

Structure

A valid theme has the following structure:

    ```
    - custom-theme
    |- index.css // theme entry configurable in config.json
    |- config.json // theme configuration file
    |- resource.json // internal resources file
    ```

Within the config.json are two important properties, "entrypoint" and isPrivate. By default the entrypoint of your theme, which we use for processing, is index.css. The "isPrivate" property let's us know if the theme should be listed as an available theme. By default, this is true. Setting this to false is particularly useful if your "theme" is shared between multiple themes that are listed as available themes.

Before getting started, we recommend that you familiarize yourself with the structure of one of our provided themes.

** IMPORTANT **

Both the light and dark themes are owned and maintained by Inductive Automation. This means that they can't be altered. However, the derived themes (light-cool, dark-cool, etc.) can be modified freely.

Features

CSS Variables

CSS variables have a central role in theme authoring. We recommend leveraging this built in feature of CSS to aid in modular theme development and ease frustrations of long term maintenance. We use CSS variables throughout our theme stylesheets, so whenever there may be a need to change something like a color, it only needs to be changed in a single file.

Declaring variables:

--corporateColor: #FF5D00;

Using variables:

background-color: var(--corporateColor);

Variables can also be used in the Designer's property editor as the value of a components style property. Assuming that the variable exists, of course. Simply specify the variables name as the style property value:

backgroundColor: --corporateColor

Descriptive CSS Classes

Component authors specify unique CSS class selectors that give you direct access to the styling of particular elements. Each class selector is unique enough to prevent clashing and descriptive enough to minimize any guessing surrounding its dedicated purpose. We follow a standard naming convention called ABEM (Atomic Block Element Modifier).

Convention in a nutshell:

atomicPrefix_blockName__elementName--modifierName

In use:

ia_cylindricalTankComponent__liquid--animation

Keep in mind that these unique classes give you direct access to specific elements. You can find a list of available selectors, and their defined rules, in their respective files. If you can not find the selector you need, then it is likely not defined. You may either request it or use one of the many other ways to style elements in Perspective.

CSS Imports

Imports provide the ability to develop or author themes in a modular fashion. They also make overriding easy (see section on overriding themes). There are two rules that we expect you to follow when using imports.

  1. Imports should be declared at the top of each CSS file.

  2. Each import statement must begin with the CSS at-rule @import, specify the relative path to the file to import, and terminate with a semicolon. Imports that do not meet this criteria may be ignored. You may use single or double quotes surrounding the import path. For example:

     ```
      @import "../button.css";  
      @import './variables.css';
     ```
    

Overriding or Adapting Themes

Overriding or adapting themes is easy by leveraging the "C" in CSS (Cascading Style Sheet). Simply add your own CSS import pointing to your own custom style sheet containing the rulesets that you want to override or adapt AFTER any existing imports. For example, to override something declared in one of our bundled themes light-cool, add your own import in the light-cool/index.css entry file like so:

light-cool.css

@import "./light/index.css" 
@import "./custom/overrides.css"

We do not attempt to rewrite this file on startup unless it does not exist.

Creating Custom Themes

To create your own custom theme, either use Ignition's HTTP OpenAPI (recommended) or create the necessary structure on the filesystem (refer to the structure section above). Use one of the bundled themes as an example. Any derivative themes (light-cool, dark, dark-warm, etc.) will serve as ideal examples for most use cases. We recommend looking at these. The derivative themes simply extend the base theme (light), but overrides the values of some of the CSS variables that define fundamental colors.

The most important items to remember when authoring your own theme are:

  1. Ensure that the structure is correct and that an entry file has been defined in the theme resource's config.json.
  2. Order matters. Duplicate rules that come after existing rules will override or supplement depending on declared properties between the two.
  3. The light theme is the base theme, and all themes should extend from this. If any of the rules defined in the provided base theme (light) are missing from your custom theme, either from not being declared or not being imported, the result of these missing properties will be reflected in your project (for example, a button missing a border). When creating your own custom themes, make sure that rulesets declared in the base theme (light) exist in your custom theme at all times, unless of course you've accommodated for this in some other way.
  4. Our updated base themes light and dark can be copied into the core resources folder by submitting a POST HTTP request {gateway_url}/data/perspective/api/v1/themes/copy-base-themes. This is to make referencing our base themes easier. The API token used in this request must have write permissions. Any modifications to these copied base themes are ignored.

Migrating to 8.3

In 8.1, theme authorship relied soley on the filesystem. In 8.3, with the new config overhaul and resource collection model, we have had to slightly change the existing theme structure to conform to this new model. The old entry point files that existed at the root of the themes folder (i.e., themes/light.css, themes/custom-theme.css, etc.) have been removed. They are no longer used to determine the available themes. Instead, each respective theme gets a config.json. Within this config file is an isPrivate property that when set to true will prevent this theme from being listed as an available theme. This is useful in instances where you may have a common or shared set of theme resources that other themes might import or extend. Also within this config is the entrypoint property that lets us know where to start processing your theme. This is generally an index.css file that exists within your theme folder (i.e., themes/custom/index.css). By default it is index.css, but you may change this if you’d like.

If you followed the structure and format we used for our bundled themes (light, dark, light-cool, dark-warm, etc.), then your themes should migrate successfully. If not, you will likely need to update some of your imports, and in some situations create a new theme. For example, if your old custom-theme.css entry file had an import like @import “./light.css”, you will need to add @import “../light/index.css” to your theme's entrypoint file (custom-theme/index.css). Like we mentioned, we have gotten rid of the old entry files. All external imports or declarations that you might have had in that old entry file, will need to be moved into the new entrypoint file for your theme. Luckily, you can find all of those original migrated files in the .migrated-themes-TIMESTAMP directory within data/modules/com.inductiveautomation.perspective. You can reference the old files to help resolve your imports and move to this new structure.

In circumstances where you may have had an old entry file (i.e., themes/test-theme.css), but no peer directory of the same name (i.e., themes/test-theme), you will find that we have created one for you as part of the migration process. Within this migrated directory will be an index.css entrypoint. You will need to update this index.css to include any imports you might have included in the old entry file. We did not attempt to resolve, modify, or move, any imports during the migration.

7 Likes

Hi @ynejati

I tried to overriding the Perspective out of the box theme like cool-light as you described and it is working but when I try to do the same thing for light or dark theme, it only apply my variables and as there is no CSS files for light and dark in light folder all default CSS files are missing here. Of course, I can open perspectve.modl file and copy the light and dark css files into the themes folder but the problem it break IA future update as well.

What I need is to add my own CSS variables to default dark and light theme as most people use those theme by default.

So my question is when there is no light/dark files in themes folder, how can I add my own css code and extend it?

You cannot. This was clearly declared above:

You will have to alter the others or offer your own theme names.

(Project stylesheets can supplement the base themes, though.)

I think there will eventually be a route, and maybe UI to go with it, that allows you to do a one time copy of a theme's files from the "system" to "core" collection, at which point they will exist on disk and can be customized, though the discussion I'm referencing seems to also maintain that light and dark won't be overridable.

1 Like

I am trying to add custom themes that extend the light.css and dark.css themes. I can’t seem to get the @import to work. I tried looking up the light-cool.css and light-cool/index.css files, but I cannot find the light-cool/index.css file through the api. Any help would be really appreciated!

/data/api/v1/resources/datafile/com.inductiveautomation.perspective/themes/light-cool/light-cool.css
returns @import "./light-cool/index.css";

but there doesn’t seem to be a way for me to look at light-cool/index.css to see how it’s importing the light theme.

/data/api/v1/resources/datafile/com.inductiveautomation.perspective/themes/light-cool/index.css
returns a 404 page

I saw above that I should change @import “./light/index.css” to @import “../light/index.css" but this doesn’t work.

In my custom light theme folder, my config.json has the entrypoint set to index.css. And index.css has the following:
@import "../light/index.css";
@import "./variables.css";

the variables.css file exists in the same directory, but I don’t know where light/index.css is and my custom theme looks mostly unstyled without the base light.css styles.

Also, do I have to make these datafiles manually? I couldn’t seem to create them through the API. Is this the correct endpoint for that? /data/api/v1/resources/datafile/com.inductiveautomation.perspective/themes/{name}/{filename}

Thank you

I’m wondering how should I handle custom CSS variables in my Perspective components module. My components should render properly in both light and dark theme not a custom theme.

When someone installs a custom Perspective components module out of the box, they may use it with the default light or dark theme. In that case, I can’t import my own CSS variables into the theme, and my components are limited to the CSS variables that Ignition provides—which are quite limited.

I know I can define my own CSS variables in the module’s private CSS file, but that approach doesn’t support theme switching in Perspective.

Hey Nader. Unfortunately the only way to override our base themes is to create a custom theme that inherits from our base themes. Luckily that’s very easy to do, and even easier once we create a dedicated UI for this in the Gateway.

Good point about the custom component module, and additional variables. I’ll look into this immediately. Thanks!

1 Like

Hey Daniel. That’s to be expected, as the changes I described in my post above haven’t been released yet. They’ll be available in the 8.3.0 final release. We missed the deadline for the RC by a few days.

You can check to see if the file exists by viewing the config:
{{gateway_address}}/data/api/v1/resources/find/com.inductiveautomation.perspective/themes/:name

For reference, the contents of light-cool/index.css:

@import "./variables.css";
@import "../light/fonts.css";
@import "../light/globals.css";
@import "../light/app/index.css";
@import "../light/common/index.css";
@import "../light/designer/index.css";
@import "../light/palette/index.css";

Hope this helps.


Update

In 8.3.0, we’ve added the ability to override our light and dark themes, just like in 8.1. In order to do so, you must create a new theming resource called overrides-[light/dark]. Make sure that the theme config isPrivate: true in order to hide the theme from themes list. Example POST payload:

[
  {
    "name": "overrides-light",
    "collection": "core",
    "enabled": true,
    "description": "Overrides light theme.",
    "config": {
      "entrypoint": "index.css",
      "isPrivate": true
    }
  }
]

If we detect an override resource, we simply redirect the entry point of the Perspective base theme to the entry point specified in the overriding theme resource config. The contents of the overriding entry point (typically `index.css) can be as simple as:

@import "../light/index.css";

:root {
  --customVariable: "whatever";
}

Or, as complicated as:

@import "./variables.css";
@import "../light/fonts.css";
@import "./globals.css";
@import "../light/app/index.css";
@import "../light/common/index.css";
@import "../light/designer/index.css";
@import "../light/palette/index.css";

Either way, it's up to you to make sure the base theme imports are included in your overriding theme.

Thanks again for bringing it up, @nader.chinichian. Hope this helps.

3 Likes

@ynejati & @andrew.budaiev I am having the same issues and I feel everyone’s posts are confusing everything. First, @andrew.budaiev is referencing the “migrated” folder from what I believe is the 8.1 themes. Second, @Kevin.Herron is referencing what looks to be a “core” folder that contains themes which is unclear if this is for 8.3.

My question is, what is the correct path for themes that Ignition Perspective 8.3 uses? Please see my images of the different file paths.

The former, data/config/resources/core/com.inductiveautomation.perspective/themes/, is the only path that the system is looking at in 8.3.
data/modules/com.inductiveautomation.perspective/themes was the path in 8.0/8.1.
The "migrated" path that's been mentioned is basically a safety valve - during the 8.1 to 8.3 upgrade process we automatically back up the originals because the migration process is not exactly 1:1. It will only exist if you had any 'legacy' themes to migrate.

1 Like