From a57ecfd86c5dfd90540337c379aecc55946b7e49 Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Mon, 9 Mar 2026 15:26:00 +0200 Subject: [PATCH 01/16] Redesign automations UI with card-based creation flow and trigger pills Replace dropdown-based rule creation with visual WHEN/THEN card layout. Add colored trigger pills with glow states, action method pills, and unified styling for both creation and edit views. Save button shows "Saved" state after successful save. Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions.component.css | 392 ++++++++++++++++ .../db-table-actions.component.html | 425 +++++++++++++----- .../db-table-actions.component.ts | 75 +++- 3 files changed, 782 insertions(+), 110 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index f4b0059b0..08c807dd3 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -35,6 +35,12 @@ text-align: center; } +@media (prefers-color-scheme: dark) { + .no-actions { + color: rgba(255, 255, 255, 0.5); + } +} + /* .new-action-input { background-color: transparent; margin-top: 12px; @@ -326,3 +332,389 @@ color: rgba(255, 255, 255, 0.64); } } + +/* ── Creation flow ── */ + +.creation-flow { + flex-grow: 1; + margin-top: 20px; +} + +.creation-flow__form { + display: flex; + flex-direction: column; + gap: 24px; + max-width: 900px; +} + +.creation-flow__name { + width: 50%; +} + +.creation-flow__actions { + margin-top: auto; + display: flex; + justify-content: space-between; +} + +/* ── Step badges ── */ + +.step-label__badge { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.65em; + font-weight: 700; + letter-spacing: 0.05em; + padding: 3px 8px; + border-radius: 4px; + margin-right: 8px; + vertical-align: middle; +} + +.step-label__badge--when { + background-color: rgba(156, 39, 176, 0.2); + color: #ce93d8; +} + +.step-label__badge--then { + background-color: rgba(33, 150, 243, 0.2); + color: #64b5f6; +} + +@media (prefers-color-scheme: light) { + .step-label__badge--when { + background-color: rgba(123, 31, 162, 0.12); + color: #7b1fa2; + } + + .step-label__badge--then { + background-color: rgba(21, 101, 192, 0.12); + color: #1565c0; + } +} + +/* ── Cards ── */ + +.creation-card { + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 8px; + padding: 20px 24px; +} + +@media (prefers-color-scheme: dark) { + .creation-card { + border-color: rgba(255, 255, 255, 0.12); + background-color: #1e1e1e; + } +} + +.creation-card--disabled { + opacity: 0.35; + pointer-events: none; +} + +.creation-card__label { + font-weight: 500; + display: block; + margin-bottom: 16px; +} + +.creation-card__hint { + font-style: italic; + color: rgba(0, 0, 0, 0.45); +} + +@media (prefers-color-scheme: dark) { + .creation-card__hint { + color: rgba(255, 255, 255, 0.45); + } +} + +/* ── Trigger pills ── */ + +.trigger-pills { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.trigger-pills__or { + font-size: 11px; + font-weight: 500; + color: #5a5a70; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +@media (prefers-color-scheme: light) { + .trigger-pills__or { + color: #94a3b8; + } +} + +.trigger-pill { + display: inline-flex; + align-items: center; + gap: 7px; + padding: 7px 14px; + border-radius: 8px; + border: 1px solid #2a2a3a; + background: #0f0f18; + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s; +} + +.trigger-pill__icon { + font-size: 15px; + width: 15px; + height: 15px; +} + +/* Default colored text & icons per type */ +.trigger-pill--add-row { color: #4ade80; } +.trigger-pill--update-row { color: #38bdf8; } +.trigger-pill--delete-row { color: #f87171; } +.trigger-pill--custom { color: #c084fc; } + +.trigger-pill:hover { + border-color: #3a3a50; + background: #161620; +} + +/* Active states */ +.trigger-pill--add-row.trigger-pill--active { + border-color: #4ade80; + background: #0a1f14; + box-shadow: 0 0 0 1px rgba(74, 222, 128, 0.25), 0 0 12px rgba(74, 222, 128, 0.08); +} + +.trigger-pill--update-row.trigger-pill--active { + border-color: #38bdf8; + background: #071428; + box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.25), 0 0 12px rgba(56, 189, 248, 0.08); +} + +.trigger-pill--delete-row.trigger-pill--active { + border-color: #f87171; + background: #1a0808; + box-shadow: 0 0 0 1px rgba(248, 113, 113, 0.25), 0 0 12px rgba(248, 113, 113, 0.08); +} + +.trigger-pill--custom.trigger-pill--active { + border-color: #c084fc; + background: #150820; + box-shadow: 0 0 0 1px rgba(192, 132, 252, 0.25), 0 0 12px rgba(192, 132, 252, 0.08); +} + +/* Light mode overrides */ +@media (prefers-color-scheme: light) { + .trigger-pill { + background: #ffffff; + border-color: #e2e8f0; + } + + .trigger-pill--add-row { color: #16a34a; } + .trigger-pill--update-row { color: #0284c7; } + .trigger-pill--delete-row { color: #dc2626; } + .trigger-pill--custom { color: #9333ea; } + + .trigger-pill:hover { + border-color: #cbd5e1; + background: #f8fafc; + } + + .trigger-pill--add-row.trigger-pill--active { + border-color: #16a34a; + background: #f0fdf4; + box-shadow: 0 0 0 1px rgba(22, 163, 74, 0.25); + } + + .trigger-pill--update-row.trigger-pill--active { + border-color: #0284c7; + background: #f0f9ff; + box-shadow: 0 0 0 1px rgba(2, 132, 199, 0.25); + } + + .trigger-pill--delete-row.trigger-pill--active { + border-color: #dc2626; + background: #fef2f2; + box-shadow: 0 0 0 1px rgba(220, 38, 38, 0.25); + } + + .trigger-pill--custom.trigger-pill--active { + border-color: #9333ea; + background: #faf5ff; + box-shadow: 0 0 0 1px rgba(147, 51, 234, 0.25); + } +} + +/* Custom event inline */ +.custom-event-inline { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 16px; + margin-top: 16px; + padding-top: 16px; + border-top: 1px solid rgba(0, 0, 0, 0.08); +} + +@media (prefers-color-scheme: dark) { + .custom-event-inline { + border-top-color: rgba(255, 255, 255, 0.08); + } +} + +/* ── Affects row ── */ + +.affects-row { + display: flex; + flex-direction: column; + gap: 8px; + width: 100%; +} + +.affects-row__label { + font-weight: 500; + font-size: 0.85em; + color: rgba(0, 0, 0, 0.6); +} + +@media (prefers-color-scheme: dark) { + .affects-row__label { + color: rgba(255, 255, 255, 0.6); + } +} + +.affects-row__tabs { + display: flex; + gap: 8px; +} + +.affects-tab { + padding: 6px 16px; + border-radius: 4px; + border: 1.5px solid #1e1e24; + background: #0d0d0f; + color: #3f3f50; + font-size: 0.85em; + font-weight: 500; + cursor: pointer; + transition: border-color 0.15s, background-color 0.15s, color 0.15s; +} + +.affects-tab:hover { + border-color: #2e2e38; + color: #6a6a80; +} + +.affects-tab--active { + border-color: var(--color-accentedPalette-500); + background: rgba(var(--color-accentedPalette-500-rgb, 103, 58, 183), 0.12); + color: var(--color-accentedPalette-500); +} + +@media (prefers-color-scheme: light) { + .affects-tab { + background: #f5f5f7; + border-color: #e0e0e4; + color: #9090a0; + } + + .affects-tab:hover { + border-color: #c0c0c8; + color: #606070; + } +} + +/* ── Action method pills ── */ + +.action-methods { + display: flex; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 16px; +} + +.action-method-pill { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 8px 16px; + border-radius: 4px; + border: 1.5px solid #1e1e24; + background: transparent; + color: #3f3f50; + font-size: 0.9em; + font-weight: 500; + cursor: pointer; + transition: border-color 0.15s, background-color 0.15s, color 0.15s; +} + +.action-method-pill__icon { + font-size: 18px; + width: 18px; + height: 18px; +} + +.action-method-pill:hover { + border-color: #2e2e38; + color: #6a6a80; +} + +@media (prefers-color-scheme: light) { + .action-method-pill { + background: transparent; + border-color: #e0e0e4; + color: #9090a0; + } + + .action-method-pill:hover { + border-color: #c0c0c8; + color: #606070; + } +} + +.action-method-pill--active { + border-color: #1565c0; + background: rgba(21, 101, 192, 0.15); + color: #42a5f5; +} + +@media (prefers-color-scheme: light) { + .action-method-pill--active { + border-color: #1565c0; + background: rgba(21, 101, 192, 0.1); + color: #1565c0; + } +} + +/* ── Action fields ── */ + +.action-fields__input { + width: 60%; +} + +.action-fields__hint { + margin-top: -12px; + margin-bottom: 8px; + font-size: 0.85em; + color: rgba(0, 0, 0, 0.5); +} + +@media (prefers-color-scheme: dark) { + .action-fields__hint { + color: rgba(255, 255, 255, 0.5); + } +} + +@media screen and (max-width: 768px) { + .creation-flow__name, + .action-fields__input { + width: 100%; + } +} diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 54e6ab93f..ee260feef 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -25,8 +25,8 @@

Automations

{{ rule.title }} - - + Automations -
-
- +
+ + Name -
- Trigger(s) -
-
-
- or - - Event - - - {{ availableEvent.label }} - - - - -
-
-
-
- Custom event + +
+ + WHEN + trigger happens + + +
+ + or + + or + + or + +
-
+ @if (selectedRuleCustomEvent) { +
- Name + Button label - - Request confirmation +
+ Affects +
+ + +
+
- -
- - Affects - - Single row - - - Multiple rows - - -
+ }
-
-
- Action - - Actions type - - Email notification - Slack notification - URL webhook - - - - Action URL - - - - - Slack URL - - - - - Emails - - {{companyMember.name}} | {{companyMember.email}} - - + +
+ + THEN + action + + +
+ + +
-
- - - +
+ @if ($any(selectedRule.table_actions[0]).method === 'URL') { + + Webhook URL + + +

Requests are signed with HMAC-SHA256. Use the code snippets below to verify.

+ +
+ + + + + + + +
+ } + + @if ($any(selectedRule.table_actions[0]).method === 'EMAIL') { + + Notification emails + + + {{companyMember.name}} | {{companyMember.email}} + + + + } - - - - + @if ($any(selectedRule.table_actions[0]).method === 'SLACK') { + + Slack webhook URL + + + }
-
+
+
+ +
+ + @if (selectedRule && isCreationMode) { +
+
+ + Automation name + + + + +
+ + WHEN + trigger happens + + +
+ + or + + or + + or + +
+ + @if (selectedRuleCustomEvent) { +
+ + Button label + + + + + + Request confirmation + +
+ Affects +
+ + +
+
+
+ } +
+ + +
+ + THEN + action + + @if (!hasTriggersSelected) { + Add a trigger first + } @else { +
+ + + +
+ +
+ @if ($any(selectedRule.table_actions[0]).method === 'URL') { + + Webhook URL + + +

Requests are signed with HMAC-SHA256. Use the code snippets below to verify.

+ +
+ + + + + + + +
+ } + + @if ($any(selectedRule.table_actions[0]).method === 'EMAIL') { + + Notification emails + + + {{companyMember.name}} | {{companyMember.email}} + + + + } + + @if ($any(selectedRule.table_actions[0]).method === 'SLACK') { + + Slack webhook URL + + + } +
+ } +
+ +
+ +
+ } -
+

Configure custom triggers and actions for database records React to standard operations like create, update, delete, or define your own. diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts index 8c251ee7f..eedeb37c4 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts @@ -1,14 +1,16 @@ import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { HttpErrorResponse } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatListModule } from '@angular/material/list'; +import { MatMenuModule } from '@angular/material/menu'; import { MatRadioModule } from '@angular/material/radio'; import { MatSelectModule } from '@angular/material/select'; import { MatSidenavModule } from '@angular/material/sidenav'; @@ -43,6 +45,7 @@ import { ActionDeleteDialogComponent } from './action-delete-dialog/action-delet ClipboardModule, FormsModule, MatButtonModule, + MatButtonToggleModule, MatCheckboxModule, MatDialogModule, MatIconModule, @@ -51,6 +54,7 @@ import { ActionDeleteDialogComponent } from './action-delete-dialog/action-delet MatTooltipModule, MatSidenavModule, MatListModule, + MatMenuModule, MatRadioModule, MatTabsModule, CodeEditorModule, @@ -73,6 +77,7 @@ export class DbTableActionsComponent implements OnInit { }; public rules: Rule[]; public submitting: boolean; + public isSaved = false; public selectedRule: Rule = null; public selectedRuleCustomEvent: CustomEvent = null; public customAction: CustomAction = null; @@ -96,6 +101,8 @@ export class DbTableActionsComponent implements OnInit { 'schedule', ]; + @ViewChild('newActionInput') newActionInput: ElementRef; + public signingKey: string; public codeViewerOptions = { @@ -111,8 +118,16 @@ export class DbTableActionsComponent implements OnInit { { value: EventType.DeleteRow, label: 'Delete row' }, { value: EventType.Custom, label: 'Custom' }, ]; + + public triggerMeta: Record = { + [EventType.AddRow]: { icon: 'add_circle_outline', desc: 'Fires when a new row is inserted', color: '#4caf50' }, + [EventType.UpdateRow]: { icon: 'edit', desc: 'Fires when an existing row is modified', color: '#2196f3' }, + [EventType.DeleteRow]: { icon: 'delete_outline', desc: 'Fires when a row is removed', color: '#e53935' }, + [EventType.Custom]: { icon: 'tune', desc: 'Manual trigger with custom button', color: '#9c27b0' }, + }; public selectedEvents: string[] = []; public codeEditorTheme: 'vs' | 'vs-dark' = 'vs-dark'; + public isCreationMode = false; constructor( private _connections: ConnectionsService, @@ -175,6 +190,18 @@ export class DbTableActionsComponent implements OnInit { }); } + get hasTriggersSelected(): boolean { + return this.selectedRule?.events?.some((e) => e.event !== null) ?? false; + } + + get activeTriggers() { + return this.selectedRule?.events?.filter((e) => e.event !== null) ?? []; + } + + get unusedTriggerOptions() { + return this.availableEvents.filter((e) => !this.selectedEvents.includes(e.value)); + } + get currentConnection() { // this.codeSnippets = codeSnippets(this._connections.currentConnection.signing_key); return this._connections.currentConnection; @@ -208,6 +235,7 @@ export class DbTableActionsComponent implements OnInit { setSelectedRule(rule: Rule) { this.selectedRule = rule; this.selectedRuleTitle = rule.title; + this.isCreationMode = !rule.id; if (this.selectedRule.events[this.selectedRule.events.length - 1].event !== null) this.selectedRule.events.push({ event: null }); this.selectedEvents = this.selectedRule.events.map((event) => event.event); @@ -248,6 +276,8 @@ export class DbTableActionsComponent implements OnInit { }; this.setSelectedRule(this.newRule); + this.isCreationMode = true; + setTimeout(() => this.newActionInput?.nativeElement?.focus()); } addNewAction() { @@ -269,6 +299,7 @@ export class DbTableActionsComponent implements OnInit { this.selectedRuleTitle = this.selectedRule.title; this.rules.push(this.selectedRule); this.newRule = null; + this.isCreationMode = false; } else { this.actionNameError = 'You already have an action with this name.'; } @@ -309,6 +340,8 @@ export class DbTableActionsComponent implements OnInit { addRule() { this.submitting = true; + if (this.selectedRuleTitle) this.selectedRule.title = this.selectedRuleTitle; + this.newRule = null; this.selectedRule.events = this.selectedRule.events.filter((event) => event.event !== null); this.selectedRule.events = this.selectedRule.events.map((event) => { if (event.event === 'CUSTOM') { @@ -329,6 +362,7 @@ export class DbTableActionsComponent implements OnInit { this.rules = undatedRulesData.action_rules; const currentRule = this.rules.find((rule: Rule) => rule.id === res.id); this.setSelectedRule(currentRule); + this.isSaved = true; } catch (error) { if (error instanceof HttpErrorResponse) { console.log(error.error.message); @@ -361,6 +395,7 @@ export class DbTableActionsComponent implements OnInit { this.rules = undatedRulesData.action_rules; const currentRule = this.rules.find((rule: Rule) => rule.id === res.id); this.setSelectedRule(currentRule); + this.isSaved = true; } catch (error) { if (error instanceof HttpErrorResponse) { console.log(error.error.message); @@ -412,6 +447,44 @@ export class DbTableActionsComponent implements OnInit { } } + toggleTriggerTile(eventType: EventType) { + this.isSaved = false; + const idx = this.selectedEvents.indexOf(eventType); + if (idx > -1) { + // Remove trigger + this.selectedRule.events = this.selectedRule.events.filter((e) => e.event !== eventType); + this.selectedEvents = this.selectedEvents.filter((e) => e !== eventType); + if (eventType === EventType.Custom) { + this.selectedRuleCustomEvent = null; + } + } else { + // Add trigger + this.selectedRule.events = this.selectedRule.events.filter((e) => e.event !== null); + this.selectedRule.events.push({ event: eventType }); + this.selectedEvents.push(eventType); + if (eventType === EventType.Custom) { + this.selectedRuleCustomEvent = { + event: EventType.Custom, + title: '', + type: CustomActionType.Single, + icon: '', + require_confirmation: false, + }; + } + } + // Keep trailing null for the old form + if (this.selectedRule.events[this.selectedRule.events.length - 1]?.event !== null) { + this.selectedRule.events.push({ event: null }); + } + } + + selectActionMethod(method: string) { + this.isSaved = false; + if (this.selectedRule.table_actions.length) { + this.selectedRule.table_actions[0].method = method as CustomActionMethod; + } + } + removeEvent(event: any) { this.selectedRule.events = this.selectedRule.events.filter((e) => e.event !== event); this.selectedEvents = this.selectedRule.events.map((event) => event.event); From 0e862c5533e60bd9ca5b5050d6fc4790323737bf Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Mon, 9 Mar 2026 17:52:31 +0200 Subject: [PATCH 02/16] Polish automations UI: fix footer, improve theme styling, and fix trigger/action bugs - Match footer pattern with widgets (routerLink Back, proper shadow/padding per theme) - Improve dark theme: lighter action pill borders/text, lighter hover states, muted trigger colors - Improve light theme: muted trigger colors when inactive, darker affects-tab text - Fix Single/Multiple row buttons not clickable (use setCustomEventType method) - Fix action card staying visible when all triggers deselected - Unify icon-picker: show "Add icon"/"Change icon" with dashed border - Align icon-picker and checkbox vertically with input fields - Style WHEN/THEN badges: larger text, thinner/lighter background Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions.component.css | 151 +++++++++++++----- .../db-table-actions.component.html | 60 ++++--- .../db-table-actions.component.ts | 7 + .../icon-picker/icon-picker.component.html | 18 +-- 4 files changed, 157 insertions(+), 79 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 08c807dd3..8d4994e87 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -25,6 +25,16 @@ margin: 0; } +.custom-event-inline app-icon-picker ::ng-deep .icon-picker-button { + border: 1.5px dashed #8888a0; +} + +@media (prefers-color-scheme: light) { + .custom-event-inline app-icon-picker ::ng-deep .icon-picker-button { + border-color: #b0b0c0; + } +} + .no-actions { display: flex; flex-direction: column; @@ -347,14 +357,48 @@ max-width: 900px; } +.creation-flow__name-row { + display: flex; + align-items: center; + gap: 8px; +} + +.creation-flow__name-row > button { + margin-left: auto; + margin-top: -22px; +} + .creation-flow__name { width: 50%; } -.creation-flow__actions { - margin-top: auto; +.actions { + position: fixed; + left: 0; + bottom: 0; display: flex; + align-items: center; justify-content: space-between; + background-color: var(--background-color); + box-shadow: var(--shadow); + height: 64px; + padding: 0 calc(5% + 70px) 0 5%; + width: 100vw; + z-index: 10; +} + +@media (prefers-color-scheme: dark) { + .actions { + --shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.5), 0 2px 2px 0 rgba(0, 0, 0, 0.64), 0 1px 5px 0 rgba(0, 0, 0, 0.85); + --background-color: var(--surface-dark-color); + } +} + +@media (prefers-color-scheme: light) { + .actions { + --shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + --background-color: #fff; + } } /* ── Step badges ── */ @@ -363,33 +407,33 @@ display: inline-flex; align-items: center; justify-content: center; - font-size: 0.65em; + font-size: 0.75em; font-weight: 700; letter-spacing: 0.05em; - padding: 3px 8px; + padding: 2px 7px; border-radius: 4px; margin-right: 8px; vertical-align: middle; } .step-label__badge--when { - background-color: rgba(156, 39, 176, 0.2); - color: #ce93d8; + background-color: rgba(156, 39, 176, 0.12); + color: #d1a3db; } .step-label__badge--then { - background-color: rgba(33, 150, 243, 0.2); - color: #64b5f6; + background-color: rgba(33, 150, 243, 0.12); + color: #82c4f8; } @media (prefers-color-scheme: light) { .step-label__badge--when { - background-color: rgba(123, 31, 162, 0.12); + background-color: rgba(123, 31, 162, 0.08); color: #7b1fa2; } .step-label__badge--then { - background-color: rgba(21, 101, 192, 0.12); + background-color: rgba(21, 101, 192, 0.08); color: #1565c0; } } @@ -474,11 +518,17 @@ height: 15px; } -/* Default colored text & icons per type */ -.trigger-pill--add-row { color: #4ade80; } -.trigger-pill--update-row { color: #38bdf8; } -.trigger-pill--delete-row { color: #f87171; } -.trigger-pill--custom { color: #c084fc; } +/* Default colored text & icons per type (muted when not selected) */ +.trigger-pill--add-row { color: #2d8a54; } +.trigger-pill--update-row { color: #2a7faa; } +.trigger-pill--delete-row { color: #a85656; } +.trigger-pill--custom { color: #8660b0; } + +/* Full saturation when active */ +.trigger-pill--add-row.trigger-pill--active { color: #4ade80; } +.trigger-pill--update-row.trigger-pill--active { color: #38bdf8; } +.trigger-pill--delete-row.trigger-pill--active { color: #f87171; } +.trigger-pill--custom.trigger-pill--active { color: #c084fc; } .trigger-pill:hover { border-color: #3a3a50; @@ -517,10 +567,15 @@ border-color: #e2e8f0; } - .trigger-pill--add-row { color: #16a34a; } - .trigger-pill--update-row { color: #0284c7; } - .trigger-pill--delete-row { color: #dc2626; } - .trigger-pill--custom { color: #9333ea; } + .trigger-pill--add-row { color: #6aab7d; } + .trigger-pill--update-row { color: #6a9fbf; } + .trigger-pill--delete-row { color: #c07070; } + .trigger-pill--custom { color: #9878bf; } + + .trigger-pill--add-row.trigger-pill--active { color: #16a34a; } + .trigger-pill--update-row.trigger-pill--active { color: #0284c7; } + .trigger-pill--delete-row.trigger-pill--active { color: #dc2626; } + .trigger-pill--custom.trigger-pill--active { color: #9333ea; } .trigger-pill:hover { border-color: #cbd5e1; @@ -563,6 +618,11 @@ border-top: 1px solid rgba(0, 0, 0, 0.08); } +.custom-event-inline app-icon-picker, +.custom-event-inline mat-checkbox { + margin-bottom: 22px; +} + @media (prefers-color-scheme: dark) { .custom-event-inline { border-top-color: rgba(255, 255, 255, 0.08); @@ -576,6 +636,9 @@ flex-direction: column; gap: 8px; width: 100%; + position: relative; + z-index: 1; + margin-top: -8px; } .affects-row__label { @@ -596,11 +659,11 @@ } .affects-tab { - padding: 6px 16px; + padding: 8px 16px; border-radius: 4px; - border: 1.5px solid #1e1e24; - background: #0d0d0f; - color: #3f3f50; + border: 1.5px solid #3a3a4a; + background: transparent; + color: #8888a0; font-size: 0.85em; font-weight: 500; cursor: pointer; @@ -608,26 +671,34 @@ } .affects-tab:hover { - border-color: #2e2e38; - color: #6a6a80; -} - -.affects-tab--active { - border-color: var(--color-accentedPalette-500); - background: rgba(var(--color-accentedPalette-500-rgb, 103, 58, 183), 0.12); - color: var(--color-accentedPalette-500); + border-color: #50506a; + color: #a0a0b8; } @media (prefers-color-scheme: light) { .affects-tab { - background: #f5f5f7; - border-color: #e0e0e4; - color: #9090a0; + background: transparent; + border-color: #c8c8d0; + color: #6a6a7a; } .affects-tab:hover { - border-color: #c0c0c8; - color: #606070; + border-color: #a0a0b0; + color: #505060; + } +} + +.affects-tab--active { + border-color: #1565c0; + background: rgba(21, 101, 192, 0.15); + color: #42a5f5; +} + +@media (prefers-color-scheme: light) { + .affects-tab--active { + border-color: #1565c0; + background: rgba(21, 101, 192, 0.1); + color: #1565c0; } } @@ -646,9 +717,9 @@ gap: 6px; padding: 8px 16px; border-radius: 4px; - border: 1.5px solid #1e1e24; + border: 1.5px solid #3a3a4a; background: transparent; - color: #3f3f50; + color: #8888a0; font-size: 0.9em; font-weight: 500; cursor: pointer; @@ -662,8 +733,8 @@ } .action-method-pill:hover { - border-color: #2e2e38; - color: #6a6a80; + border-color: #50506a; + color: #a0a0b8; } @media (prefers-color-scheme: light) { diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index ee260feef..11ca20d50 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -46,16 +46,22 @@

Automations

- - Name - - +
+ + Name + + + +
WHEN - trigger happens + Trigger happens
@@ -110,12 +116,12 @@

Automations

@@ -125,12 +131,14 @@

Automations

-
+
THEN - action + Action - + @if (!hasTriggersSelected) { + Add a trigger first + } @else {
-
- +
+ + Back +
@@ -302,7 +310,7 @@

Automations

THEN - action + Action @if (!hasTriggersSelected) { Add a trigger first @@ -331,7 +339,7 @@

Automations

Webhook URL -

Requests are signed with HMAC-SHA256. Use the code snippets below to verify.

+
@@ -380,11 +388,11 @@

Automations

}
-
- +
+ + Back + + - - -
From 57af53e405df146437146c8ae2f6f8ef4596c224 Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Mon, 9 Mar 2026 18:07:02 +0200 Subject: [PATCH 03/16] Improve Save button UX: validate fields inline instead of disabling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Save button always active (disabled only when submitting or already saved) - On click, validates top-to-bottom: name → triggers → action fields - Focuses empty input or opens empty select on validation failure - Highlights trigger card with pulse animation when no triggers selected - Remove required attributes to avoid red error styling on focus Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions.component.css | 16 ++++++++ .../db-table-actions.component.html | 20 +++++----- .../db-table-actions.component.ts | 39 +++++++++++++++++++ 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 8d4994e87..ceda8e225 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -458,6 +458,22 @@ pointer-events: none; } +.creation-card--highlight { + animation: card-pulse 1.5s ease; +} + +@keyframes card-pulse { + 0%, 100% { border-color: rgba(0, 0, 0, 0.12); } + 25%, 75% { border-color: var(--color-accentedPalette-500); } +} + +@media (prefers-color-scheme: dark) { + @keyframes card-pulse { + 0%, 100% { border-color: rgba(255, 255, 255, 0.12); } + 25%, 75% { border-color: var(--color-accentedPalette-500); } + } +} + .creation-card__label { font-weight: 500; display: block; diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 11ca20d50..5be16b2d3 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -49,7 +49,7 @@

Automations

Name - +
@@ -230,7 +230,7 @@

Automations

Automation name - + @@ -274,7 +274,7 @@

Automations

Button label - + Automations @if ($any(selectedRule.table_actions[0]).method === 'URL') { Webhook URL - + @@ -381,7 +381,7 @@

Automations

@if ($any(selectedRule.table_actions[0]).method === 'SLACK') { Slack webhook URL - + }
@@ -394,7 +394,7 @@

Automations

diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts index c3bd5358e..118a7a035 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts @@ -104,6 +104,7 @@ export class DbTableActionsComponent implements OnInit { ]; @ViewChild('newActionInput') newActionInput: ElementRef; + @ViewChild('ruleNameInput') ruleNameInput: ElementRef; public signingKey: string; @@ -196,6 +197,12 @@ export class DbTableActionsComponent implements OnInit { return this.selectedRule?.events?.some((e) => e.event !== null) ?? false; } + get saveDisabledReason(): string { + if (!this.selectedRuleTitle) return 'Enter automation name'; + if (!this.hasTriggersSelected) return 'Select at least one trigger'; + return ''; + } + get activeTriggers() { return this.selectedRule?.events?.filter((e) => e.event !== null) ?? []; } @@ -336,6 +343,38 @@ export class DbTableActionsComponent implements OnInit { } handleRuleSubmitting() { + if (!this.selectedRuleTitle) { + this.ruleNameInput?.nativeElement?.focus(); + return; + } + + if (!this.hasTriggersSelected) { + const triggerCard = document.querySelector('.creation-card') as HTMLElement; + if (triggerCard) { + triggerCard.scrollIntoView({ behavior: 'smooth', block: 'center' }); + triggerCard.classList.add('creation-card--highlight'); + setTimeout(() => triggerCard.classList.remove('creation-card--highlight'), 1500); + } + return; + } + + const action = this.selectedRule.table_actions[0]; + if (action) { + const method = (action.method as string).toUpperCase(); + if (method === 'URL' && !action.url) { + (document.querySelector('input[name="action-url"]') as HTMLInputElement)?.focus(); + return; + } + if (method === 'EMAIL' && (!action.emails || action.emails.length === 0)) { + (document.querySelector('mat-select[name="notification-emails"]') as HTMLElement)?.click(); + return; + } + if (method === 'SLACK' && !(action as any).slack_url) { + (document.querySelector('input[name="action-slack-url"]') as HTMLInputElement)?.focus(); + return; + } + } + if (this.selectedRule.events.filter((event) => event.event !== null).length > 0) { if (this.selectedRule.id) { this.updateRule(); From d831946d0c2f86cffd3d7b9495dbafa1eafd7d8f Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Mon, 9 Mar 2026 18:13:02 +0200 Subject: [PATCH 04/16] Replace sidebar add button with dashed "Add automation" and show new rule in list - Remove icon-button from sidebar header - Add dashed "Add automation" button below saved rules list - Show "New automation" placeholder in sidebar when creating - Sync name input with sidebar title in real-time - Clean up unsaved rule from list on Back/undo Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions.component.css | 15 ++++++++ .../db-table-actions.component.html | 36 +++++++------------ .../db-table-actions.component.ts | 6 +++- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index ceda8e225..1bcf55808 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -25,6 +25,21 @@ margin: 0; } +.add-automation-button { + width: calc(100% - 24px); + margin: 8px 12px; + border: 1.5px dashed #8888a0 !important; + border-radius: 4px; + color: #8888a0; +} + +@media (prefers-color-scheme: light) { + .add-automation-button { + border-color: #b0b0c0 !important; + color: #8090a0; + } +} + .custom-event-inline app-icon-picker ::ng-deep .icon-picker-button { border: 1.5px dashed #8888a0; } diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 5be16b2d3..4736a8497 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -2,19 +2,11 @@

Automations

- -
-
+
No added automations
- + - - - {{actionNameError}} - - + @@ -230,7 +217,8 @@

Automations

Automation name - + diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts index 118a7a035..16c9acacc 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts @@ -289,9 +289,9 @@ export class DbTableActionsComponent implements OnInit { ], }; + this.rules.push(this.newRule); this.setSelectedRule(this.newRule); this.isCreationMode = true; - setTimeout(() => this.newActionInput?.nativeElement?.focus()); } addNewAction() { @@ -321,7 +321,11 @@ export class DbTableActionsComponent implements OnInit { } undoRule() { + if (this.newRule) { + this.rules = this.rules.filter((r) => r !== this.newRule); + } this.newRule = null; + this.isCreationMode = false; if (this.rules.length) this.setSelectedRule(this.rules[0]); } From 6c822325362921b950ac0132352b8c600d978504 Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Tue, 10 Mar 2026 14:25:41 +0200 Subject: [PATCH 05/16] Add connector line with arrow between trigger and action cards, move WHEN/THEN badges inside cards Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions.component.css | 52 ++++++++++++++++--- .../db-table-actions.component.html | 24 +++------ 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 1bcf55808..a41f77565 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -369,18 +369,58 @@ display: flex; flex-direction: column; gap: 24px; +} + +.creation-flow__form .creation-card { + max-width: 900px; +} + +/* ── Card connector (line + arrow) ── */ + +.card-connector { + display: flex; + flex-direction: column; + align-items: center; + height: 28px; + margin: -14px 0; max-width: 900px; } +.card-connector::before { + content: ''; + flex: 1; + border-left: 1.5px dashed #8888a0; +} + +.card-connector::after { + content: ''; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 6px solid #8888a0; +} + +@media (prefers-color-scheme: light) { + .card-connector::before { + border-left-color: #b0b0c0; + } + + .card-connector::after { + border-top-color: #b0b0c0; + } +} + .creation-flow__name-row { display: flex; align-items: center; gap: 8px; + max-width: 900px; } .creation-flow__name-row > button { margin-left: auto; - margin-top: -22px; + margin-bottom: 22px; } .creation-flow__name { @@ -428,27 +468,26 @@ padding: 2px 7px; border-radius: 4px; margin-right: 8px; - vertical-align: middle; } .step-label__badge--when { - background-color: rgba(156, 39, 176, 0.12); + background-color: #2a1530; color: #d1a3db; } .step-label__badge--then { - background-color: rgba(33, 150, 243, 0.12); + background-color: #0d1a2e; color: #82c4f8; } @media (prefers-color-scheme: light) { .step-label__badge--when { - background-color: rgba(123, 31, 162, 0.08); + background-color: #f3e5f5; color: #7b1fa2; } .step-label__badge--then { - background-color: rgba(21, 101, 192, 0.08); + background-color: #e3f2fd; color: #1565c0; } } @@ -456,6 +495,7 @@ /* ── Cards ── */ .creation-card { + position: relative; border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 8px; padding: 20px 24px; diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 4736a8497..8bf699cf9 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -46,10 +46,7 @@

Automations

- - WHEN - Trigger happens - + WHEN Trigger
+
+
- - THEN - Action - + THEN Action @if (!hasTriggersSelected) { Add a trigger first } @else { @@ -223,10 +219,7 @@

Automations

- - WHEN - Trigger happens - + WHEN Trigger
+
+
- - THEN - Action - + THEN Action @if (!hasTriggersSelected) { Add a trigger first } @else { From e0c9633d9a772eb46bd2d8ac9ab1bc9945f9977b Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Tue, 10 Mar 2026 14:32:38 +0200 Subject: [PATCH 06/16] Add dot on trigger card bottom border for connector flow Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions.component.css | 19 +++++++++++++++++++ .../db-table-actions.component.html | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index a41f77565..226bd2bff 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -377,6 +377,25 @@ /* ── Card connector (line + arrow) ── */ +.creation-card--trigger::after { + content: ''; + position: absolute; + bottom: -4px; + left: 50%; + transform: translateX(-50%); + width: 7px; + height: 7px; + border-radius: 50%; + background-color: #8888a0; + z-index: 1; +} + +@media (prefers-color-scheme: light) { + .creation-card--trigger::after { + background-color: #b0b0c0; + } +} + .card-connector { display: flex; flex-direction: column; diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 8bf699cf9..a8621e9f3 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -45,7 +45,7 @@

Automations

-
+
WHEN Trigger
@@ -218,7 +218,7 @@

Automations

-
+
WHEN Trigger
From 8496cdb3f20f869d2b7db67715e5c029122803d0 Mon Sep 17 00:00:00 2001 From: Karina Kharchenko Date: Tue, 10 Mar 2026 14:53:31 +0200 Subject: [PATCH 07/16] Lighten WHEN/THEN badge backgrounds in dark theme Co-Authored-By: Claude Opus 4.6 --- .../db-table-actions/db-table-actions.component.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 226bd2bff..462447e83 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -490,12 +490,12 @@ } .step-label__badge--when { - background-color: #2a1530; + background-color: #3d2248; color: #d1a3db; } .step-label__badge--then { - background-color: #0d1a2e; + background-color: #1a2d4a; color: #82c4f8; } From c06822368aba10841ce708ecf0b967c54a2ee926 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Wed, 11 Mar 2026 13:29:51 +0000 Subject: [PATCH 08/16] create global variables for red, orange, blue and green colors --- .../ui-components/alert/alert.component.css | 29 +++++-------------- .../ui-components/banner/banner.component.css | 20 +++++-------- frontend/src/custom-theme.scss | 15 ++++++++++ 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/frontend/src/app/components/ui-components/alert/alert.component.css b/frontend/src/app/components/ui-components/alert/alert.component.css index d9262e252..7fb7d8b48 100644 --- a/frontend/src/app/components/ui-components/alert/alert.component.css +++ b/frontend/src/app/components/ui-components/alert/alert.component.css @@ -21,10 +21,6 @@ @media (prefers-color-scheme: dark) { .alert { - border-top: 1px solid var(--alert-dark-theme-color); - border-right: 1px solid var(--alert-dark-theme-color); - border-bottom: 1px solid var(--alert-dark-theme-color); - border-left: 12px solid var(--alert-dark-theme-color); backdrop-filter: blur(2px); } } @@ -37,27 +33,23 @@ } .alert_error { - --alert-theme-color: #b71c1c; - --alert-dark-theme-color: #e53935; - --bg-color: color-mix(in hsl, #b71c1c, transparent 95%); + --alert-theme-color: var(--error-color); + --bg-color: var(--error-background-color); } .alert_warning { - --alert-theme-color: #f79008; - --alert-dark-theme-color: #f79008; - --bg-color: color-mix(in hsl, #f79008, transparent 95%); + --alert-theme-color: var(--warning-color); + --bg-color: var(--warning-background-color); } .alert_info { - --alert-theme-color: #296ee9; - --alert-dark-theme-color: #296ee9; - --bg-color: color-mix(in hsl, #296ee9, transparent 95%); + --alert-theme-color: var(--info-color); + --bg-color: var(--info-background-color); } .alert_success { - --alert-theme-color: #1b5e20; - --alert-dark-theme-color: #4caf50; - --bg-color: color-mix(in hsl, #1b5e20, transparent 95%); + --alert-theme-color: var(--success-color); + --bg-color: var(--success-background-color); } .alert__icon { @@ -73,11 +65,6 @@ width: 36px; } -@media (prefers-color-scheme: dark) { - .alert__icon { - color: var(--alert-dark-theme-color); - } -} .alert__message { flex: 1; diff --git a/frontend/src/app/components/ui-components/banner/banner.component.css b/frontend/src/app/components/ui-components/banner/banner.component.css index bc86bce07..d84ff3d65 100644 --- a/frontend/src/app/components/ui-components/banner/banner.component.css +++ b/frontend/src/app/components/ui-components/banner/banner.component.css @@ -29,27 +29,23 @@ } .banner_error { - --alert-theme-color: #b71c1c; - --alert-dark-theme-color: #e53935; - --bg-color: color-mix(in hsl, #b71c1c, transparent 95%); + --alert-theme-color: var(--error-color); + --bg-color: var(--error-background-color); } .banner_warning { - --alert-theme-color: #f79008; - --alert-dark-theme-color: #f79008; - --bg-color: color-mix(in hsl, #f79008, transparent 95%); + --alert-theme-color: var(--warning-color); + --bg-color: var(--warning-background-color); } .banner_info { - --alert-theme-color: #296ee9; - --alert-dark-theme-color: #296ee9; - --bg-color: color-mix(in hsl, #296ee9, transparent 95%); + --alert-theme-color: var(--info-color); + --bg-color: var(--info-background-color); } .banner_success { - --alert-theme-color: #1b5e20; - --alert-dark-theme-color: #4caf50; - --bg-color: color-mix(in hsl, #1b5e20, transparent 95%); + --alert-theme-color: var(--success-color); + --bg-color: var(--success-background-color); } .banner-box { diff --git a/frontend/src/custom-theme.scss b/frontend/src/custom-theme.scss index 4687ad29f..abb5bc346 100644 --- a/frontend/src/custom-theme.scss +++ b/frontend/src/custom-theme.scss @@ -27,6 +27,16 @@ html { --surface-dark-color: #202020 !important; --mat-toolbar-container-background-color: var(--surface-dark-color) !important; + + --error-color: var(--color-warnPalette-500); + --warning-color: #f79008; + --info-color: #296ee9; + --success-color: #1b5e20; + + --error-background-color: color-mix(in hsl, var(--error-color), transparent 95%); + --warning-background-color: color-mix(in hsl, var(--warning-color), transparent 95%); + --info-background-color: color-mix(in hsl, var(--info-color), transparent 95%); + --success-background-color: color-mix(in hsl, var(--success-color), transparent 95%); } @media (prefers-color-scheme: dark) { @@ -35,6 +45,11 @@ html { --mat-table-background-color: var(--surface-dark-color) !important; --mat-paginator-container-background-color: var(--surface-dark-color) !important; --mat-snack-bar-button-color: var(--color-accentedPalette-500) !important; + + --error-color: var(--color-warnDarkPalette-500); + --warning-color: #f79008; + --info-color: #296ee9; + --success-color: #4caf50; } .mat-datepicker-content { From 65fa16eb59a4721e272501d2d180ac95662f6136 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Wed, 11 Mar 2026 14:00:03 +0000 Subject: [PATCH 09/16] Automations: apply error, info and success colors to trigger options --- .../db-table-actions.component.css | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 462447e83..40496e1bb 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -609,15 +609,15 @@ } /* Default colored text & icons per type (muted when not selected) */ -.trigger-pill--add-row { color: #2d8a54; } -.trigger-pill--update-row { color: #2a7faa; } -.trigger-pill--delete-row { color: #a85656; } +.trigger-pill--add-row { color: color-mix(in srgb, var(--success-color), transparent 40%); } +.trigger-pill--update-row { color: color-mix(in srgb, var(--info-color), transparent 40%); } +.trigger-pill--delete-row { color: color-mix(in srgb, var(--error-color), transparent 40%); } .trigger-pill--custom { color: #8660b0; } /* Full saturation when active */ -.trigger-pill--add-row.trigger-pill--active { color: #4ade80; } -.trigger-pill--update-row.trigger-pill--active { color: #38bdf8; } -.trigger-pill--delete-row.trigger-pill--active { color: #f87171; } +.trigger-pill--add-row.trigger-pill--active { color: var(--success-color); } +.trigger-pill--update-row.trigger-pill--active { color: var(--info-color); } +.trigger-pill--delete-row.trigger-pill--active { color: var(--error-color); } .trigger-pill--custom.trigger-pill--active { color: #c084fc; } .trigger-pill:hover { @@ -627,21 +627,21 @@ /* Active states */ .trigger-pill--add-row.trigger-pill--active { - border-color: #4ade80; - background: #0a1f14; - box-shadow: 0 0 0 1px rgba(74, 222, 128, 0.25), 0 0 12px rgba(74, 222, 128, 0.08); + border-color: var(--success-color); + background: color-mix(in srgb, var(--success-color), transparent 90%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--success-color), transparent 75%), 0 0 12px color-mix(in srgb, var(--success-color), transparent 92%); } .trigger-pill--update-row.trigger-pill--active { - border-color: #38bdf8; - background: #071428; - box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.25), 0 0 12px rgba(56, 189, 248, 0.08); + border-color: var(--info-color); + background: color-mix(in srgb, var(--info-color), transparent 90%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--info-color), transparent 75%), 0 0 12px color-mix(in srgb, var(--info-color), transparent 92%); } .trigger-pill--delete-row.trigger-pill--active { - border-color: #f87171; - background: #1a0808; - box-shadow: 0 0 0 1px rgba(248, 113, 113, 0.25), 0 0 12px rgba(248, 113, 113, 0.08); + border-color: var(--error-color); + background: color-mix(in srgb, var(--error-color), transparent 90%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--error-color), transparent 75%), 0 0 12px color-mix(in srgb, var(--error-color), transparent 92%); } .trigger-pill--custom.trigger-pill--active { @@ -657,14 +657,14 @@ border-color: #e2e8f0; } - .trigger-pill--add-row { color: #6aab7d; } - .trigger-pill--update-row { color: #6a9fbf; } - .trigger-pill--delete-row { color: #c07070; } + .trigger-pill--add-row { color: color-mix(in srgb, var(--success-color), transparent 35%); } + .trigger-pill--update-row { color: color-mix(in srgb, var(--info-color), transparent 35%); } + .trigger-pill--delete-row { color: color-mix(in srgb, var(--error-color), transparent 35%); } .trigger-pill--custom { color: #9878bf; } - .trigger-pill--add-row.trigger-pill--active { color: #16a34a; } - .trigger-pill--update-row.trigger-pill--active { color: #0284c7; } - .trigger-pill--delete-row.trigger-pill--active { color: #dc2626; } + .trigger-pill--add-row.trigger-pill--active { color: var(--success-color); } + .trigger-pill--update-row.trigger-pill--active { color: var(--info-color); } + .trigger-pill--delete-row.trigger-pill--active { color: var(--error-color); } .trigger-pill--custom.trigger-pill--active { color: #9333ea; } .trigger-pill:hover { @@ -673,21 +673,21 @@ } .trigger-pill--add-row.trigger-pill--active { - border-color: #16a34a; - background: #f0fdf4; - box-shadow: 0 0 0 1px rgba(22, 163, 74, 0.25); + border-color: var(--success-color); + background: color-mix(in srgb, var(--success-color), transparent 92%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--success-color), transparent 75%); } .trigger-pill--update-row.trigger-pill--active { - border-color: #0284c7; - background: #f0f9ff; - box-shadow: 0 0 0 1px rgba(2, 132, 199, 0.25); + border-color: var(--info-color); + background: color-mix(in srgb, var(--info-color), transparent 92%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--info-color), transparent 75%); } .trigger-pill--delete-row.trigger-pill--active { - border-color: #dc2626; - background: #fef2f2; - box-shadow: 0 0 0 1px rgba(220, 38, 38, 0.25); + border-color: var(--error-color); + background: color-mix(in srgb, var(--error-color), transparent 92%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--error-color), transparent 75%); } .trigger-pill--custom.trigger-pill--active { From 69aa98da7d51da5ca2dfac2832c08ee47d9296b5 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Wed, 11 Mar 2026 14:10:36 +0000 Subject: [PATCH 10/16] Automations: refactor triggers with checkboxes elements --- .../db-table-actions.component.css | 6 ++ .../db-table-actions.component.html | 72 ++++++++++--------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 40496e1bb..eb7c883f9 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -602,6 +602,12 @@ transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s; } +.trigger-pill__checkbox { + position: absolute; + opacity: 0; + pointer-events: none; +} + .trigger-pill__icon { font-size: 15px; width: 15px; diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index a8621e9f3..30bf909f5 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -49,33 +49,37 @@

Automations

WHEN Trigger
- + or - + or - + or - +
@if (selectedRuleCustomEvent) { @@ -222,33 +226,37 @@

Automations

WHEN Trigger
- + or - + or - + or - +
@if (selectedRuleCustomEvent) { From b0b2c053be751a8389415e54bd59f0f3da6a96f4 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Wed, 11 Mar 2026 14:16:37 +0000 Subject: [PATCH 11/16] Automation: remove dashed-border buttons and use standard outlined --- .../db-table-actions.component.css | 25 +++---------------- .../db-table-actions.component.html | 2 +- .../icon-picker/icon-picker.component.html | 2 +- 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index eb7c883f9..558ef1a26 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -28,41 +28,22 @@ .add-automation-button { width: calc(100% - 24px); margin: 8px 12px; - border: 1.5px dashed #8888a0 !important; - border-radius: 4px; - color: #8888a0; -} - -@media (prefers-color-scheme: light) { - .add-automation-button { - border-color: #b0b0c0 !important; - color: #8090a0; - } } -.custom-event-inline app-icon-picker ::ng-deep .icon-picker-button { - border: 1.5px dashed #8888a0; -} - -@media (prefers-color-scheme: light) { - .custom-event-inline app-icon-picker ::ng-deep .icon-picker-button { - border-color: #b0b0c0; - } -} .no-actions { display: flex; flex-direction: column; align-items: center; gap: 12px; - color: rgba(0, 0, 0, 0.5); + color: rgba(0, 0, 0, 0.64); padding: 1rem 0; text-align: center; } @media (prefers-color-scheme: dark) { .no-actions { - color: rgba(255, 255, 255, 0.5); + color: rgba(255, 255, 255, 0.64); } } @@ -115,7 +96,7 @@ position: absolute; top: 44px; left: 0; - color: #e53935; + color: var(--color-error); font-size: 0.75em; width: 100%; } diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 30bf909f5..90d403ba5 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -17,7 +17,7 @@

Automations

{{ rule.title || 'New automation' }} - - -
+ + Single row + Multiple rows +
} @@ -126,23 +120,20 @@

Automations

@if (!hasTriggersSelected) { Add a trigger first } @else { -
- - - -
+ + + link URL webhook + + + email Email + + + tag Slack + +
@if ($any(selectedRule.table_actions[0]).method === 'URL') { @@ -278,18 +269,12 @@

Automations

Affects -
- - -
+ + Single row + Multiple rows +
} @@ -303,23 +288,20 @@

Automations

@if (!hasTriggersSelected) { Add a trigger first } @else { -
- - - -
+ + + link URL webhook + + + email Email + + + tag Slack + +
@if ($any(selectedRule.table_actions[0]).method === 'URL') { From f552c641e14b5a15f6fd850ea1656d87795d84e6 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Thu, 12 Mar 2026 11:07:48 +0000 Subject: [PATCH 13/16] Automation: fix layout --- .../db-table-actions.component.css | 74 ++++++++++++++++--- .../db-table-actions.component.html | 12 +-- .../db-table-actions.component.ts | 2 - 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index a01b6add0..61ecc1ec9 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -1,3 +1,12 @@ +:host { + display: block; + height: calc(100vh - 44px); + margin-bottom: -60px; + overflow: hidden; + position: relative; + z-index: 1; +} + :host app-alert:not(:empty) { --alert-margin: 0; @@ -5,13 +14,17 @@ margin-bottom: 16px; } -.drawer { +.actions-layout { + display: flex; height: 100%; } -.mat-drawer { - padding-bottom: 16px; +.actions-sidebar { width: clamp(200px, 18%, 320px); + padding-bottom: 16px; + border-right: 1px solid var(--mat-sidenav-container-divider-color); + overflow-y: auto; + flex-shrink: 0; } .drawer-header { @@ -101,10 +114,38 @@ width: 100%; } -.mat-drawer-content { +.actions-main { + flex: 1; + overflow-y: auto; display: flex; flex-direction: column; - padding: 20px 24px; + background-color: var(--mat-sidenav-content-background-color); +} + +.actions-main > app-alert, +.actions-main > app-breadcrumbs, +.actions-main > app-content-loader, +.actions-main > .creation-flow, +.actions-main > .empty-state { + padding-left: clamp(40px, 5vw, 100px); + padding-right: clamp(40px, 5vw, 100px); +} + +.actions-main > app-alert, +.actions-main > app-breadcrumbs, +.actions-main > app-content-loader { + padding-top: 20px; +} + +@media (width <= 600px) { + .actions-main > app-alert, + .actions-main > app-breadcrumbs, + .actions-main > app-content-loader, + .actions-main > .creation-flow, + .actions-main > .empty-state { + padding-left: 16px; + padding-right: 16px; + } } .rule { @@ -343,8 +384,11 @@ /* ── Creation flow ── */ .creation-flow { - flex-grow: 1; + flex: 1; margin-top: 20px; + max-width: 1400px; + width: 100%; + box-sizing: border-box; } .creation-flow__form { @@ -413,17 +457,19 @@ } .actions { - position: fixed; - left: 0; + position: sticky; bottom: 0; display: flex; align-items: center; justify-content: space-between; + gap: 16px; + margin-left: calc(-1 * clamp(40px, 5vw, 100px)); + margin-right: calc(-1 * clamp(40px, 5vw, 100px)); + padding: 0 clamp(40px, 5vw, 100px); background-color: var(--background-color); box-shadow: var(--shadow); height: 64px; - padding: 0 calc(5% + 70px) 0 5%; - width: 100vw; + flex-shrink: 0; z-index: 10; } @@ -441,6 +487,14 @@ } } +@media (width <= 600px) { + .actions { + margin-left: -16px; + margin-right: -16px; + padding: 0 16px; + } +} + /* ── Step badges ── */ .step-label__badge { diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 44350744b..d50db73da 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -1,5 +1,5 @@ - - +
+

Automations

@@ -24,9 +24,9 @@

Automations

(click)="addNewRule(); posthog.capture('Actions: add first action is clicked')"> add Add automation - +
- +
@@ -432,5 +432,5 @@

Automations

- -
+
+
diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts index 16c9acacc..5f4ec10f7 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.ts @@ -13,7 +13,6 @@ import { MatListModule } from '@angular/material/list'; import { MatMenuModule } from '@angular/material/menu'; import { MatRadioModule } from '@angular/material/radio'; import { MatSelectModule } from '@angular/material/select'; -import { MatSidenavModule } from '@angular/material/sidenav'; import { MatTabsModule } from '@angular/material/tabs'; import { MatTooltipModule } from '@angular/material/tooltip'; import { Title } from '@angular/platform-browser'; @@ -53,7 +52,6 @@ import { ActionDeleteDialogComponent } from './action-delete-dialog/action-delet MatInputModule, MatSelectModule, MatTooltipModule, - MatSidenavModule, MatListModule, MatMenuModule, MatRadioModule, From 091af4dbfda321f848cebca61e69f69551579e03 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Thu, 12 Mar 2026 11:10:13 +0000 Subject: [PATCH 14/16] Automation: fix sticky footer --- .../db-table-actions/db-table-actions.component.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css index 61ecc1ec9..cd5227562 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.css @@ -395,6 +395,11 @@ display: flex; flex-direction: column; gap: 24px; + min-height: 100%; +} + +.creation-flow__form > .actions { + margin-top: auto; } .creation-flow__form .creation-card { From e7d6cd803aca79125bd5476213850a0a164f7322 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Thu, 12 Mar 2026 11:17:54 +0000 Subject: [PATCH 15/16] Automation: add Cancel button for unsubmitted automation --- .../db-table-actions.component.html | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index d50db73da..52469664b 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -206,11 +206,17 @@

Automations

@if (selectedRule && isCreationMode) {
- - Automation name - - +
+ + Automation name + + + +
From 3f3de4873bc30a0f85bb4d9c93d3cd47435ba1f4 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Thu, 12 Mar 2026 11:25:08 +0000 Subject: [PATCH 16/16] Automations: refactor layout --- .../db-table-actions.component.html | 201 ++---------------- 1 file changed, 17 insertions(+), 184 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html index 52469664b..0334530b5 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-actions/db-table-actions.component.html @@ -31,17 +31,25 @@

Automations

-
+
- Name - + Automation name + - + @if (isCreationMode) { + + } @else { + + }
@@ -86,7 +94,7 @@

Automations

Button label - + Automations tooltip="Choose an icon" (onFieldChange)="updateIcon($event)"> - Request confirmation @@ -203,181 +211,6 @@

Automations

- @if (selectedRule && isCreationMode) { -
-
-
- - Automation name - - - -
- - -
- WHEN Trigger - -
- - or - - or - - or - -
- - @if (selectedRuleCustomEvent) { -
- - Button label - - - - - - Request confirmation - -
- Affects - - Single row - Multiple rows - -
-
- } -
- -
- - -
- THEN Action - @if (!hasTriggersSelected) { - Add a trigger first - } @else { - - - link URL webhook - - - email Email - - - tag Slack - - - -
- @if ($any(selectedRule.table_actions[0]).method === 'URL') { - - Webhook URL - - - - -
- - - - - - - -
- } - - @if ($any(selectedRule.table_actions[0]).method === 'EMAIL') { - - Notification emails - - - {{companyMember.name}} | {{companyMember.email}} - - - - } - - @if ($any(selectedRule.table_actions[0]).method === 'SLACK') { - - Slack webhook URL - - - } -
- } -
- -
- - Back - - - -
-
-
- } -

Configure custom triggers and actions for database records