Audit v3#1584
Conversation
- Change date format from "P p" to "d MMM yyyy 'at' h:mm a" - Add green status badge for successful operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Material icons for actions (add, delete, create, visibility) - Rename Details column to Changes - Add new fields: IsAddAction, DateOnly, TimeOnly - Style icons with appropriate colors per action type Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show user name on top with normal font weight - Show email below in smaller secondary text - Look up user name from usersList by email Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created (was "added row") - Deleted (was "deleted row") - Edited (was "edit row") - Viewed (was "received row/rows") Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Material Icons Outlined for visibility icon Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add exportRows to LogOperationTypeEnum - Add audit logging to export CSV use case - Log export operations with success/failure status Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ProfileSidebarComponent with collapsible state - Extract Branding section into separate /branding route - Extract API Keys section into separate /api-keys route - Move SAML SSO to /saml route (from /sso/:company-id) - Add Pricing tab linking to /upgrade page - Update all profile pages to use sidebar layout - Reduce sidebar icon size and spacing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
There was a problem hiding this comment.
Pull request overview
This PR updates the “settings/profile” area of the frontend to use a new reusable profile sidebar layout, introduces dedicated pages for Branding and API Keys, refreshes the Audit log UI (“Audit v3”), and adds backend audit logging for CSV exports.
Changes:
- Add
ProfileSidebarComponentand refactor multiple pages (Company, Secrets, Upgrade, User Settings, Zapier, SAML) into a shared “profile-layout” structure. - Split features into new routes/pages:
/branding,/api-keys, and rename SSO route to/samlwith updated SSO UX and skeleton loader. - Enhance audit logging: UI improvements + add backend operation type
exportRowsand persist a log record during CSV export.
Reviewed changes
Copilot reviewed 50 out of 50 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/environments/environment.dev.ts | Switches dev build configuration to SaaS mode. |
| frontend/src/app/models/ui-settings.ts | Adds persisted UI flag for sidebar collapse state. |
| frontend/src/app/components/zapier/zapier.component.ts | Embeds Zapier page into new profile layout with sidebar + alerts. |
| frontend/src/app/components/zapier/zapier.component.spec.ts | Updates test imports for router usage with new child components. |
| frontend/src/app/components/zapier/zapier.component.html | Adds profile layout wrappers and sidebar. |
| frontend/src/app/components/zapier/zapier.component.css | Adds profile layout styling + updates Zapier page spacing. |
| frontend/src/app/components/user-settings/user-settings.component.ts | Removes API key logic from account settings; adds sidebar to layout. |
| frontend/src/app/components/user-settings/user-settings.component.html | Refactors into profile layout; removes API key section from this page. |
| frontend/src/app/components/user-settings/user-settings.component.css | Adds profile layout styling and adjusts page padding responsiveness. |
| frontend/src/app/components/upgrade/upgrade.component.ts | Adds sidebar import to upgrade page. |
| frontend/src/app/components/upgrade/upgrade.component.html | Wraps upgrade UI in profile layout with sidebar + alert. |
| frontend/src/app/components/upgrade/upgrade.component.css | Adds profile layout styling for upgrade page. |
| frontend/src/app/components/sso/sso.component.ts | Changes SSO page to fetch current company, add saved feedback, and set document title. |
| frontend/src/app/components/sso/sso.component.spec.ts | Updates tests to mock fetchCompany() flow and saved-state behavior. |
| frontend/src/app/components/sso/sso.component.html | Adds profile layout + alert + skeleton; refactors form and save button states. |
| frontend/src/app/components/sso/sso.component.css | Adds profile layout styling and updates SSO page spacing + description styling. |
| frontend/src/app/components/skeletons/placeholder-sso/placeholder-sso.component.ts | New skeleton component for SSO loading state. |
| frontend/src/app/components/skeletons/placeholder-sso/placeholder-sso.component.html | Skeleton markup for SSO page. |
| frontend/src/app/components/skeletons/placeholder-sso/placeholder-sso.component.css | Skeleton styling for SSO page. |
| frontend/src/app/components/skeletons/placeholder-company/placeholder-company.component.css | Adjusts placeholder company padding/max-width to match new layout spacing. |
| frontend/src/app/components/skeletons/placeholder-branding/placeholder-branding.component.ts | New skeleton component for Branding loading state. |
| frontend/src/app/components/skeletons/placeholder-branding/placeholder-branding.component.html | Skeleton markup for Branding page. |
| frontend/src/app/components/skeletons/placeholder-branding/placeholder-branding.component.css | Skeleton styling for Branding page. |
| frontend/src/app/components/skeletons/placeholder-api-keys-list/placeholder-api-keys-list.component.ts | New skeleton component for API keys list loading state. |
| frontend/src/app/components/skeletons/placeholder-api-keys-list/placeholder-api-keys-list.component.html | Skeleton markup for API keys list. |
| frontend/src/app/components/skeletons/placeholder-api-keys-list/placeholder-api-keys-list.component.css | Skeleton styling for API keys list. |
| frontend/src/app/components/secrets/secrets.component.ts | Adds sidebar import to secrets page. |
| frontend/src/app/components/secrets/secrets.component.spec.ts | Adds RouterModule to satisfy router usage with new sidebar layout. |
| frontend/src/app/components/secrets/secrets.component.html | Wraps secrets UI in profile layout with sidebar + alert. |
| frontend/src/app/components/secrets/secrets.component.css | Adds profile layout styling and updates secrets page spacing. |
| frontend/src/app/components/secrets/create-secret-dialog/create-secret-dialog.component.html | Restructures dialog markup to wrap content/actions in a form. |
| frontend/src/app/components/profile/profile-sidebar/profile-sidebar.component.ts | New reusable profile sidebar with persisted collapse state. |
| frontend/src/app/components/profile/profile-sidebar/profile-sidebar.component.html | Sidebar navigation links for account/company/pricing/branding/saml/api/secrets/zapier. |
| frontend/src/app/components/profile/profile-sidebar/profile-sidebar.component.css | Sidebar styling, collapsed behavior, and responsive/mobile behavior. |
| frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.ts | Updates inline widget config comments to reference “unique identifiers” for secrets. |
| frontend/src/app/components/company/company.component.ts | Imports sidebar component for new profile layout integration. |
| frontend/src/app/components/company/company.component.html | Wraps company page in profile layout; removes embedded SAML + Branding sections from this page. |
| frontend/src/app/components/company/company.component.css | Adds profile layout styling and updates company page spacing. |
| frontend/src/app/components/branding/branding.component.ts | New dedicated Branding page extracted from Company page functionality. |
| frontend/src/app/components/branding/branding.component.html | Branding UI (custom domain, logo/favicon, tab title, preview, DNS how-to) in profile layout. |
| frontend/src/app/components/branding/branding.component.css | Branding page layout and styling. |
| frontend/src/app/components/audit/audit.component.ts | Adds icons module and introduces getUserName() for enhanced audit display. |
| frontend/src/app/components/audit/audit.component.html | “Audit v3” table rendering: status badge, action icons, user display, date split, changes column label. |
| frontend/src/app/components/audit/audit.component.css | Adds row hover, spacing, and new cell/badge/icon styling. |
| frontend/src/app/components/audit/audit-data-source.ts | Formats dates, adds action labels/icons, and enriches row model for UI. |
| frontend/src/app/components/api-keys/api-keys.component.ts | New dedicated API Keys page extracted from User Settings. |
| frontend/src/app/components/api-keys/api-keys.component.html | API key generation + display + list management UI within profile layout. |
| frontend/src/app/components/api-keys/api-keys.component.css | API keys page layout and styling. |
| frontend/src/app/app-routing.module.ts | Adds /branding and /api-keys, renames SSO route to /saml. |
| backend/src/enums/log-operation-type.enum.ts | Adds exportRows operation type. |
| backend/src/entities/table/use-cases/export-csv-from-table.use.case.ts | Writes an audit log record for CSV export success/failure. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| handleChangeCompanyDomain() { | ||
| this.submittingCustomDomain = true; | ||
| if (this.companyCustomDomain.id) { | ||
| this._company.updateCustomDomain(this.company.id, this.companyCustomDomain.id).subscribe(() => { | ||
| this.submittingCustomDomain = false; | ||
| this.angulartics2.eventTrack.next({ | ||
| action: 'Company: domain is updated successfully', | ||
| }); | ||
| }); | ||
| } else { | ||
| this._company.createCustomDomain(this.company.id, this.companyCustomDomainHostname).subscribe(() => { | ||
| this.submittingCustomDomain = false; | ||
| this.angulartics2.eventTrack.next({ | ||
| action: 'Company: domain is created successfully', |
There was a problem hiding this comment.
handleChangeCompanyDomain() calls updateCustomDomain(this.company.id, this.companyCustomDomain.id), but CompanyService.updateCustomDomain(companyId, hostname) expects the hostname string (and you already track it as companyCustomDomainHostname). Passing the domain id will send the wrong payload to /saas/custom-domain/update/:companyId and prevent updates from working.
| const actions = { | ||
| addRow: 'added row', | ||
| deleteRow: 'deleted row', | ||
| updateRow: 'edit row', | ||
| rowReceived: 'received row', | ||
| rowsReceived: 'received rows' | ||
| addRow: 'Created', | ||
| deleteRow: 'Deleted', | ||
| updateRow: 'Edited', | ||
| rowReceived: 'Viewed', | ||
| rowsReceived: 'Viewed', | ||
| importRow: 'Imported', | ||
| exportRows: 'Exported' | ||
| } | ||
|
|
||
| const actionIcons = { | ||
| addRow: 'add', | ||
| deleteRow: 'delete', | ||
| updateRow: 'edit', | ||
| rowReceived: 'visibility', | ||
| rowsReceived: 'visibility', | ||
| importRow: 'upload', | ||
| exportRows: 'download' | ||
| } |
There was a problem hiding this comment.
actions[log.operationType] / actionIcons[log.operationType] will be undefined for operation types not listed here (e.g. backend enum includes actionActivated). This will render blank/"—" actions and may also create unexpected CSS classes. Add explicit mappings for the missing operation types and/or provide a fallback label/icon when the operation type is unknown.
| getUserName(email: string): string | null { | ||
| if (!this.usersList) return null; | ||
| const user = this.usersList.find((u) => u.email === email); | ||
| return user?.name || null; |
There was a problem hiding this comment.
getUserName() does a linear find() over usersList. Since the template calls getUserName(element.UserEmail) multiple times per row, this can become O(rows × users) per change detection. Consider building a Map<email, name> once when usersList is loaded (or enriching the datasource rows with UserName) and do O(1) lookups in the template.
| <mat-icon *ngIf="element.ActionIcon === 'visibility'" class="material-icons-outlined action-icon action-icon--visibility">visibility</mat-icon> | ||
| <mat-icon *ngIf="element.ActionIcon === 'delete'" class="material-icons-outlined action-icon action-icon--delete">delete</mat-icon> |
There was a problem hiding this comment.
The Action column uses class="material-icons-outlined" for some icons, while the app elsewhere appears to use Material Symbols (e.g. fontSet="material-symbols-outlined"). If the Material Icons font isn’t loaded, these icons won’t render. Use the same icon font approach here (e.g. fontSet="material-symbols-outlined") or remove the special-casing and rely on the project’s configured default.
| <mat-icon *ngIf="element.ActionIcon === 'visibility'" class="material-icons-outlined action-icon action-icon--visibility">visibility</mat-icon> | |
| <mat-icon *ngIf="element.ActionIcon === 'delete'" class="material-icons-outlined action-icon action-icon--delete">delete</mat-icon> | |
| <mat-icon *ngIf="element.ActionIcon === 'visibility'" class="action-icon action-icon--visibility">visibility</mat-icon> | |
| <mat-icon *ngIf="element.ActionIcon === 'delete'" class="action-icon action-icon--delete">delete</mat-icon> |
| beforeEach(async () => { | ||
| await TestBed.configureTestingModule({ | ||
| imports: [ZapierComponent], | ||
| imports: [ZapierComponent, RouterModule.forRoot([])], | ||
| providers: [provideHttpClient()] | ||
| }) |
There was a problem hiding this comment.
This spec now renders ProfileSidebarComponent, whose ngOnInit subscribes to UiSettingsService.getUiSettings() and triggers an HTTP GET to /user/settings. The test currently provides a real HttpClient but doesn’t mock the request, which can make the test fail/flaky. Consider using provideHttpClientTesting() and flushing the request, or stubbing UiSettingsService.getUiSettings() to return a synchronous observable.
No description provided.