File: src/app/foundation/shared/components/toolbar/shared-toolbar.component.ts
Standard page toolbar: title + Add button, a 3-dot overflow menu (Export / Export PDF / Download Template / Import), a search row (basic / SQL / AI modes via <app-search-mode>), a projected filter row, and an optional Cards/Table layout toggle. Never inline a toolbar manually — including the layout-toggle buttons; use showLayoutToggle/activeLayout/layoutChange below instead of recreating the two buttons in toolbar-extra.
Note:
<app-table>and<app-tree-table>already compose this toolbar internally (showToolbar,toolbarShowAdd,toolbarFilters,showLayoutToggle, etc. on those components forward straight through to here). Only drop<app-shared-toolbar>directly into a page when you need a layout the table/tree-table wrapper can't express (e.g. the toolbar sits above a tree-table rendered with[showToolbar]="false").
| Input | Type | Default | What it does |
|---|---|---|---|
title |
string |
'' |
Page heading |
showAdd |
boolean |
false |
Shows the Add button |
showSearch |
boolean |
true |
Shows the entire search row (Row 2 search side) |
showBuiltInSearch |
boolean |
true |
Shows the basic-mode search input itself |
showClearButton |
boolean |
true |
Shows the "Clear filters" button next to filters |
searchValue |
string |
'' |
Current basic-search string |
searchPlaceholder |
string |
'Search…' |
Basic-search input placeholder |
searchMode |
'basic' | 'sql' | 'ai' |
'basic' |
Active search mode |
availableSearchModes |
SearchMode[] |
['basic','sql','ai'] |
Which mode-switcher icons are shown |
sqlValue |
string |
'' |
Current SQL-mode textarea value |
sqlPlaceholder |
string |
'' |
SQL-mode placeholder (falls back to an i18n default) |
aiValue |
string |
'' |
Current AI-mode textarea value |
aiPlaceholder |
string |
'' |
AI-mode placeholder (falls back to an i18n default) |
hasFilters |
boolean |
false |
Shows Row 2 (search + projected filters + layout toggle) at all |
showLayoutToggle |
boolean |
false |
Shows the built-in Cards/Table toggle — use this instead of a manual toggle |
activeLayout |
'list' | 'grid' |
'list' |
Which toggle button is highlighted |
| Output | Payload | When fired |
|---|---|---|
addClicked |
void |
Add button clicked |
searchValueChange |
string |
Supports [(searchValue)] |
searchChanged |
string |
Every keystroke (basic mode) + Enter |
clearSearch |
void |
Clear-filters button clicked |
searchModeChange |
SearchMode |
Mode switcher clicked |
sqlValueChange / sqlSearch |
string |
SQL textarea changes / Enter or search-icon clicked |
aiValueChange / aiSearch |
string |
AI textarea changes / Enter or sparkles-icon clicked |
layoutChange |
'list' | 'grid' |
Layout toggle button clicked |
onExport |
void |
"Export" clicked in the 3-dot menu |
onExportPdf |
void |
"Export PDF" clicked in the 3-dot menu |
onImport |
void |
"Import" clicked in the 3-dot menu |
onDownloadTemplate |
void |
"Download Template" clicked in the 3-dot menu |
| Slot | Purpose |
|---|---|
[toolbar-row-actions] |
Extra buttons in Row 1, to the left of Add |
[toolbar-filters] |
Filter dropdowns/chips rendered inside the search row (Row 2), next to the search input |
[toolbar-extra] |
Right-aligned custom content in Row 2, after the built-in layout toggle (if shown) |
The search row is rendered by <app-search-mode> (src/app/foundation/shared/components/search-mode/search-mode.component.ts), a child component owned by the toolbar — it is not meant to be used standalone. availableSearchModes controls which of the three mode icons (pi-globe / pi-code / pi-sparkles) appear; if only one mode is available the switcher icons are hidden entirely. SQL/AI modes submit on Enter (Shift+Enter inserts a newline) or via their trailing button. As of this writing no page in the app sets availableSearchModes away from the default, so SQL/AI mode is wired but unused — confirm a real consumer exists before building on it.
The Cards/Table toggle is built into the toolbar (showLayoutToggle / activeLayout / layoutChange) specifically so every page renders the same two buttons instead of each page hand-rolling its own pi-th-large/pi-list pair in toolbar-extra. Wire it like this:
<app-shared-toolbar
[showLayoutToggle]="true"
[activeLayout]="layoutMode()"
(layoutChange)="layoutMode.set($event)"
>
...
</app-shared-toolbar>Tooltips use shared.toolbar.cardsView / shared.toolbar.tableView (see i18n keys below) — don't pass per-page tooltip text.
All static labels come from the shared transloco scope under shared.toolbar.*: moreOptions, clearFilters, export, exportPdf, import, downloadTemplate, cardsView, tableView. Add new keys to both public/i18n/en/shared.json and public/i18n/ar/shared.json together — a key present in only one locale silently falls back to the raw key string at runtime.
<app-shared-toolbar
[title]="tr().pageTitle"
[searchValue]="globalSearchText()"
[searchPlaceholder]="tr().search"
[hasFilters]="true"
[showAdd]="true"
[showLayoutToggle]="true"
[activeLayout]="layoutMode()"
(addClicked)="openNew()"
(searchChanged)="onSearchChanged($event)"
(clearSearch)="clearFilters()"
(onExport)="exportToCSV()"
(layoutChange)="layoutMode.set($event)"
>
<ng-container toolbar-filters>
<app-filter
[label]="tr().filterStatus"
[options]="statusOpts()"
[selected]="selectedStatusFilters()"
(selectedChange)="updateStatusFilters($event)"
/>
</ng-container>
</app-shared-toolbar>