Custom extended themes
Proposed
- Added new Theme objects in backend, along with relevant resolvers and such
- Modified Settings page to allow admins to create, modify, export, and import custom themes
- Modified Settings page to allow admins to select default platform theme from a dynamic list
- Modified User profile page to select their preferred theme from a dynamic list
- Modified frontend theming to use dynamic themes instead of dark/light themes
- Added text color to themes
- Admins may delete non-system default themes (e.g. anything besides light and dark mode)
- System themes are translated
- Admins cannot delete a currently active platform default theme
- Deleting a theme currently used by a user will change the user's selected theme to the platform default
Related issues
- https://github.com/OpenCTI-Platform/opencti/pull/9456
Checklist
- [x] I consider the submitted work as finished
- [x] I tested the code for its functionality
- [x] I wrote test cases for the relevant uses case (coverage and e2e)
- [ ] I added/update the relevant documentation (either on github or on notion)
- [x] Where necessary I refactored code to improve the overall quality
Codecov Report
Attention: Patch coverage is 30.57554% with 193 lines in your changes missing coverage. Please review.
Project coverage is 64.85%. Comparing base (
7e8e794) to head (a6cf749).
Additional details and impacted files
@@ Coverage Diff @@
## release/current #10675 +/- ##
===================================================
- Coverage 65.01% 64.85% -0.17%
===================================================
Files 727 732 +5
Lines 71924 72199 +275
Branches 7857 7852 -5
===================================================
+ Hits 46761 46824 +63
- Misses 25163 25375 +212
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
-
The
Cancelbutton doesn't work in the create drawer -
When you create a theme, you set the name in the create form, errors are displayed in the other mandatory fields.
-
You can copy the behaviour of the other create forms, the goal is to have a star (
*) in mandatory fields, display errors after validation, remove error if the field is valid
* When you create a theme, you set the name in the create form, errors are displayed in the other mandatory fields.
I set the Formik validation for the create theme form to
validateOnChange={false}
validateOnBlur={false}
Is this alright?
- [x] Cancel Button
- [x] Don't validate all fields before the first change
- [x] Display stars on mandatory fields
- [x] Don't disable the
createbutton if!isValidbut ifisSubmitting(it's the behaviour on other create form) - [x] Replace always the initial values on Edition form (if I open the form, update a color value with a not valid value, example empty, I close the form and I open it, the empty value is still displayed, but I want to see the initial value)
Error management on the DetectDuplicate query is not clear :
I try to create a new theme :
-
I enter the name
Dark -
The query return the theme Dark with the same name => CLEAR
-
I enter the name
Test -
The query return an error
Theme already exists
The current behaviour :
- I try to create a report
- I enter the name
Test - The query doesn't find any report
- It's not an error, juste return an empty array
Import type validation
Currently, I can import any json file into the import theme module.
The actual behaviour, for example Dashbord import, if the file doesn't has the right type, the dashboard isn't created.
Ok for the feature. But i try to test the migration with this process :
- From release/current branch
- Start a new platform
- Don't touch the platform theme
- Stop this platform
- Checkout to custom_extended_themes branch
- Start the platform
- it will execute the migration
- I have an error in the backend
{"level":"info","message":"[MIGRATION] 1 migrations will be executed","timestamp":"2025-07-10T07:26:53.025Z"}
{"level":"info","message":"[MIGRATION] Replacing platform theme with Theme ID > started","timestamp":"2025-07-10T07:26:53.026Z"}
{"category":"APP","cause":{"code":"UNKNOWN_ERROR","message":"Cannot convert undefined or null to object","name":"TypeError","stack":"TypeError: Cannot convert undefined or null to object\n at Object.keys (<anonymous>)\n at <anonymous> (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\modules\\theme\\theme-domain.ts:104:14)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Migration2.up126 (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\migrations\\1751397354695-set-default-theme.js:19:18)"},"level":"error","message":"Migration up error","source":"backend","timestamp":"2025-07-10T07:26:53.029Z","version":"6.7.1"}
{"category":"APP","level":"info","message":"[INIT] Platform initialization done","source":"backend","timestamp":"2025-07-10T07:26:53.031Z","version":"6.7.1"}
{"category":"APP","cause":{"code":"UNKNOWN_ERROR","message":"Cannot convert undefined or null to object","name":"TypeError","stack":"TypeError: Cannot convert undefined or null to object\n at Object.keys (<anonymous>)\n at <anonymous> (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\modules\\theme\\theme-domain.ts:104:14)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Migration2.up126 (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\migrations\\1751397354695-set-default-theme.js:19:18)"},"level":"error","message":"[OPENCTI] Platform default initialization failed","source":"backend","timestamp":"2025-07-10T07:26:53.031Z","version":"6.7.1"}
Ok for the feature. But i try to test the migration with this process :
* From release/current branch * Start a new platform * Don't touch the platform theme * Stop this platform * Checkout to custom_extended_themes branch * Start the platform * it will execute the migration * I have an error in the backend{"level":"info","message":"[MIGRATION] 1 migrations will be executed","timestamp":"2025-07-10T07:26:53.025Z"} {"level":"info","message":"[MIGRATION] Replacing platform theme with Theme ID > started","timestamp":"2025-07-10T07:26:53.026Z"} {"category":"APP","cause":{"code":"UNKNOWN_ERROR","message":"Cannot convert undefined or null to object","name":"TypeError","stack":"TypeError: Cannot convert undefined or null to object\n at Object.keys (<anonymous>)\n at <anonymous> (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\modules\\theme\\theme-domain.ts:104:14)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Migration2.up126 (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\migrations\\1751397354695-set-default-theme.js:19:18)"},"level":"error","message":"Migration up error","source":"backend","timestamp":"2025-07-10T07:26:53.029Z","version":"6.7.1"} {"category":"APP","level":"info","message":"[INIT] Platform initialization done","source":"backend","timestamp":"2025-07-10T07:26:53.031Z","version":"6.7.1"} {"category":"APP","cause":{"code":"UNKNOWN_ERROR","message":"Cannot convert undefined or null to object","name":"TypeError","stack":"TypeError: Cannot convert undefined or null to object\n at Object.keys (<anonymous>)\n at <anonymous> (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\modules\\theme\\theme-domain.ts:104:14)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Migration2.up126 (C:\\Users\\FrancoisGrunert\\IdeaProjects\\opencti\\opencti-platform\\opencti-graphql\\src\\migrations\\1751397354695-set-default-theme.js:19:18)"},"level":"error","message":"[OPENCTI] Platform default initialization failed","source":"backend","timestamp":"2025-07-10T07:26:53.031Z","version":"6.7.1"}
@frapuks Thanks for letting me know. I just fixed this and tested it on a brand new db. It should work for you now.