Skip to content

Content copilot UI#793

Open
deckdom wants to merge 5 commits into
devfrom
f-content-copilot-ui
Open

Content copilot UI#793
deckdom wants to merge 5 commits into
devfrom
f-content-copilot-ui

Conversation

@deckdom
Copy link
Copy Markdown
Member

@deckdom deckdom commented May 5, 2026

No description provided.

Philipp Doerre added 4 commits May 5, 2026 08:54
- new CopilotModule with sidebar component (header, empty container,
  disabled chat input)
- toolbar button surfaces only while a page is in EDIT mode and the
  customer-supplied {ui-conf}/config/copilot.yml has 'enabled: true'
- YAML config supports an 'actions:' list, parsed by a dependency-free
  parser; sidebar renders entries automatically when populated
- feature is fully disabled by default — no behaviour change without
  config file present
- new CopilotModule (sidebar component, YAML config loader, runtime state)
- toolbar button surfaces only while a page is in EDIT mode and the
  customer-supplied {ui-conf}/config/copilot.yml has 'enabled: true'
- YAML supports an 'actions:' list parsed by a small dependency-free
  parser; sidebar renders entries automatically when populated
- services use providedIn: 'root' so the bootstrap-time fetch survives
  ContentFrameModule being lazy-loaded; load() is triggered from
  AppComponent.ngOnInit, mirroring UIOverridesService
- de/en i18n entries under 'copilot.*'
- feature is fully disabled by default — no behaviour change without
  config file present
- new CopilotModule with sidebar component (header, action container,
  disabled chat input); CopilotConfigService and CopilotStateService
  use providedIn: 'root' so the bootstrap-time fetch survives
  ContentFrameModule being lazy-loaded — load() is triggered from
  AppComponent.ngOnInit, mirroring UIOverridesService
- toolbar button surfaces only while a page is in EDIT mode, the
  customer-supplied {ui-conf}/config/copilot.yml has 'enabled: true',
  the page is not locked and not in language comparison
- YAML supports an 'actions:' list parsed by a small dependency-free
  parser; sidebar renders entries automatically when populated — no
  UI rebuild required to add or change actions
- de/en i18n entries under 'copilot.*'
- styling reuses existing SCSS variables; drawer drop shadow extracted
  into a reusable gcmsDrawerBoxShadow mixin in _variables.scss; sidebar
  width expressed in rem
- specs for copilot-yaml.parser, CopilotStateService and
  CopilotConfigService; existing EditorToolbarComponent spec extended
  with a MockCopilotConfigService
- feature is fully disabled by default — no behaviour change without
  config file present
- copilot.spec.ts in apps/editor-ui/e2e covering button visibility,
  open/close interaction, empty-state vs configured action rendering,
  and the disabled chat input
- each test stubs {ui-conf}/config/copilot.yml via page.route before
  navigateToApp so the App-Initializer fetch sees the per-test response
- add data-id attribute to copilot-sidebar action items so the spec
  can target individual cards reliably
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Philipp Doerre seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a YAML Parser.
The Configuration itself should either be a JSON file, or in the future will be done in the CMS, and will be made available via a REST Endpoint in JSON.

* dot it's treated as an i18n key, otherwise rendered as-is. Keeps
* configuration files concise without precluding localisation.
*/
label: string;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be labelI18n with a I18nString type, as translation strings only work if they are bundled into the editor-ui already, which limits the use-case for this.

* Short description shown under the label. Same dot-vs-literal
* heuristic as `label`.
*/
description?: string;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as label above, with descriptionI18n

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the tests for the parser, as there shouldn't be a parser to begin with

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state should be done in the already used NgXS store, instead of a custom solution.
Since it's only a single boolean flag, it should be integrated into the existing ui state.

await expect(summarize).toBeVisible();
await expect(summarize.locator('.copilot-action-label')).toHaveText('Zusammenfassen');
await expect(summarize.locator('.copilot-action-description'))
.toHaveText('Eine kurze Zusammenfassung der Seite erstellen');
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking for translatable text values is not a good way to test.
While the settings are stubed and therefore the values are known, these texts can't be directly used due to changes for label -> labelI18n and description -> descriptionI18n.

We'd first need to ensure a specific UI language (as it's initially determined by the browser/system language), and therefore translation texts may differ.

[title]="'copilot.button_tooltip' | gtxI18n"
(click)="toggleCopilot()"
>
<icon left>auto_awesome</icon>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no icon named auto_awesome in the material symbols font.

* invalidation.
*/
public load(): void {
const url = `${CUSTOMER_CONFIG_PATH}config/copilot.yml?t=${Date.now()}`;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the path ui-conf/config? Should be simply ui-conf

<icon class="copilot-action-icon">{{ action.icon }}</icon>
}
<div class="copilot-action-text">
<span class="copilot-action-label">{{ action.label }}</span>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label and description need to be translated using the gtxI18n pipes, or with the changes for labelI18n and descriptionI18n using the gtxI18nObject pipe.


<footer class="copilot-sidebar-footer">
<div class="copilot-chat-input">
<textarea
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the existing gtx-textarea component instead and remove special styling for this textarea.

- drop the hand-rolled YAML parser; load `{ui-conf}/copilot.json` as
  JSON via JSON.parse with shape validation (review #1, #7, #15)
- switch action label/description to per-language objects `labelI18n`
  and `descriptionI18n` (type: `I18nString` = Record<string,string>)
  so config values stay translatable without UI rebuild (review #3, #5)
- new `gtxI18nObject` pipe in cms-components for resolving I18nString
  against the active UI language with en-fallback (review #17)
- move sidebar open/close flag from a custom service into the existing
  NGXS UI state slice (`state.ui.copilotOpen` + `SetCopilotOpenAction`);
  remove `CopilotStateService` (review #9)
- replace native <textarea> with <gtx-textarea>; drop the custom CSS
  that styled the native element (review #19)
- replace `auto_awesome` icon with `lightbulb` (subset-safe) (review #13)
- e2e tests no longer assert on translated label text — they verify
  structural hooks (data-id, label container non-empty) so the suite
  stays language-agnostic (review #11)
- update COPILOT.md docs and copilot.example.json accordingly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants