Skip to content

Graph page topic selection preset#629

Open
TheJeffreyKuo wants to merge 5 commits intodevelopfrom
566-add-graph-page-topic-selection-presets
Open

Graph page topic selection preset#629
TheJeffreyKuo wants to merge 5 commits intodevelopfrom
566-add-graph-page-topic-selection-presets

Conversation

@TheJeffreyKuo
Copy link
Copy Markdown

Changes

Adds a client-side topic-selection preset system to the graph page so engineers can save and reapply named topic groupings without having to reselect each session. New GraphPresetService persists presets in localStorage. New PresetDialogComponent provides save selection, apply, upload, download, delete, and restore defaults actions. It opens from both graph sidebars via DialogService. The graph sidebar gets a presets row above the topic tree containing a select dropdown for fast applying and a manage button, with the dropdown's defaultValue bound to activePresetName so it tracks the live selection.

Notes

  • All commits are tagged with the ticket number
  • No linting errors / newline at end of file warnings
  • All code follows repository-configured prettier formatting
  • No merge conflicts
  • All checks passing
  • Screenshots of UI changes (see Screenshots section)
  • Remove any non-applicable sections of this template
  • Assign the PR to yourself
  • Request reviewers & ping on Slack
  • PR is linked to the ticket (fill in the closes line below)

Closes #566

@TheJeffreyKuo TheJeffreyKuo self-assigned this Apr 28, 2026
const topicNames = this.currentSelection().map((dt) => dt.name);
const existing = this.presetService.findByName(name);
if (existing) {
if (!confirm(`A preset named "${name}" already exists. Replace its topics?`)) return;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Three native confirm() calls (here, line 94, line 138) block the JS thread, break the dialog's dark theme, and aren't testable. The repo already uses PrimeNG's ConfirmationService — see car-command-page/car-command.component.ts:101-108. Suggest swapping all three to confirmationService.confirm({ message, header, acceptLabel, rejectLabel, accept: () => ... }) and adding <p-confirmDialog /> to the dialog template.

Comment on lines +124 to +134
onDownload(preset: Preset): void {
const exported: PresetSeed = { name: preset.name, topicNames: [...preset.topicNames] };
const blob = new Blob([JSON.stringify(exported, null, 2)], { type: 'application/json;charset=utf-8;' });
const url = URL.createObjectURL(blob);

const link = document.createElement('a');
link.href = url;
link.download = `${this.sanitizeFilename(preset.name)}.json`;
link.click();

URL.revokeObjectURL(url);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This Blob + createObjectURL + hidden anchor pattern is line-for-line the same as notification-rules-page.component.ts:401-408 (downloadRulesAsCsv). Worth extracting downloadAsFile(filename, content, mimeType) into a utils/file-download.utils.ts and using it from both call sites.

Comment on lines +71 to +108
onFileSelected(event: Event): void {
const input = event.target as HTMLInputElement;
const file = input.files?.[0];
if (!file) return;

input.value = '';

if (!file.name.toLowerCase().endsWith('.json')) {
this.messageService.add({ severity: 'error', summary: 'Invalid File', detail: 'Please select a .json file' });
return;
}

const reader = new FileReader();
reader.onload = () => {
const text = reader.result as string;
const parsed = this.parsePresetJson(text);
if (!parsed) return;

const fallbackName = file.name.replace(/\.json$/i, '').trim() || 'Untitled Preset';
const name = parsed.name?.trim() || fallbackName;

const existing = this.presetService.findByName(name);
if (existing) {
if (!confirm(`A preset named "${name}" already exists. Replace its topics?`)) return;
this.presetService.replacePreset(existing.id, { topicNames: parsed.topicNames });
} else {
this.presetService.addPreset(name, parsed.topicNames);
}
this.messageService.add({
severity: 'success',
summary: 'Preset Imported',
detail: `"${name}" with ${parsed.topicNames.length} topic(s)`
});
};
reader.onerror = () => {
this.messageService.add({ severity: 'error', summary: 'Read Error', detail: 'Failed to read file' });
};
reader.readAsText(file);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same shape as notification-rules-page.component.ts:182-204 — extension check → reset input.valueFileReader.readAsText with onload/onerror, even down to the same toast wording. Pair with the downloadAsFile extraction above and add a readTextFile(file, allowedExt): Promise<string> helper.

// silently skipped on Apply (with a warn toast), not hard-errored.
export const PRESET_SEEDS: PresetSeed[] = [
{
name: 'test preset',
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

'test preset' ships to every fresh user via loadOrSeed(). Replace with real defaults or empty array.

this.subject.next(this.loadOrSeed());
}

getPresets = (): BehaviorSubject<Preset[]> => this.subject;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Returns the writable subject — callers can .next() and bypass save(). Return subject.asObservable() to force callers through the typed mutators.

Comment on lines +137 to +144
if (unknown.length > 0) {
this.messageService.add({
severity: 'warn',
summary: 'Unknown Topics Skipped',
detail: unknown.join(', '),
life: 8000
});
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same warn toast lives in three files (here, graph-sidebar-mobile.component.ts, and preset-dialog.component.ts). Move into the service or a helper.

@TheJeffreyKuo TheJeffreyKuo requested a review from bracyw April 29, 2026 21:29
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.

Add graph page topic selection presets

2 participants