@navette-js/panels 0.0.0-stage → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +8 -2
- package/THIRD-PARTY-NOTICES.md +12 -0
- package/dist/FILAMENT-LICENSE.md +21 -0
- package/dist/filament/css/filament/filament/app.css +2 -0
- package/dist/filament/fonts/INTER-LICENSE.txt +92 -0
- package/dist/filament/fonts/filament/filament/inter/index.css +1 -0
- package/dist/filament/fonts/filament/filament/inter/inter-cyrillic-ext-wght-normal-SP7Z6XGK.woff2 +0 -0
- package/dist/filament/fonts/filament/filament/inter/inter-cyrillic-wght-normal-DR6K5BQD.woff2 +0 -0
- package/dist/filament/fonts/filament/filament/inter/inter-greek-ext-wght-normal-A2J6H3EX.woff2 +0 -0
- package/dist/filament/fonts/filament/filament/inter/inter-greek-wght-normal-ZABHMKQG.woff2 +0 -0
- package/dist/filament/fonts/filament/filament/inter/inter-latin-ext-wght-normal-ZIT2UBIY.woff2 +0 -0
- package/dist/filament/fonts/filament/filament/inter/inter-latin-wght-normal-DIHYUR35.woff2 +0 -0
- package/dist/filament/fonts/filament/filament/inter/inter-vietnamese-wght-normal-VWEHJHBA.woff2 +0 -0
- package/dist/filament/js/filament/actions/actions.js +1 -0
- package/dist/filament/js/filament/filament/app.js +1 -0
- package/dist/filament/js/filament/filament/echo.js +13 -0
- package/dist/filament/js/filament/forms/components/builder.js +1 -0
- package/dist/filament/js/filament/forms/components/checkbox-list.js +1 -0
- package/dist/filament/js/filament/forms/components/code-editor.js +38 -0
- package/dist/filament/js/filament/forms/components/color-picker.js +1 -0
- package/dist/filament/js/filament/forms/components/date-time-picker.js +1 -0
- package/dist/filament/js/filament/forms/components/file-upload.js +116 -0
- package/dist/filament/js/filament/forms/components/js-field.js +1 -0
- package/dist/filament/js/filament/forms/components/key-value.js +1 -0
- package/dist/filament/js/filament/forms/components/markdown-editor.js +51 -0
- package/dist/filament/js/filament/forms/components/repeater.js +1 -0
- package/dist/filament/js/filament/forms/components/rich-editor.js +161 -0
- package/dist/filament/js/filament/forms/components/select.js +11 -0
- package/dist/filament/js/filament/forms/components/slider.js +1 -0
- package/dist/filament/js/filament/forms/components/tags-input.js +1 -0
- package/dist/filament/js/filament/forms/components/text-input/password-reveal.js +1 -0
- package/dist/filament/js/filament/forms/components/textarea.js +1 -0
- package/dist/filament/js/filament/forms/components/toggle-buttons.js +1 -0
- package/dist/filament/js/filament/notifications/notifications.js +1 -0
- package/dist/filament/js/filament/schemas/components/actions.js +1 -0
- package/dist/filament/js/filament/schemas/components/js-component.js +1 -0
- package/dist/filament/js/filament/schemas/components/tabs.js +1 -0
- package/dist/filament/js/filament/schemas/components/wizard.js +1 -0
- package/dist/filament/js/filament/schemas/schemas.js +1 -0
- package/dist/filament/js/filament/support/support.js +46 -0
- package/dist/filament/js/filament/tables/components/columns/checkbox.js +1 -0
- package/dist/filament/js/filament/tables/components/columns/select.js +11 -0
- package/dist/filament/js/filament/tables/components/columns/text-input.js +1 -0
- package/dist/filament/js/filament/tables/components/columns/toggle.js +1 -0
- package/dist/filament/js/filament/tables/tables.js +1 -0
- package/dist/filament/js/filament/widgets/components/chart.js +31 -0
- package/dist/filament/js/filament/widgets/components/js-widget.js +1 -0
- package/dist/filament/js/filament/widgets/components/stats-overview/stat/chart.js +20 -0
- package/dist/navette/navette/calendar.css +108 -0
- package/dist/navette/navette/motion.css +101 -0
- package/dist/navette/navette/motion.js +49 -0
- package/lib/auth.d.ts +61 -0
- package/lib/auth.js +140 -0
- package/lib/calendar.d.ts +82 -0
- package/lib/calendar.js +107 -0
- package/lib/index.d.ts +1624 -0
- package/lib/index.js +3532 -0
- package/lib/notifications.d.ts +76 -0
- package/lib/notifications.js +112 -0
- package/lib/topbar.d.ts +90 -0
- package/lib/topbar.js +240 -0
- package/package.json +58 -4
- package/resources/filament/LICENSE.md +21 -0
- package/resources/filament/README.md +2 -0
- package/resources/filament/packages/actions/resources/css/actions.css +30 -0
- package/resources/filament/packages/actions/resources/css/index.css +1 -0
- package/resources/filament/packages/forms/dist/index.css +1 -0
- package/resources/filament/packages/forms/resources/css/components/builder.css +206 -0
- package/resources/filament/packages/forms/resources/css/components/checkbox-list.css +55 -0
- package/resources/filament/packages/forms/resources/css/components/code-editor.css +79 -0
- package/resources/filament/packages/forms/resources/css/components/color-picker.css +17 -0
- package/resources/filament/packages/forms/resources/css/components/date-time-picker.css +127 -0
- package/resources/filament/packages/forms/resources/css/components/field.css +88 -0
- package/resources/filament/packages/forms/resources/css/components/file-upload/filepond-plugin-media-preview.css +104 -0
- package/resources/filament/packages/forms/resources/css/components/file-upload.css +199 -0
- package/resources/filament/packages/forms/resources/css/components/key-value.css +57 -0
- package/resources/filament/packages/forms/resources/css/components/markdown-editor.css +343 -0
- package/resources/filament/packages/forms/resources/css/components/modal-table-select.css +17 -0
- package/resources/filament/packages/forms/resources/css/components/radio.css +41 -0
- package/resources/filament/packages/forms/resources/css/components/repeater.css +401 -0
- package/resources/filament/packages/forms/resources/css/components/rich-editor.css +666 -0
- package/resources/filament/packages/forms/resources/css/components/select.css +13 -0
- package/resources/filament/packages/forms/resources/css/components/slider.css +54 -0
- package/resources/filament/packages/forms/resources/css/components/tags-input.css +33 -0
- package/resources/filament/packages/forms/resources/css/components/text-input.css +20 -0
- package/resources/filament/packages/forms/resources/css/components/textarea.css +26 -0
- package/resources/filament/packages/forms/resources/css/components/toggle-buttons.css +49 -0
- package/resources/filament/packages/forms/resources/css/index.css +32 -0
- package/resources/filament/packages/infolists/resources/css/components/code.css +21 -0
- package/resources/filament/packages/infolists/resources/css/components/color.css +34 -0
- package/resources/filament/packages/infolists/resources/css/components/entry.css +68 -0
- package/resources/filament/packages/infolists/resources/css/components/icon.css +39 -0
- package/resources/filament/packages/infolists/resources/css/components/image.css +161 -0
- package/resources/filament/packages/infolists/resources/css/components/key-value.css +24 -0
- package/resources/filament/packages/infolists/resources/css/components/repeatable.css +136 -0
- package/resources/filament/packages/infolists/resources/css/components/text.css +234 -0
- package/resources/filament/packages/infolists/resources/css/index.css +14 -0
- package/resources/filament/packages/notifications/resources/css/database-notifications.css +56 -0
- package/resources/filament/packages/notifications/resources/css/index.css +3 -0
- package/resources/filament/packages/notifications/resources/css/notification.css +109 -0
- package/resources/filament/packages/notifications/resources/css/notifications.css +29 -0
- package/resources/filament/packages/panels/resources/css/base.css +13 -0
- package/resources/filament/packages/panels/resources/css/components/global-search.css +93 -0
- package/resources/filament/packages/panels/resources/css/components/header.css +56 -0
- package/resources/filament/packages/panels/resources/css/components/layout.css +182 -0
- package/resources/filament/packages/panels/resources/css/components/logo.css +11 -0
- package/resources/filament/packages/panels/resources/css/components/page.css +60 -0
- package/resources/filament/packages/panels/resources/css/components/sidebar.css +311 -0
- package/resources/filament/packages/panels/resources/css/components/tenant-menu.css +49 -0
- package/resources/filament/packages/panels/resources/css/components/theme-switcher.css +15 -0
- package/resources/filament/packages/panels/resources/css/components/topbar.css +89 -0
- package/resources/filament/packages/panels/resources/css/components/user-menu.css +46 -0
- package/resources/filament/packages/panels/resources/css/index.css +40 -0
- package/resources/filament/packages/panels/resources/css/theme.css +2 -0
- package/resources/filament/packages/panels/resources/css/utilities.css +3 -0
- package/resources/filament/packages/panels/resources/css/widgets/account-widget.css +21 -0
- package/resources/filament/packages/panels/resources/css/widgets/filament-info-widget.css +21 -0
- package/resources/filament/packages/schemas/resources/css/components/actions.css +29 -0
- package/resources/filament/packages/schemas/resources/css/components/flex.css +106 -0
- package/resources/filament/packages/schemas/resources/css/components/form.css +7 -0
- package/resources/filament/packages/schemas/resources/css/components/fused-group.css +337 -0
- package/resources/filament/packages/schemas/resources/css/components/icon.css +11 -0
- package/resources/filament/packages/schemas/resources/css/components/image.css +12 -0
- package/resources/filament/packages/schemas/resources/css/components/section.css +24 -0
- package/resources/filament/packages/schemas/resources/css/components/tabs.css +77 -0
- package/resources/filament/packages/schemas/resources/css/components/text.css +77 -0
- package/resources/filament/packages/schemas/resources/css/components/unordered-list.css +15 -0
- package/resources/filament/packages/schemas/resources/css/components/wizard.css +177 -0
- package/resources/filament/packages/schemas/resources/css/index.css +12 -0
- package/resources/filament/packages/schemas/resources/css/schema.css +132 -0
- package/resources/filament/packages/support/dist/index.css +1 -0
- package/resources/filament/packages/support/resources/css/base.css +23 -0
- package/resources/filament/packages/support/resources/css/components/avatar.css +15 -0
- package/resources/filament/packages/support/resources/css/components/badge.css +90 -0
- package/resources/filament/packages/support/resources/css/components/breadcrumbs.css +25 -0
- package/resources/filament/packages/support/resources/css/components/button.css +214 -0
- package/resources/filament/packages/support/resources/css/components/callout.css +57 -0
- package/resources/filament/packages/support/resources/css/components/dropdown/header.css +21 -0
- package/resources/filament/packages/support/resources/css/components/dropdown/index.css +79 -0
- package/resources/filament/packages/support/resources/css/components/dropdown/list/index.css +7 -0
- package/resources/filament/packages/support/resources/css/components/dropdown/list/item.css +74 -0
- package/resources/filament/packages/support/resources/css/components/empty-state.css +67 -0
- package/resources/filament/packages/support/resources/css/components/fieldset.css +23 -0
- package/resources/filament/packages/support/resources/css/components/grid.css +511 -0
- package/resources/filament/packages/support/resources/css/components/icon-button.css +124 -0
- package/resources/filament/packages/support/resources/css/components/icon.css +31 -0
- package/resources/filament/packages/support/resources/css/components/input/checkbox.css +32 -0
- package/resources/filament/packages/support/resources/css/components/input/index.css +55 -0
- package/resources/filament/packages/support/resources/css/components/input/one-time-code.css +7 -0
- package/resources/filament/packages/support/resources/css/components/input/radio.css +11 -0
- package/resources/filament/packages/support/resources/css/components/input/select.css +154 -0
- package/resources/filament/packages/support/resources/css/components/input/wrapper.css +107 -0
- package/resources/filament/packages/support/resources/css/components/link.css +90 -0
- package/resources/filament/packages/support/resources/css/components/loading-indicator.css +3 -0
- package/resources/filament/packages/support/resources/css/components/loading-section.css +3 -0
- package/resources/filament/packages/support/resources/css/components/modal.css +494 -0
- package/resources/filament/packages/support/resources/css/components/pagination.css +160 -0
- package/resources/filament/packages/support/resources/css/components/section.css +234 -0
- package/resources/filament/packages/support/resources/css/components/tabs.css +70 -0
- package/resources/filament/packages/support/resources/css/components/toggle.css +60 -0
- package/resources/filament/packages/support/resources/css/components/tooltip.css +36 -0
- package/resources/filament/packages/support/resources/css/index.css +133 -0
- package/resources/filament/packages/support/resources/css/sortable.css +3 -0
- package/resources/filament/packages/support/resources/css/utilities.css +897 -0
- package/resources/filament/packages/tables/resources/css/actions.css +51 -0
- package/resources/filament/packages/tables/resources/css/cell.css +139 -0
- package/resources/filament/packages/tables/resources/css/column-manager.css +48 -0
- package/resources/filament/packages/tables/resources/css/columns/checkbox.css +54 -0
- package/resources/filament/packages/tables/resources/css/columns/color.css +76 -0
- package/resources/filament/packages/tables/resources/css/columns/icon.css +81 -0
- package/resources/filament/packages/tables/resources/css/columns/image.css +207 -0
- package/resources/filament/packages/tables/resources/css/columns/layout/grid.css +49 -0
- package/resources/filament/packages/tables/resources/css/columns/layout/panel.css +3 -0
- package/resources/filament/packages/tables/resources/css/columns/layout/split.css +35 -0
- package/resources/filament/packages/tables/resources/css/columns/layout/stack.css +29 -0
- package/resources/filament/packages/tables/resources/css/columns/select.css +36 -0
- package/resources/filament/packages/tables/resources/css/columns/summaries/icon-count.css +43 -0
- package/resources/filament/packages/tables/resources/css/columns/summaries/range.css +27 -0
- package/resources/filament/packages/tables/resources/css/columns/summaries/text.css +29 -0
- package/resources/filament/packages/tables/resources/css/columns/summaries/values.css +33 -0
- package/resources/filament/packages/tables/resources/css/columns/text-input.css +36 -0
- package/resources/filament/packages/tables/resources/css/columns/text.css +319 -0
- package/resources/filament/packages/tables/resources/css/columns/toggle.css +54 -0
- package/resources/filament/packages/tables/resources/css/container.css +311 -0
- package/resources/filament/packages/tables/resources/css/content.css +342 -0
- package/resources/filament/packages/tables/resources/css/empty-state.css +31 -0
- package/resources/filament/packages/tables/resources/css/group-header.css +54 -0
- package/resources/filament/packages/tables/resources/css/header-cell.css +224 -0
- package/resources/filament/packages/tables/resources/css/index.css +26 -0
- package/resources/filament/packages/tables/resources/css/row.css +47 -0
- package/resources/filament/packages/tables/resources/css/table.css +394 -0
- package/resources/filament/packages/widgets/resources/css/chart-widget.css +88 -0
- package/resources/filament/packages/widgets/resources/css/index.css +3 -0
- package/resources/filament/packages/widgets/resources/css/stats-overview-widget.css +67 -0
- package/resources/filament/packages/widgets/resources/css/widget.css +3 -0
- package/theme.css +17 -0
- package/views/components/logo.ejs +9 -0
- package/views/components/tenant-menu.ejs +13 -0
- package/views/components/user-menu.ejs +82 -0
- package/views/layout/base.ejs +129 -0
- package/views/layout/index.ejs +41 -0
- package/views/layout/simple.ejs +19 -0
- package/views/livewire/sidebar.ejs +123 -0
- package/views/livewire/topbar.ejs +47 -0
- package/views/pages/page.ejs +143 -0
- package/views/pages/simple.ejs +32 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,1624 @@
|
|
|
1
|
+
import { type Mailer, type MailMessage } from './auth.ts';
|
|
2
|
+
export { consoleMailer, fileMailer, hashPassword, knexAuthProvider, knexTenantProvider, mailText, verifyPassword, type Mailer, type MailMessage, type TableQuery } from './auth.ts';
|
|
3
|
+
import { type Request, type Response, type Router } from 'express';
|
|
4
|
+
import { Action } from '@navette-js/actions';
|
|
5
|
+
import { Step, Wizard } from '@navette-js/forms';
|
|
6
|
+
import { Component as SchemaComponent, Schema, type SchemaHost } from '@navette-js/schemas';
|
|
7
|
+
export { Notification, Notifications } from './notifications.ts';
|
|
8
|
+
import { type CalendarEvent, type CalendarLabels, type CalendarView } from './calendar.ts';
|
|
9
|
+
export { addDays, addMonths, CALENDAR_LABELS, dayOf, daysBetween, eventsOn, renderCalendar, renderCalendarEvent, timeOf, visibleRange, type CalendarEvent, type CalendarLabels, type CalendarModel, type CalendarView } from './calendar.ts';
|
|
10
|
+
import { type DatabaseNotificationStore, type GlobalSearchCategory, type GlobalSearchResult } from './topbar.ts';
|
|
11
|
+
export { DatabaseNotifications, GlobalSearch, knexNotificationStore, timeAgo, type DatabaseNotificationAction, type DatabaseNotificationRecord, type DatabaseNotificationStore, type GlobalSearchCategory, type GlobalSearchResult } from './topbar.ts';
|
|
12
|
+
import { ColorManager, RenderHookRegistry, type Palette, type RenderHookCallback } from '@navette-js/support';
|
|
13
|
+
import type { DataAdapter } from '@navette-js/database';
|
|
14
|
+
import { Table, type ColumnState, type FilterState, type TableHost } from '@navette-js/tables';
|
|
15
|
+
import { Component, type WireRuntime } from '@navette-js/wire';
|
|
16
|
+
export declare const ASSET_VERSION = "5.11.2.0";
|
|
17
|
+
/** The signed-in user. Your auth provider may add any field (role, team…): policies receive it as-is. */
|
|
18
|
+
export type User = {
|
|
19
|
+
id: string | number;
|
|
20
|
+
name: string;
|
|
21
|
+
email: string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Resource policy: one function per ability
|
|
26
|
+
* (`viewAny`, `create`, `update`, `delete`, `deleteAny`, `restore`, `forceDelete`, `reorder`, or your own names).
|
|
27
|
+
* A missing ability is allowed.
|
|
28
|
+
*/
|
|
29
|
+
export type Policy<R = any> = Partial<Record<string, (user: User, record: R | null) => boolean | Promise<boolean>>>;
|
|
30
|
+
/** A reusable bundle of configuration. `register` receives the panel being built; `boot` is called when the router is mounted. */
|
|
31
|
+
export type Plugin = {
|
|
32
|
+
id: string;
|
|
33
|
+
register(panel: Panel): void;
|
|
34
|
+
boot?(panel: Panel): void;
|
|
35
|
+
};
|
|
36
|
+
/** Question asked to the panel's authorization hook. `resource`, `page` or `widget` tells what it is about. */
|
|
37
|
+
export type AuthorizationCheck = {
|
|
38
|
+
user: User;
|
|
39
|
+
ability: string;
|
|
40
|
+
resource: unknown | null;
|
|
41
|
+
record: unknown | null;
|
|
42
|
+
page: typeof Page | null;
|
|
43
|
+
widget: typeof Widget | null;
|
|
44
|
+
};
|
|
45
|
+
/** Return `true` or `false` to decide, or `undefined` to let the resource policy (or `canAccess` / `canView`) answer. */
|
|
46
|
+
export type Authorizer = (check: AuthorizationCheck) => boolean | undefined | Promise<boolean | undefined>;
|
|
47
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* User provider. `attempt` and `find` are enough for login; the optional methods enable
|
|
50
|
+
* registration (`create`, `findByEmail`), password reset (`findByEmail`, `update`, `getPasswordFingerprint`),
|
|
51
|
+
* email verification (`hasVerifiedEmail`, `markEmailAsVerified`) and the profile page (`update`).
|
|
52
|
+
* `knexAuthProvider(knex)` implements all of them for a `users` table.
|
|
53
|
+
*/
|
|
54
|
+
export interface AuthProvider {
|
|
55
|
+
attempt(email: string, password: string): MaybePromise<User | null>;
|
|
56
|
+
find(id: string | number): MaybePromise<User | null>;
|
|
57
|
+
findByEmail?(email: string): MaybePromise<User | null>;
|
|
58
|
+
/** Creates the user. The password is plain text; the provider must hash it. */
|
|
59
|
+
create?(data: {
|
|
60
|
+
name: string;
|
|
61
|
+
email: string;
|
|
62
|
+
password: string;
|
|
63
|
+
}): MaybePromise<User>;
|
|
64
|
+
/** Updates name, email or password (plain text, to hash). Changing the email must reset its verification. */
|
|
65
|
+
update?(user: User, data: {
|
|
66
|
+
name?: string;
|
|
67
|
+
email?: string;
|
|
68
|
+
password?: string;
|
|
69
|
+
}): MaybePromise<User>;
|
|
70
|
+
hasVerifiedEmail?(user: User): MaybePromise<boolean>;
|
|
71
|
+
markEmailAsVerified?(user: User): MaybePromise<void>;
|
|
72
|
+
/** A value that changes with the stored password, so a used reset link becomes invalid. */
|
|
73
|
+
getPasswordFingerprint?(user: User): MaybePromise<string>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Panel tenants (teams, organizations…). Every panel page then lives under
|
|
77
|
+
* `/<panel>/<tenant key>/…`, and only a member of the tenant can open it.
|
|
78
|
+
*/
|
|
79
|
+
export interface TenantProvider<T = any> {
|
|
80
|
+
/** Tenants the user is a member of. */
|
|
81
|
+
getTenants(user: User): MaybePromise<T[]>;
|
|
82
|
+
/** Tenant from its URL key (comes from the browser: validate it). */
|
|
83
|
+
find(key: string): MaybePromise<T | null>;
|
|
84
|
+
canAccess(user: User, tenant: T): MaybePromise<boolean>;
|
|
85
|
+
getKey(tenant: T): string;
|
|
86
|
+
getName(tenant: T): string;
|
|
87
|
+
/** Text above the tenant name in the menu ("Current team"), or `null`. */
|
|
88
|
+
getCurrentTenantLabel?(tenant: T): string | null;
|
|
89
|
+
getAvatarUrl?(tenant: T): string | null;
|
|
90
|
+
/** Creates a tenant (tenant registration page); the user becomes a member. */
|
|
91
|
+
create?(data: Record<string, unknown>, user: User): MaybePromise<T>;
|
|
92
|
+
update?(tenant: T, data: Record<string, unknown>): MaybePromise<T>;
|
|
93
|
+
}
|
|
94
|
+
export type PanelContext = {
|
|
95
|
+
req: Request;
|
|
96
|
+
res: Response;
|
|
97
|
+
panel: Panel;
|
|
98
|
+
user: User | null;
|
|
99
|
+
mailbox: string;
|
|
100
|
+
tenant?: unknown;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Predefined panel theme: a set of colors (palettes or plain colors), optionally a font and some CSS.
|
|
104
|
+
* When a panel declares several, users pick theirs from the user menu; the choice is kept in a cookie.
|
|
105
|
+
*/
|
|
106
|
+
export type Theme = {
|
|
107
|
+
id: string;
|
|
108
|
+
label: string;
|
|
109
|
+
colors?: Record<string, Palette | string>;
|
|
110
|
+
font?: {
|
|
111
|
+
family: string;
|
|
112
|
+
url?: string;
|
|
113
|
+
};
|
|
114
|
+
/** CSS added to the page for this theme (written by the panel developer, inserted as-is). */
|
|
115
|
+
css?: string;
|
|
116
|
+
};
|
|
117
|
+
export declare class NavigationItem {
|
|
118
|
+
label: string;
|
|
119
|
+
_url: string;
|
|
120
|
+
_icon: string | null;
|
|
121
|
+
_group: string | null;
|
|
122
|
+
_sort: number;
|
|
123
|
+
_isActive: ((path: string) => boolean) | null;
|
|
124
|
+
_badge: string | number | null;
|
|
125
|
+
_badgeColor: string;
|
|
126
|
+
constructor(label: string);
|
|
127
|
+
static make(label: string): NavigationItem;
|
|
128
|
+
url(url: string): this;
|
|
129
|
+
icon(icon: string | null): this;
|
|
130
|
+
group(group: string | null): this;
|
|
131
|
+
sort(sort: number): this;
|
|
132
|
+
badge(badge: string | number | null, color?: string): this;
|
|
133
|
+
/** By default an item is active on its exact URL; this overrides the rule. */
|
|
134
|
+
isActiveWhen(fn: (path: string) => boolean): this;
|
|
135
|
+
isActive(path: string): boolean;
|
|
136
|
+
}
|
|
137
|
+
export declare class Panel {
|
|
138
|
+
private _id;
|
|
139
|
+
private _path;
|
|
140
|
+
private _brandName;
|
|
141
|
+
private _brandLogo;
|
|
142
|
+
private _darkModeBrandLogo;
|
|
143
|
+
private _brandLogoHeight;
|
|
144
|
+
private _favicon;
|
|
145
|
+
private _theme;
|
|
146
|
+
private _motion;
|
|
147
|
+
private _themes;
|
|
148
|
+
private _font;
|
|
149
|
+
private _login;
|
|
150
|
+
private _auth;
|
|
151
|
+
private _key;
|
|
152
|
+
private _pages;
|
|
153
|
+
private _resources;
|
|
154
|
+
private _navigationItems;
|
|
155
|
+
private _navigationGroups;
|
|
156
|
+
private _maxContentWidth;
|
|
157
|
+
readonly colors: ColorManager;
|
|
158
|
+
static make(): Panel;
|
|
159
|
+
id(id: string): this;
|
|
160
|
+
path(path: string): this;
|
|
161
|
+
brandName(name: string): this;
|
|
162
|
+
brandLogo(url: string): this;
|
|
163
|
+
darkModeBrandLogo(url: string): this;
|
|
164
|
+
brandLogoHeight(height: string): this;
|
|
165
|
+
/** Browser tab icon. */
|
|
166
|
+
favicon(url: string | null): this;
|
|
167
|
+
getFavicon(): string | null;
|
|
168
|
+
/**
|
|
169
|
+
* Theme stylesheet compiled by the application (Tailwind); it replaces the default stylesheet.
|
|
170
|
+
* The theme imports `@navette-js/panels/theme.css` and declares its own sources.
|
|
171
|
+
*/
|
|
172
|
+
theme(url: string | null): this;
|
|
173
|
+
getTheme(): string | null;
|
|
174
|
+
/**
|
|
175
|
+
* Navette's motion and loading indicators (springs, activity dot, spinner for deferred areas).
|
|
176
|
+
* `motion(false)` renders the plain interface without them.
|
|
177
|
+
*/
|
|
178
|
+
motion(enabled?: boolean): this;
|
|
179
|
+
hasMotion(): boolean;
|
|
180
|
+
/** Themes offered to the user; the first one is the default. */
|
|
181
|
+
themes(themes: Theme[]): this;
|
|
182
|
+
getThemes(): Theme[];
|
|
183
|
+
/** Theme for the request: the cookie's theme if declared, otherwise the first one. `null` if the panel has no themes. */
|
|
184
|
+
resolveTheme(req: Request): Theme | null;
|
|
185
|
+
rememberTheme(res: Response, theme: Theme): void;
|
|
186
|
+
/** Runs a render with the colors of the request's theme. */
|
|
187
|
+
withTheme<T>(req: Request, fn: () => T): T;
|
|
188
|
+
setColors(colors: Record<string, Palette | string>): this;
|
|
189
|
+
/** Panel font. Without a URL, it is loaded from Bunny Fonts. */
|
|
190
|
+
font(family: string, url?: string): this;
|
|
191
|
+
login(page?: typeof Login): this;
|
|
192
|
+
auth(provider: AuthProvider): this;
|
|
193
|
+
key(key: string): this;
|
|
194
|
+
pages(pages: (typeof Page)[]): this;
|
|
195
|
+
/** Registers resources: their pages and navigation items. */
|
|
196
|
+
resources(resources: (typeof Resource)[]): this;
|
|
197
|
+
navigationItems(items: NavigationItem[]): this;
|
|
198
|
+
/** Order of navigation groups. */
|
|
199
|
+
navigationGroups(groups: string[]): this;
|
|
200
|
+
private _plugins;
|
|
201
|
+
/** Applies a plugin: an object that configures the panel (resources, pages, render hooks, themes…). */
|
|
202
|
+
plugin(plugin: Plugin): this;
|
|
203
|
+
plugins(plugins: Plugin[]): this;
|
|
204
|
+
getPlugins(): Plugin[];
|
|
205
|
+
private _renderHooks;
|
|
206
|
+
/**
|
|
207
|
+
* Inserts HTML at a named location of this panel's UI (names: `PanelsRenderHook`, `TablesRenderHook`, `ActionsRenderHook`, `WidgetsRenderHook`).
|
|
208
|
+
* `scopes` limits the hook to some pages or resources (their class). The HTML is inserted as-is: escape any data with `e()`.
|
|
209
|
+
*/
|
|
210
|
+
renderHook(name: string, render: RenderHookCallback, scopes?: unknown | unknown[] | null): this;
|
|
211
|
+
getRenderHooks(): RenderHookRegistry;
|
|
212
|
+
private _authorizer;
|
|
213
|
+
/** Plugs in your own permission system: consulted before any policy, for every ability, page and widget. */
|
|
214
|
+
authorizeUsing(authorizer: Authorizer | null): this;
|
|
215
|
+
/** Authorization decision: the panel hook first, then the given rule. Always `false` without a user. */
|
|
216
|
+
authorize(user: User | null, ability: string, subject?: {
|
|
217
|
+
resource?: unknown;
|
|
218
|
+
record?: unknown;
|
|
219
|
+
page?: typeof Page;
|
|
220
|
+
widget?: typeof Widget;
|
|
221
|
+
rule?: (() => boolean | Promise<boolean>) | null;
|
|
222
|
+
}): Promise<boolean>;
|
|
223
|
+
/** Whether the user can open a page. List: `viewAny`; create: `create`; edit: checked against the record; custom page: `canAccess`. */
|
|
224
|
+
canAccessPage(PageClass: typeof Page, user: User | null): Promise<boolean>;
|
|
225
|
+
private _widgets;
|
|
226
|
+
/** Panel widgets (dashboard, custom pages): registered as components, displayed through a page's `getHeaderWidgets()`. */
|
|
227
|
+
widgets(widgets: (typeof Widget)[]): this;
|
|
228
|
+
getWidgets(): (typeof Widget)[];
|
|
229
|
+
maxContentWidth(width: string): this;
|
|
230
|
+
getId(): string;
|
|
231
|
+
getBrandName(): string;
|
|
232
|
+
getAuth(): AuthProvider;
|
|
233
|
+
getLoginPage(): typeof Login | null;
|
|
234
|
+
getPages(): (typeof Page)[];
|
|
235
|
+
getResources(): (typeof Resource)[];
|
|
236
|
+
private _globalSearch;
|
|
237
|
+
private _globalSearchKeyBindings;
|
|
238
|
+
private _globalSearchDebounce;
|
|
239
|
+
private _globalSearchSuffix;
|
|
240
|
+
/** `false` removes the global search field. It only appears when at least one resource is searchable. */
|
|
241
|
+
globalSearch(condition?: boolean): this;
|
|
242
|
+
/** Keyboard shortcuts that focus the field: `['command+k', 'ctrl+k']`. */
|
|
243
|
+
globalSearchKeyBindings(keyBindings: string[]): this;
|
|
244
|
+
getGlobalSearchKeyBindings(): string[];
|
|
245
|
+
/** Delay between typing and searching (`500ms` by default). */
|
|
246
|
+
globalSearchDebounce(debounce: string): this;
|
|
247
|
+
getGlobalSearchDebounce(): string;
|
|
248
|
+
globalSearchFieldSuffix(suffix: string | null): this;
|
|
249
|
+
/** Shows the first shortcut in the field, written for the browser's platform (`command+k` shows as "META+K" outside macOS). */
|
|
250
|
+
globalSearchFieldKeyBindingSuffix(): this;
|
|
251
|
+
getGlobalSearchFieldSuffix(userAgent?: string): string | null;
|
|
252
|
+
hasGlobalSearch(): boolean;
|
|
253
|
+
/** Results per resource, in registration order. Only resources the user can list are queried. */
|
|
254
|
+
getGlobalSearchResults(search: string, user: User | null): Promise<GlobalSearchCategory[]>;
|
|
255
|
+
private _databaseNotifications;
|
|
256
|
+
private _databaseNotificationsPolling;
|
|
257
|
+
/** Enables the database notifications bell, read from and written to this store (`knexNotificationStore(knex)`). */
|
|
258
|
+
databaseNotifications(store: DatabaseNotificationStore | null): this;
|
|
259
|
+
getDatabaseNotifications(): DatabaseNotificationStore | null;
|
|
260
|
+
/** Polling interval (`30s` by default); `null` disables polling. */
|
|
261
|
+
databaseNotificationsPolling(interval: string | null): this;
|
|
262
|
+
getDatabaseNotificationsPollingInterval(): string | null;
|
|
263
|
+
private _topbar;
|
|
264
|
+
private _topNavigation;
|
|
265
|
+
private _navigation;
|
|
266
|
+
private _sidebarCollapsibleOnDesktop;
|
|
267
|
+
private _sidebarFullyCollapsibleOnDesktop;
|
|
268
|
+
private _positions;
|
|
269
|
+
/** Topbar, shown by default. `topbar(false)` moves the logo, search, bell and user menu into the sidebar. */
|
|
270
|
+
topbar(condition?: boolean): this;
|
|
271
|
+
hasTopbar(): boolean;
|
|
272
|
+
/** Navigation in the topbar (one dropdown per group) instead of the sidebar. */
|
|
273
|
+
topNavigation(condition?: boolean): this;
|
|
274
|
+
hasTopNavigation(): boolean;
|
|
275
|
+
/** `navigation(false)` removes all navigation (no sidebar, no menus). */
|
|
276
|
+
navigation(condition?: boolean): this;
|
|
277
|
+
hasNavigation(): boolean;
|
|
278
|
+
/** On desktop, the sidebar can collapse to a column of icons. */
|
|
279
|
+
sidebarCollapsibleOnDesktop(condition?: boolean): this;
|
|
280
|
+
isSidebarCollapsibleOnDesktop(): boolean;
|
|
281
|
+
/** On desktop, the sidebar can be fully hidden. */
|
|
282
|
+
sidebarFullyCollapsibleOnDesktop(condition?: boolean): this;
|
|
283
|
+
isSidebarFullyCollapsibleOnDesktop(): boolean;
|
|
284
|
+
/** Where the user menu goes; defaults to the topbar when there is one. */
|
|
285
|
+
userMenuPosition(position: 'topbar' | 'sidebar' | null): this;
|
|
286
|
+
getUserMenuPosition(): 'topbar' | 'sidebar';
|
|
287
|
+
globalSearchPosition(position: 'topbar' | 'sidebar' | null): this;
|
|
288
|
+
getGlobalSearchPosition(): 'topbar' | 'sidebar';
|
|
289
|
+
databaseNotificationsPosition(position: 'topbar' | 'sidebar' | null): this;
|
|
290
|
+
getDatabaseNotificationsPosition(): 'topbar' | 'sidebar';
|
|
291
|
+
private _userMenuItems;
|
|
292
|
+
/** Items added to the user menu (URL or modal actions). A negative `sort()` places them above the theme switcher. Keys `profile` and `logout` replace the defaults. */
|
|
293
|
+
userMenuItems(items: Record<string, Action> | Action[]): this;
|
|
294
|
+
getUserMenuItems(): Record<string, Action>;
|
|
295
|
+
private _registration;
|
|
296
|
+
private _passwordReset;
|
|
297
|
+
private _emailVerification;
|
|
298
|
+
private _profile;
|
|
299
|
+
private _mailer;
|
|
300
|
+
/** Registration page (`/register`). The auth provider must implement `create` and `findByEmail`. */
|
|
301
|
+
registration(page?: typeof Register | null): this;
|
|
302
|
+
hasRegistration(): boolean;
|
|
303
|
+
getRegistrationPage(): typeof Register | null;
|
|
304
|
+
/** Password reset: request page (`/password-reset/request`), then reset through a signed link sent by email. */
|
|
305
|
+
passwordReset(request?: typeof RequestPasswordReset, reset?: typeof ResetPassword): this;
|
|
306
|
+
hasPasswordReset(): boolean;
|
|
307
|
+
getPasswordResetPages(): {
|
|
308
|
+
request: typeof RequestPasswordReset;
|
|
309
|
+
reset: typeof ResetPassword;
|
|
310
|
+
};
|
|
311
|
+
/** Email verification: a signed link is sent on registration. Until it is followed, only the verification prompt is accessible (`isRequired`). */
|
|
312
|
+
emailVerification(prompt?: typeof EmailVerificationPrompt, isRequired?: boolean): this;
|
|
313
|
+
hasEmailVerification(): boolean;
|
|
314
|
+
isEmailVerificationRequired(): boolean;
|
|
315
|
+
getEmailVerificationPrompt(): typeof EmailVerificationPrompt | null;
|
|
316
|
+
/** Profile page (`/profile`): name, email, password. `isSimple`: simple layout (default) or full panel layout. */
|
|
317
|
+
profile(page?: typeof EditProfile, isSimple?: boolean): this;
|
|
318
|
+
hasProfile(): boolean;
|
|
319
|
+
getProfile(): {
|
|
320
|
+
page: typeof EditProfile;
|
|
321
|
+
isSimple: boolean;
|
|
322
|
+
};
|
|
323
|
+
/** Mailer for password reset and verification emails. Defaults to the console. */
|
|
324
|
+
mailer(mailer: Mailer): this;
|
|
325
|
+
sendMail(message: MailMessage): Promise<void>;
|
|
326
|
+
getAuthKey(): string;
|
|
327
|
+
getRegistrationUrl(): string;
|
|
328
|
+
getRequestPasswordResetUrl(): string;
|
|
329
|
+
getResetPasswordUrl(user: User, fingerprint: string): string;
|
|
330
|
+
/** Payload of a password reset token valid for this panel, otherwise `null`. */
|
|
331
|
+
readResetPasswordToken(token: unknown): {
|
|
332
|
+
uid: string | number;
|
|
333
|
+
fp: string;
|
|
334
|
+
} | null;
|
|
335
|
+
getVerifyEmailUrl(user: User): string;
|
|
336
|
+
checkVerifyEmailUrl(id: string, hash: string, expires: unknown, signature: unknown): boolean;
|
|
337
|
+
getEmailVerificationPromptUrl(): string;
|
|
338
|
+
getProfileUrl(): string | null;
|
|
339
|
+
/** Whether the user must still verify their email before using the panel. */
|
|
340
|
+
mustVerifyEmail(user: User | null): Promise<boolean>;
|
|
341
|
+
private _tenant;
|
|
342
|
+
private _tenantOwnershipColumn;
|
|
343
|
+
private _tenantRegistration;
|
|
344
|
+
private _tenantProfile;
|
|
345
|
+
private _tenantMenu;
|
|
346
|
+
private _tenantMenuItems;
|
|
347
|
+
private _tenantScope;
|
|
348
|
+
/**
|
|
349
|
+
* Makes the panel multi-tenant. `ownershipColumn` is the column linking a record to its tenant (`team_id`);
|
|
350
|
+
* the panel's resources then only read and write the current tenant's records (see `Resource.isScopedToTenant`).
|
|
351
|
+
*/
|
|
352
|
+
tenant(provider: TenantProvider | null, options?: {
|
|
353
|
+
ownershipColumn?: string;
|
|
354
|
+
}): this;
|
|
355
|
+
hasTenancy(): boolean;
|
|
356
|
+
getTenantProvider(): TenantProvider;
|
|
357
|
+
getTenantOwnershipColumn(): string | null;
|
|
358
|
+
/** Tenant registration page (`/new`). */
|
|
359
|
+
tenantRegistration(page: typeof RegisterTenant | null): this;
|
|
360
|
+
getTenantRegistrationPage(): typeof RegisterTenant | null;
|
|
361
|
+
/** Tenant profile page (`/<tenant>/profile`). */
|
|
362
|
+
tenantProfile(page: typeof EditTenantProfile | null): this;
|
|
363
|
+
getTenantProfilePage(): typeof EditTenantProfile | null;
|
|
364
|
+
tenantMenu(condition?: boolean): this;
|
|
365
|
+
hasTenantMenu(): boolean;
|
|
366
|
+
tenantMenuItems(items: Record<string, Action> | Action[]): this;
|
|
367
|
+
getTenantMenuItems(): Record<string, Action>;
|
|
368
|
+
/** Runs `fn` for a tenant: generated URLs (`getUrl`) and resource queries are scoped to it. */
|
|
369
|
+
withTenant<T>(tenant: unknown, fn: () => T): T;
|
|
370
|
+
/** Tenant of the current request, or `null`. */
|
|
371
|
+
getTenant<T = any>(): T | null;
|
|
372
|
+
getTenantUrlKey(tenant: unknown): string;
|
|
373
|
+
private _subNavigationPosition;
|
|
374
|
+
/** Default position of page sub-navigation (`start`). */
|
|
375
|
+
subNavigationPosition(position: 'start' | 'end' | 'top'): this;
|
|
376
|
+
getSubNavigationPosition(): 'start' | 'end' | 'top';
|
|
377
|
+
private _appUrl;
|
|
378
|
+
/** Public URL of the application (`https://example.com`), used in emailed links. Without it the request origin is used, which should be avoided in production (the `Host` header can be forged). */
|
|
379
|
+
appUrl(url: string | null): this;
|
|
380
|
+
getAppUrl(): string | null;
|
|
381
|
+
getMaxContentWidth(): string;
|
|
382
|
+
/** URL inside the panel; in a multi-tenant panel, prefixed with the current (or given) tenant. */
|
|
383
|
+
getUrl(sub?: string, tenant?: unknown): string;
|
|
384
|
+
/** URL outside any tenant (login, registration, profile, tenant registration). */
|
|
385
|
+
getBaseUrl(sub?: string): string;
|
|
386
|
+
getLoginUrl(): string;
|
|
387
|
+
getLogoutUrl(): string;
|
|
388
|
+
/** Prefix of this panel's Livewire endpoint (`/livewire` or `/<path>/livewire`): each panel has its own. */
|
|
389
|
+
getLivewirePrefix(): string;
|
|
390
|
+
assetUrl(file: string): string;
|
|
391
|
+
getBrand(): Record<string, unknown>;
|
|
392
|
+
getFont(): typeof this._font;
|
|
393
|
+
/** Default avatar: the name's initials from the external ui-avatars.com service. */
|
|
394
|
+
getUserAvatarUrl(user: User): string;
|
|
395
|
+
/** Tenant avatar: from the tenant provider (`getAvatarUrl`), otherwise its initials. */
|
|
396
|
+
getTenantAvatarUrl(tenant: unknown): string;
|
|
397
|
+
private _spa;
|
|
398
|
+
/** SPA mode: navigate between panel pages without full reloads (`wire:navigate`). */
|
|
399
|
+
spa(condition?: boolean): this;
|
|
400
|
+
hasSpaMode(): boolean;
|
|
401
|
+
getAvatarUrlFor(name: string): string;
|
|
402
|
+
/** Navigation groups: registered pages plus custom items, sorted, grouped in the declared order. */
|
|
403
|
+
/** Computed navigation badges: page URL → value. */
|
|
404
|
+
resolveNavigationBadges(): Promise<Map<string, string | number | null>>;
|
|
405
|
+
/** URLs of menu pages this user cannot open. */
|
|
406
|
+
resolveInaccessiblePages(user: User | null): Promise<Set<string>>;
|
|
407
|
+
getNavigation(path: string, badges?: Map<string, string | number | null>, hidden?: Set<string>): {
|
|
408
|
+
label: string | null;
|
|
409
|
+
itemsId: string;
|
|
410
|
+
isActive: boolean;
|
|
411
|
+
items: {
|
|
412
|
+
label: string;
|
|
413
|
+
url: string;
|
|
414
|
+
icon: string | null;
|
|
415
|
+
isActive: boolean;
|
|
416
|
+
badge: string | number | null;
|
|
417
|
+
badgeColorClasses: string[];
|
|
418
|
+
}[];
|
|
419
|
+
}[];
|
|
420
|
+
private sign;
|
|
421
|
+
logIn(res: Response, user: User, remember: boolean): void;
|
|
422
|
+
logOut(res: Response): void;
|
|
423
|
+
user(req: Request): Promise<User | null>;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Render hook locations of a panel. A few are declared but not rendered anywhere yet: see `UNPLACED_RENDER_HOOKS`.
|
|
427
|
+
*/
|
|
428
|
+
export declare const PanelsRenderHook: {
|
|
429
|
+
readonly AUTH_LOGIN_FORM_AFTER: "panels::auth.login.form.after";
|
|
430
|
+
readonly AUTH_LOGIN_FORM_BEFORE: "panels::auth.login.form.before";
|
|
431
|
+
readonly AUTH_PASSWORD_RESET_REQUEST_FORM_AFTER: "panels::auth.password-reset.request.form.after";
|
|
432
|
+
readonly AUTH_PASSWORD_RESET_REQUEST_FORM_BEFORE: "panels::auth.password-reset.request.form.before";
|
|
433
|
+
readonly AUTH_PASSWORD_RESET_RESET_FORM_AFTER: "panels::auth.password-reset.reset.form.after";
|
|
434
|
+
readonly AUTH_PASSWORD_RESET_RESET_FORM_BEFORE: "panels::auth.password-reset.reset.form.before";
|
|
435
|
+
readonly AUTH_REGISTER_FORM_AFTER: "panels::auth.register.form.after";
|
|
436
|
+
readonly AUTH_REGISTER_FORM_BEFORE: "panels::auth.register.form.before";
|
|
437
|
+
readonly BODY_END: "panels::body.end";
|
|
438
|
+
readonly BODY_START: "panels::body.start";
|
|
439
|
+
readonly CONTENT_AFTER: "panels::content.after";
|
|
440
|
+
readonly CONTENT_BEFORE: "panels::content.before";
|
|
441
|
+
readonly CONTENT_END: "panels::content.end";
|
|
442
|
+
readonly CONTENT_START: "panels::content.start";
|
|
443
|
+
readonly FOOTER: "panels::footer";
|
|
444
|
+
readonly GLOBAL_SEARCH_AFTER: "panels::global-search.after";
|
|
445
|
+
readonly GLOBAL_SEARCH_BEFORE: "panels::global-search.before";
|
|
446
|
+
readonly GLOBAL_SEARCH_END: "panels::global-search.end";
|
|
447
|
+
readonly GLOBAL_SEARCH_START: "panels::global-search.start";
|
|
448
|
+
readonly HEAD_END: "panels::head.end";
|
|
449
|
+
readonly HEAD_START: "panels::head.start";
|
|
450
|
+
readonly LAYOUT_END: "panels::layout.end";
|
|
451
|
+
readonly LAYOUT_START: "panels::layout.start";
|
|
452
|
+
readonly PAGE_END: "panels::page.end";
|
|
453
|
+
readonly PAGE_FOOTER_WIDGETS_AFTER: "panels::page.footer-widgets.after";
|
|
454
|
+
readonly PAGE_FOOTER_WIDGETS_BEFORE: "panels::page.footer-widgets.before";
|
|
455
|
+
readonly PAGE_FOOTER_WIDGETS_END: "panels::page.footer-widgets.end";
|
|
456
|
+
readonly PAGE_FOOTER_WIDGETS_START: "panels::page.footer-widgets.start";
|
|
457
|
+
readonly PAGE_HEADER_ACTIONS_AFTER: "panels::page.header.actions.after";
|
|
458
|
+
readonly PAGE_HEADER_ACTIONS_BEFORE: "panels::page.header.actions.before";
|
|
459
|
+
readonly PAGE_HEADER_HEADING_AFTER: "panels::page.header.heading.after";
|
|
460
|
+
readonly PAGE_HEADER_HEADING_BEFORE: "panels::page.header.heading.before";
|
|
461
|
+
readonly PAGE_HEADER_WIDGETS_AFTER: "panels::page.header-widgets.after";
|
|
462
|
+
readonly PAGE_HEADER_WIDGETS_BEFORE: "panels::page.header-widgets.before";
|
|
463
|
+
readonly PAGE_HEADER_WIDGETS_END: "panels::page.header-widgets.end";
|
|
464
|
+
readonly PAGE_HEADER_WIDGETS_START: "panels::page.header-widgets.start";
|
|
465
|
+
readonly PAGE_START: "panels::page.start";
|
|
466
|
+
/** The hook name says "module-menu", not "mobile-menu": kept for compatibility. */
|
|
467
|
+
readonly PAGE_SUB_NAVIGATION_MOBILE_MENU_AFTER: "panels::page.sub-navigation.module-menu.after";
|
|
468
|
+
readonly PAGE_SUB_NAVIGATION_MOBILE_MENU_BEFORE: "panels::page.sub-navigation.module-menu.before";
|
|
469
|
+
readonly PAGE_SUB_NAVIGATION_SIDEBAR_AFTER: "panels::page.sub-navigation.sidebar.after";
|
|
470
|
+
readonly PAGE_SUB_NAVIGATION_SIDEBAR_BEFORE: "panels::page.sub-navigation.sidebar.before";
|
|
471
|
+
readonly PAGE_SUB_NAVIGATION_START_AFTER: "panels::page.sub-navigation.start.after";
|
|
472
|
+
readonly PAGE_SUB_NAVIGATION_START_BEFORE: "panels::page.sub-navigation.start.before";
|
|
473
|
+
readonly PAGE_SUB_NAVIGATION_TOP_AFTER: "panels::page.sub-navigation.top.after";
|
|
474
|
+
readonly PAGE_SUB_NAVIGATION_TOP_BEFORE: "panels::page.sub-navigation.top.before";
|
|
475
|
+
readonly PAGE_SUB_NAVIGATION_END_AFTER: "panels::page.sub-navigation.end.after";
|
|
476
|
+
readonly PAGE_SUB_NAVIGATION_END_BEFORE: "panels::page.sub-navigation.end.before";
|
|
477
|
+
readonly RESOURCE_PAGES_LIST_RECORDS_TABLE_AFTER: "panels::resource.pages.list-records.table.after";
|
|
478
|
+
readonly RESOURCE_PAGES_LIST_RECORDS_TABLE_BEFORE: "panels::resource.pages.list-records.table.before";
|
|
479
|
+
readonly RESOURCE_PAGES_LIST_RECORDS_TABS_END: "panels::resource.pages.list-records.tabs.end";
|
|
480
|
+
readonly RESOURCE_PAGES_LIST_RECORDS_TABS_START: "panels::resource.pages.list-records.tabs.start";
|
|
481
|
+
readonly RESOURCE_PAGES_MANAGE_RELATED_RECORDS_TABLE_AFTER: "panels::resource.pages.manage-related-records.table.after";
|
|
482
|
+
readonly RESOURCE_PAGES_MANAGE_RELATED_RECORDS_TABLE_BEFORE: "panels::resource.pages.manage-related-records.table.before";
|
|
483
|
+
readonly RESOURCE_RELATION_MANAGER_AFTER: "panels::resource.relation-manager.after";
|
|
484
|
+
readonly RESOURCE_RELATION_MANAGER_BEFORE: "panels::resource.relation-manager.before";
|
|
485
|
+
readonly RESOURCE_TABS_END: "panels::resource.tabs.end";
|
|
486
|
+
readonly RESOURCE_TABS_START: "panels::resource.tabs.start";
|
|
487
|
+
readonly SCRIPTS_AFTER: "panels::scripts.after";
|
|
488
|
+
readonly SCRIPTS_BEFORE: "panels::scripts.before";
|
|
489
|
+
readonly SIDEBAR_FOOTER: "panels::sidebar.footer";
|
|
490
|
+
readonly SIDEBAR_LOGO_AFTER: "panels::sidebar.logo.after";
|
|
491
|
+
readonly SIDEBAR_LOGO_BEFORE: "panels::sidebar.logo.before";
|
|
492
|
+
readonly SIDEBAR_START: "panels::sidebar.start";
|
|
493
|
+
readonly SIDEBAR_NAV_END: "panels::sidebar.nav.end";
|
|
494
|
+
readonly SIDEBAR_NAV_START: "panels::sidebar.nav.start";
|
|
495
|
+
readonly SIMPLE_LAYOUT_END: "panels::simple-layout.end";
|
|
496
|
+
readonly SIMPLE_LAYOUT_START: "panels::simple-layout.start";
|
|
497
|
+
readonly SIMPLE_PAGE_END: "panels::simple-page.end";
|
|
498
|
+
readonly SIMPLE_PAGE_START: "panels::simple-page.start";
|
|
499
|
+
readonly STYLES_AFTER: "panels::styles.after";
|
|
500
|
+
readonly STYLES_BEFORE: "panels::styles.before";
|
|
501
|
+
readonly TENANT_MENU_AFTER: "panels::tenant-menu.after";
|
|
502
|
+
readonly TENANT_MENU_BEFORE: "panels::tenant-menu.before";
|
|
503
|
+
readonly TOPBAR_AFTER: "panels::topbar.after";
|
|
504
|
+
readonly TOPBAR_BEFORE: "panels::topbar.before";
|
|
505
|
+
readonly TOPBAR_END: "panels::topbar.end";
|
|
506
|
+
readonly TOPBAR_LOGO_AFTER: "panels::topbar.logo.after";
|
|
507
|
+
readonly TOPBAR_LOGO_BEFORE: "panels::topbar.logo.before";
|
|
508
|
+
readonly TOPBAR_START: "panels::topbar.start";
|
|
509
|
+
readonly USER_MENU_AFTER: "panels::user-menu.after";
|
|
510
|
+
readonly USER_MENU_BEFORE: "panels::user-menu.before";
|
|
511
|
+
readonly USER_MENU_PROFILE_AFTER: "panels::user-menu.profile.after";
|
|
512
|
+
readonly USER_MENU_PROFILE_BEFORE: "panels::user-menu.profile.before";
|
|
513
|
+
};
|
|
514
|
+
/** Widget render hook locations, rendered by `TableWidget`. */
|
|
515
|
+
export declare const WidgetsRenderHook: {
|
|
516
|
+
readonly TABLE_WIDGET_END: "widgets::table-widget.end";
|
|
517
|
+
readonly TABLE_WIDGET_START: "widgets::table-widget.start";
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Hook locations that are declared but not rendered anywhere yet, with the reason.
|
|
521
|
+
*/
|
|
522
|
+
export declare const UNPLACED_RENDER_HOOKS: Record<string, string>;
|
|
523
|
+
/** Common base: a stateful component hosting schemas (`<name>Schema(schema)`). */
|
|
524
|
+
declare abstract class BasePage extends Component implements SchemaHost {
|
|
525
|
+
get panel(): Panel;
|
|
526
|
+
getSchema(name: string): Schema;
|
|
527
|
+
contentSchema(schema: Schema): Schema;
|
|
528
|
+
/** Render hook scopes of this page: its class (and its resource, for a resource page). */
|
|
529
|
+
getRenderHookScopes(): unknown[];
|
|
530
|
+
}
|
|
531
|
+
/** A panel page, in the full layout (sidebar, header). */
|
|
532
|
+
export declare class Page extends BasePage {
|
|
533
|
+
/** Methods the browser may call. A subclass adds its own: `static callable = ['approve']`. */
|
|
534
|
+
static callable: string[];
|
|
535
|
+
static slug: string;
|
|
536
|
+
static title: string | null;
|
|
537
|
+
static navigationLabel: string | null;
|
|
538
|
+
static navigationIcon: string | null;
|
|
539
|
+
static navigationGroup: string | null;
|
|
540
|
+
static navigationSort: number;
|
|
541
|
+
static navigationBadge: string | number | null;
|
|
542
|
+
static navigationBadgeColor: string;
|
|
543
|
+
static shouldRegisterNavigation: boolean;
|
|
544
|
+
/** Restricts the page to some users: returning `false` hides it from the menu and denies it (403). */
|
|
545
|
+
static canAccess(_user: User): boolean | Promise<boolean>;
|
|
546
|
+
static getTitle(): string;
|
|
547
|
+
static getNavigationLabel(): string;
|
|
548
|
+
/** Every request, including browser updates, requires an authenticated user: a snapshot kept after logout is not enough. */
|
|
549
|
+
boot(): Promise<void>;
|
|
550
|
+
protected isAccessAuthorized(ctx: PanelContext): boolean | Promise<boolean>;
|
|
551
|
+
getTitle(): string;
|
|
552
|
+
getHeading(): string;
|
|
553
|
+
getBreadcrumbs(): {
|
|
554
|
+
label: string;
|
|
555
|
+
url: string | null;
|
|
556
|
+
}[];
|
|
557
|
+
getHeaderActions(): Action[];
|
|
558
|
+
getPageClasses(): string[];
|
|
559
|
+
/** Page sub-navigation; empty by default. */
|
|
560
|
+
getSubNavigation(): SubNavigationItem[] | Promise<SubNavigationItem[]>;
|
|
561
|
+
/** Sub-navigation position: `start` (column before the content), `end` (after) or `top` (tabs). Defaults to the resource's, then the panel's. */
|
|
562
|
+
static subNavigationPosition: 'start' | 'end' | 'top' | null;
|
|
563
|
+
getSubNavigationPosition(): 'start' | 'end' | 'top';
|
|
564
|
+
/** Widgets shown below the page content. */
|
|
565
|
+
getFooterWidgets(): (typeof Widget)[];
|
|
566
|
+
getFooterWidgetsColumns(): number | Record<string, number>;
|
|
567
|
+
/** Footer widget grid, in the page's `footerWidgets` schema. */
|
|
568
|
+
protected renderFooterWidgets(): Promise<string>;
|
|
569
|
+
/** Widgets shown above the page content, with the data passed to each (widget properties). */
|
|
570
|
+
getHeaderWidgets(): (typeof Widget)[];
|
|
571
|
+
getHeaderWidgetsColumns(): number;
|
|
572
|
+
getWidgetData(): Record<string, unknown>;
|
|
573
|
+
/** Header widget grid, in the page's `headerWidgets` schema. */
|
|
574
|
+
protected renderHeaderWidgets(): Promise<string>;
|
|
575
|
+
/** Widgets the current user is allowed to see. */
|
|
576
|
+
protected filterVisibleWidgets(candidates: (typeof Widget)[]): Promise<(typeof Widget)[]>;
|
|
577
|
+
/** Widget grid of a schema: each widget is a child component, lazy-loaded by default. */
|
|
578
|
+
protected renderWidgetsGrid(widgets: (typeof Widget)[], columns: number | Record<string, number>, schemaKey: string): Promise<string>;
|
|
579
|
+
/** Page content: its `content` schema by default. */
|
|
580
|
+
protected renderContent(): Promise<string>;
|
|
581
|
+
mountedActions: {
|
|
582
|
+
name: string;
|
|
583
|
+
arguments: Record<string, unknown>;
|
|
584
|
+
context: Record<string, unknown>;
|
|
585
|
+
data?: Record<string, unknown>;
|
|
586
|
+
}[];
|
|
587
|
+
getActionMountContext(): Record<string, unknown>;
|
|
588
|
+
protected getActionRecord(): unknown;
|
|
589
|
+
/** Record targeted by an action mounted in a given context (table row…). */
|
|
590
|
+
protected resolveActionRecord(_context: Record<string, unknown>): Promise<unknown>;
|
|
591
|
+
/** Actions that can be mounted in a given context (page header by default). */
|
|
592
|
+
protected getMountableActions(context: Record<string, unknown>): Action[] | Promise<Action[]>;
|
|
593
|
+
/**
|
|
594
|
+
* Actions owned by a schema component (Repeater: add, delete, move; Section: header actions).
|
|
595
|
+
* The key comes from the browser: it must match a real component of the schema, or the schema itself.
|
|
596
|
+
*/
|
|
597
|
+
protected getSchemaComponentActions(key: string): Promise<Action[]>;
|
|
598
|
+
/** Context kept for a mounted action: the server's, never the browser's as-is. */
|
|
599
|
+
protected resolveMountContext(clientContext: unknown): Record<string, unknown>;
|
|
600
|
+
private findMountableAction;
|
|
601
|
+
private actionContext;
|
|
602
|
+
/** Form schema of a mounted action: key `mountedActionSchema<n>`, state under `mountedActions.<n>.data`. */
|
|
603
|
+
getMountedActionSchema(index: number): Promise<Schema | null>;
|
|
604
|
+
private renderActionModal;
|
|
605
|
+
/** Cancels a partial modal render prepared by a live field when the same request then runs an action. */
|
|
606
|
+
private cancelModalPartialRender;
|
|
607
|
+
/** Live field in a mounted action's form: runs `afterStateUpdated`, then only returns the affected modal. */
|
|
608
|
+
updatedMountedActions(_value: unknown, key: string | null): Promise<void>;
|
|
609
|
+
/** Calls a method exposed by a field, from that field's JavaScript (e.g. Select search). Does not re-render. */
|
|
610
|
+
callSchemaComponentMethod(componentKey: unknown, method: unknown, args?: unknown): Promise<unknown>;
|
|
611
|
+
/** A hidden action can be neither mounted nor run, even through a call forged by the browser. */
|
|
612
|
+
private assertActionVisible;
|
|
613
|
+
private syncActionModals;
|
|
614
|
+
/** False for a table component: its modals are rendered inside the table. */
|
|
615
|
+
protected rendersActionModalsInPage(): boolean;
|
|
616
|
+
renderActionModals(): Promise<string>;
|
|
617
|
+
/** Mounts an action: without a modal it runs immediately; with one, only the modals fragment is returned. */
|
|
618
|
+
mountAction(name: unknown, args?: unknown, _context?: unknown): Promise<void>;
|
|
619
|
+
unmountAction(_shouldCancelParentActions?: unknown): void;
|
|
620
|
+
callMountedAction(_args?: unknown): Promise<void>;
|
|
621
|
+
render(): Promise<string>;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Dashboard: a widget grid, preceded by a filters form when the page defines `filtersFormSchema(schema)`.
|
|
625
|
+
* The filters are passed to widgets as `pageFilters`.
|
|
626
|
+
*/
|
|
627
|
+
export declare class Dashboard extends Page {
|
|
628
|
+
static slug: string;
|
|
629
|
+
static title: string;
|
|
630
|
+
static navigationIcon: string;
|
|
631
|
+
static navigationSort: number;
|
|
632
|
+
/** Filters form state. Stays `null` while the page has no filters. */
|
|
633
|
+
filters: Record<string, unknown> | null;
|
|
634
|
+
/** Dashboard widgets. Defaults to the panel's (`panel.widgets([...])`). */
|
|
635
|
+
getWidgets(): (typeof Widget)[];
|
|
636
|
+
/** Grid columns: a number (at the `lg` breakpoint), or one number per breakpoint. */
|
|
637
|
+
getColumns(): number | Record<string, number>;
|
|
638
|
+
hasFiltersForm(): boolean;
|
|
639
|
+
getSchema(name: string): Schema;
|
|
640
|
+
mount(): void;
|
|
641
|
+
getWidgetData(): Record<string, unknown>;
|
|
642
|
+
protected renderContent(): Promise<string>;
|
|
643
|
+
}
|
|
644
|
+
/** In-memory rate limiter: `max` attempts per window, per key. Fine for a single instance; use a shared store when running several. */
|
|
645
|
+
export declare class Throttle {
|
|
646
|
+
private hits;
|
|
647
|
+
private max;
|
|
648
|
+
private windowMs;
|
|
649
|
+
constructor(max?: number, windowMs?: number);
|
|
650
|
+
/** Records an attempt; returns 0 if allowed, otherwise the number of seconds to wait. */
|
|
651
|
+
hit(key: string, now?: number): number;
|
|
652
|
+
clear(key: string): void;
|
|
653
|
+
}
|
|
654
|
+
/** Page with the simple layout (login, registration…). */
|
|
655
|
+
export declare abstract class SimplePage extends BasePage {
|
|
656
|
+
abstract getTitle(): string;
|
|
657
|
+
getHeading(): string | null;
|
|
658
|
+
/** Subheading, as trusted HTML (built by the page, with data escaped). */
|
|
659
|
+
getSubheading(): string | null;
|
|
660
|
+
hasLogo(): boolean;
|
|
661
|
+
render(): Promise<string>;
|
|
662
|
+
}
|
|
663
|
+
/** Registration page: name, email, confirmed password. The user is logged in, then asked to verify their email if the panel requires it. */
|
|
664
|
+
export declare class Register extends SimplePage {
|
|
665
|
+
static callable: string[];
|
|
666
|
+
data: Record<string, unknown>;
|
|
667
|
+
mount(): void;
|
|
668
|
+
getTitle(): string;
|
|
669
|
+
getHeading(): string;
|
|
670
|
+
getSubheading(): string | null;
|
|
671
|
+
formSchema(schema: Schema): Schema;
|
|
672
|
+
contentSchema(schema: Schema): Schema;
|
|
673
|
+
/** Validated data, just before creation (add a value, normalize the email…). */
|
|
674
|
+
protected mutateFormDataBeforeRegister(data: Record<string, unknown>): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
675
|
+
/** Creates the user; defaults to the auth provider's `create()`. */
|
|
676
|
+
protected handleRegistration(data: Record<string, unknown>): Promise<User> | User;
|
|
677
|
+
register(): Promise<void>;
|
|
678
|
+
}
|
|
679
|
+
/** Password reset request page: a signed link, valid for 60 minutes, is sent by email. */
|
|
680
|
+
export declare class RequestPasswordReset extends SimplePage {
|
|
681
|
+
static callable: string[];
|
|
682
|
+
data: Record<string, unknown>;
|
|
683
|
+
mount(): void;
|
|
684
|
+
getTitle(): string;
|
|
685
|
+
getHeading(): string;
|
|
686
|
+
getSubheading(): string | null;
|
|
687
|
+
formSchema(schema: Schema): Schema;
|
|
688
|
+
contentSchema(schema: Schema): Schema;
|
|
689
|
+
request(): Promise<void>;
|
|
690
|
+
}
|
|
691
|
+
/** Sets a new password from the emailed link. The link works once: it dies with the old password. */
|
|
692
|
+
export declare class ResetPassword extends SimplePage {
|
|
693
|
+
static callable: string[];
|
|
694
|
+
static locked: string[];
|
|
695
|
+
email: string | null;
|
|
696
|
+
password: string;
|
|
697
|
+
passwordConfirmation: string;
|
|
698
|
+
token: string | null;
|
|
699
|
+
mount(params: Record<string, unknown>): void;
|
|
700
|
+
/** The form has no state path: its fields are page properties. */
|
|
701
|
+
getSchema(name: string): Schema;
|
|
702
|
+
getTitle(): string;
|
|
703
|
+
getHeading(): string;
|
|
704
|
+
formSchema(schema: Schema): Schema;
|
|
705
|
+
contentSchema(schema: Schema): Schema;
|
|
706
|
+
resetPassword(): Promise<void>;
|
|
707
|
+
}
|
|
708
|
+
/** Email verification prompt, with a "Resend it." link. */
|
|
709
|
+
export declare class EmailVerificationPrompt extends SimplePage {
|
|
710
|
+
static callable: string[];
|
|
711
|
+
mount(): Promise<void>;
|
|
712
|
+
getTitle(): string;
|
|
713
|
+
getHeading(): string;
|
|
714
|
+
contentSchema(schema: Schema): Schema;
|
|
715
|
+
/** The page's only action: resend the email (at most twice per minute). */
|
|
716
|
+
mountAction(name: unknown): Promise<void>;
|
|
717
|
+
}
|
|
718
|
+
/** User profile page: name, email, new password. The current password is required to change the email or password. */
|
|
719
|
+
export declare class EditProfile extends SimplePage {
|
|
720
|
+
static callable: string[];
|
|
721
|
+
static slug: string;
|
|
722
|
+
data: Record<string, unknown>;
|
|
723
|
+
static getLabel(): string;
|
|
724
|
+
mount(): Promise<void>;
|
|
725
|
+
boot(): Promise<void>;
|
|
726
|
+
getTitle(): string;
|
|
727
|
+
hasLogo(): boolean;
|
|
728
|
+
formSchema(schema: Schema): Schema;
|
|
729
|
+
contentSchema(schema: Schema): Schema;
|
|
730
|
+
save(): Promise<void>;
|
|
731
|
+
}
|
|
732
|
+
/** Tenant registration page: the subclass provides its label and form (`formSchema`). */
|
|
733
|
+
export declare abstract class RegisterTenant extends SimplePage {
|
|
734
|
+
static callable: string[];
|
|
735
|
+
static slug: string;
|
|
736
|
+
data: Record<string, unknown>;
|
|
737
|
+
static getLabel(): string;
|
|
738
|
+
/** Whether tenants can be created; by default, if the tenant provider implements `create`. */
|
|
739
|
+
static canView(panel: Panel, _user: User): boolean | Promise<boolean>;
|
|
740
|
+
boot(): Promise<void>;
|
|
741
|
+
mount(): void;
|
|
742
|
+
getTitle(): string;
|
|
743
|
+
hasLogo(): boolean;
|
|
744
|
+
formSchema(schema: Schema): Schema;
|
|
745
|
+
contentSchema(schema: Schema): Schema;
|
|
746
|
+
protected mutateFormDataBeforeRegister(data: Record<string, unknown>): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
747
|
+
protected handleRegistration(data: Record<string, unknown>): unknown;
|
|
748
|
+
register(): Promise<void>;
|
|
749
|
+
}
|
|
750
|
+
/** Current tenant's profile page, in the full layout. */
|
|
751
|
+
export declare abstract class EditTenantProfile extends Page {
|
|
752
|
+
static callable: string[];
|
|
753
|
+
static slug: string;
|
|
754
|
+
static shouldRegisterNavigation: boolean;
|
|
755
|
+
data: Record<string, unknown>;
|
|
756
|
+
static getLabel(): string;
|
|
757
|
+
static getTitle(): string;
|
|
758
|
+
protected isAccessAuthorized(ctx: PanelContext): boolean | Promise<boolean>;
|
|
759
|
+
mount(): void;
|
|
760
|
+
formSchema(schema: Schema): Schema;
|
|
761
|
+
contentSchema(schema: Schema): Schema;
|
|
762
|
+
save(): Promise<void>;
|
|
763
|
+
}
|
|
764
|
+
export declare class Login extends SimplePage {
|
|
765
|
+
static callable: string[];
|
|
766
|
+
data: Record<string, unknown>;
|
|
767
|
+
mount(): void;
|
|
768
|
+
getTitle(): string;
|
|
769
|
+
getHeading(): string;
|
|
770
|
+
getSubheading(): string | null;
|
|
771
|
+
formSchema(schema: Schema): Schema;
|
|
772
|
+
contentSchema(schema: Schema): Schema;
|
|
773
|
+
authenticate(): Promise<void>;
|
|
774
|
+
}
|
|
775
|
+
/** Whether the host component's user has this ability on the component's resource (or relation manager). Use it in your actions' `authorize()`. */
|
|
776
|
+
export declare const can: (livewire: unknown, ability: string, record?: unknown) => Promise<boolean> | boolean;
|
|
777
|
+
/** Resource: a model with its pages, table and navigation. */
|
|
778
|
+
export declare abstract class Resource {
|
|
779
|
+
static panel: Panel;
|
|
780
|
+
static slug: string;
|
|
781
|
+
static modelLabel: string;
|
|
782
|
+
static pluralModelLabel: string | null;
|
|
783
|
+
static navigationIcon: string | null;
|
|
784
|
+
static navigationGroup: string | null;
|
|
785
|
+
static navigationSort: number;
|
|
786
|
+
static navigationBadge: string | number | null;
|
|
787
|
+
static adapter: DataAdapter;
|
|
788
|
+
/** In a multi-tenant panel, whether records belong to each tenant (`true` by default). */
|
|
789
|
+
static isScopedToTenant: boolean;
|
|
790
|
+
/** Tenant column for this resource (defaults to the panel's: `panel.tenant(provider, { ownershipColumn })`). */
|
|
791
|
+
static tenantOwnershipColumn: string | null;
|
|
792
|
+
/**
|
|
793
|
+
* Resource pages; replace them with your subclasses to change their behavior:
|
|
794
|
+
* `static pages = { index: MyList, create: MyCreate, edit: MyEdit }`.
|
|
795
|
+
*/
|
|
796
|
+
static pages: {
|
|
797
|
+
index?: typeof ListRecords;
|
|
798
|
+
create?: typeof CreateRecord;
|
|
799
|
+
edit?: typeof EditRecord;
|
|
800
|
+
view?: typeof ViewRecord;
|
|
801
|
+
};
|
|
802
|
+
/** `true` adds a view page (`ViewRecord`) to the resource; table rows then link to it. */
|
|
803
|
+
static hasViewPage: boolean;
|
|
804
|
+
/** Who can do what on this resource. Without a policy, any signed-in user can do everything. */
|
|
805
|
+
static policy: Policy | null;
|
|
806
|
+
/** Whether the user has this ability (on this record, if any). */
|
|
807
|
+
static can(ability: string, user: User | null, record?: unknown): Promise<boolean>;
|
|
808
|
+
/** Resource widgets, registered as components. */
|
|
809
|
+
static widgets: (typeof Widget)[];
|
|
810
|
+
/** Widgets shown above the table on the list page. */
|
|
811
|
+
static headerWidgets: (typeof Widget)[];
|
|
812
|
+
/** Relation managers shown below the edit form. */
|
|
813
|
+
static relations: any[];
|
|
814
|
+
/** Tabs of the list page. */
|
|
815
|
+
static tabs(): Record<string, Tab>;
|
|
816
|
+
/** Simple resource: a single page, with create and edit in modals. */
|
|
817
|
+
static isSimple: boolean;
|
|
818
|
+
static getPluralModelLabel(): string;
|
|
819
|
+
static getTitleCasePluralModelLabel(): string;
|
|
820
|
+
static getUrl(page?: string, record?: string | number): string;
|
|
821
|
+
/** Related records pages: `{ comments: ManagePostComments }` is served at `<slug>/{record}/comments`. */
|
|
822
|
+
static relatedPages: Record<string, typeof ManageRelatedRecords>;
|
|
823
|
+
/** Pages listed in a record's sub-navigation, in order: `['view', 'edit', 'comments']`. Empty: no sub-navigation. */
|
|
824
|
+
static recordSubNavigation: string[];
|
|
825
|
+
/** Record sub-navigation: one tab per declared page, the current page's tab active. */
|
|
826
|
+
static getRecordSubNavigation(page: {
|
|
827
|
+
getRecordKey(): string | null;
|
|
828
|
+
constructor: Function;
|
|
829
|
+
}): SubNavigationItem[];
|
|
830
|
+
private static _registered;
|
|
831
|
+
/** Page class actually registered under a name (pages are generated once per resource). */
|
|
832
|
+
static getRegisteredPage(name: string): typeof Page | undefined;
|
|
833
|
+
static table(table: Table): Table;
|
|
834
|
+
static form(schema: Schema): Schema;
|
|
835
|
+
/** Schema of the view page. */
|
|
836
|
+
static infolist(schema: Schema): Schema;
|
|
837
|
+
/** Columns searched by global search; defaults to the title attribute. Empty array: the resource is not searchable. */
|
|
838
|
+
static globallySearchableAttributes: string[] | null;
|
|
839
|
+
static getGloballySearchableAttributes(): string[];
|
|
840
|
+
static canGloballySearch(): boolean;
|
|
841
|
+
/** Position of this resource's group in the results; without one, after the others in registration order. */
|
|
842
|
+
static globalSearchSort: number | null;
|
|
843
|
+
/** Maximum results rendered per resource. */
|
|
844
|
+
static globalSearchResultsLimit: number;
|
|
845
|
+
static getGlobalSearchResultTitle(record: any): string;
|
|
846
|
+
/** Details shown under the title: `{ Author: 'Jane' }`. Empty values are skipped. */
|
|
847
|
+
static getGlobalSearchResultDetails(_record: any): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
848
|
+
/** URL of a result: the view page, otherwise the edit page; for a simple resource, the list with the action open. `null` if the user has no access. */
|
|
849
|
+
static getGlobalSearchResultUrl(record: any, user: User | null): Promise<string | null>;
|
|
850
|
+
static getGlobalSearchResults(search: string, user: User | null): Promise<GlobalSearchResult[]>;
|
|
851
|
+
/** Attribute used as a record's title. */
|
|
852
|
+
static recordTitleAttribute: string | null;
|
|
853
|
+
/** Without a title attribute: the model label in title case ("Leave Request"). */
|
|
854
|
+
static getRecordTitle(record: any): string;
|
|
855
|
+
/** Generated resource pages: list, create, edit. */
|
|
856
|
+
static getPages(): Record<string, typeof Page>;
|
|
857
|
+
private static buildPages;
|
|
858
|
+
}
|
|
859
|
+
/** Sub-navigation tab of a page. */
|
|
860
|
+
export type SubNavigationItem = {
|
|
861
|
+
label: string;
|
|
862
|
+
icon: string | null;
|
|
863
|
+
url: string;
|
|
864
|
+
active: boolean;
|
|
865
|
+
};
|
|
866
|
+
type ColumnSpan = number | 'full';
|
|
867
|
+
/** Widget: a component displayed in a page's widget grid. */
|
|
868
|
+
export declare abstract class Widget extends Component {
|
|
869
|
+
static componentName: string;
|
|
870
|
+
/** Width in the widget grid: a number of columns, or `'full'`. */
|
|
871
|
+
static columnSpan: ColumnSpan;
|
|
872
|
+
/** Loaded when it becomes visible. */
|
|
873
|
+
static isLazy: boolean;
|
|
874
|
+
get panel(): Panel;
|
|
875
|
+
/** Restricts the widget to some users: returning `false` removes it from the page and refuses to load it. */
|
|
876
|
+
static canView(_user: User): boolean | Promise<boolean>;
|
|
877
|
+
boot(): Promise<void>;
|
|
878
|
+
/** Grid column classes and style, at the `lg` breakpoint. */
|
|
879
|
+
protected gridColumn(): {
|
|
880
|
+
classes: string[];
|
|
881
|
+
style: string;
|
|
882
|
+
};
|
|
883
|
+
placeholder(): string;
|
|
884
|
+
/** Common widget wrapper. */
|
|
885
|
+
protected wrap(content: string, classes?: string[]): string;
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Calendar widget: month, week and list views, server-rendered navigation, no JavaScript library.
|
|
889
|
+
*
|
|
890
|
+
* Minimal use: extend the class and return the events of the displayed period.
|
|
891
|
+
*
|
|
892
|
+
* class LeaveCalendar extends CalendarWidget {
|
|
893
|
+
* static heading = 'Leave';
|
|
894
|
+
* async getEvents({ start, end }) { return [{ id: 1, title: 'Ada — vacation', start: '2026-11-12', end: '2026-11-14', color: 'success' }]; }
|
|
895
|
+
* }
|
|
896
|
+
*
|
|
897
|
+
* Everything else can be overridden method by method: available views, first day of the week, locale, labels, events
|
|
898
|
+
* per cell, day clicks (`onDateClick`) and event clicks (`onEventClick`), event rendering (`renderEvent`), cell footer
|
|
899
|
+
* (`renderDayFooter`), toolbar buttons (`renderToolbarEnd`), and appearance through the `.nv-cal` CSS variables
|
|
900
|
+
* (`getExtraClasses`, `getStyle`).
|
|
901
|
+
*/
|
|
902
|
+
export declare abstract class CalendarWidget extends Widget {
|
|
903
|
+
static columnSpan: ColumnSpan;
|
|
904
|
+
/** Heading shown before the period ("Leave — November 2026"). */
|
|
905
|
+
static heading: string | null;
|
|
906
|
+
static callable: string[];
|
|
907
|
+
/** View and date only change through the methods below, which validate them. */
|
|
908
|
+
static locked: string[];
|
|
909
|
+
view: CalendarView;
|
|
910
|
+
/** Anchor date (`YYYY-MM-DD`): the displayed month or week contains it. Empty: today. */
|
|
911
|
+
date: string;
|
|
912
|
+
/** Events overlapping `start`–`end` (inclusive, `YYYY-MM-DD`). Called on every render: filter in the database. */
|
|
913
|
+
abstract getEvents(range: {
|
|
914
|
+
start: string;
|
|
915
|
+
end: string;
|
|
916
|
+
view: CalendarView;
|
|
917
|
+
}): CalendarEvent[] | Promise<CalendarEvent[]>;
|
|
918
|
+
/** Available views; the first is the initial one. With a single view, the switcher is hidden. */
|
|
919
|
+
getViews(): CalendarView[];
|
|
920
|
+
/** 0 = Sunday, 1 = Monday… */
|
|
921
|
+
getFirstDayOfWeek(): number;
|
|
922
|
+
/** Locale for month and day names (`Intl`). */
|
|
923
|
+
getLocale(): string;
|
|
924
|
+
getLabels(): CalendarLabels;
|
|
925
|
+
/** In month view, beyond this number the cell shows "+N more" (which opens the list on that day). */
|
|
926
|
+
getMaxEventsPerDay(): number;
|
|
927
|
+
getHeading(): string | null;
|
|
928
|
+
/** Today's date, `YYYY-MM-DD` (UTC by default; override for another time zone). */
|
|
929
|
+
getToday(): string;
|
|
930
|
+
/** Click on a day number. Overriding this makes days clickable: open a page (`this.redirect`), notify, switch view… */
|
|
931
|
+
onDateClick(_date: string): void | Promise<void>;
|
|
932
|
+
/** Click on an event without a URL. The event is reloaded server-side, so `event.extra` is available. */
|
|
933
|
+
onEventClick(_event: CalendarEvent): void | Promise<void>;
|
|
934
|
+
/** Already-escaped HTML for an event, or `null` for the default rendering (`renderCalendarEvent`). */
|
|
935
|
+
renderEvent(_event: CalendarEvent, _context: {
|
|
936
|
+
day: string;
|
|
937
|
+
view: CalendarView;
|
|
938
|
+
}): string | null;
|
|
939
|
+
/** Already-escaped HTML appended to the bottom of each cell. */
|
|
940
|
+
renderDayFooter(_day: string, _events: CalendarEvent[]): string;
|
|
941
|
+
/** Already-escaped HTML at the end of the toolbar: a "New" link, a filter… */
|
|
942
|
+
renderToolbarEnd(): string;
|
|
943
|
+
/** Extra classes on the calendar, to hook your styles or override its CSS variables. */
|
|
944
|
+
getExtraClasses(): string[];
|
|
945
|
+
/** CSS variables set on the calendar: `{ '--nv-cal-day-min-height': '9rem' }`. */
|
|
946
|
+
getStyle(): Record<string, string>;
|
|
947
|
+
private anchor;
|
|
948
|
+
private currentView;
|
|
949
|
+
private shift;
|
|
950
|
+
previousPeriod(): void;
|
|
951
|
+
nextPeriod(): void;
|
|
952
|
+
goToToday(): void;
|
|
953
|
+
setView(view: unknown): void;
|
|
954
|
+
/** "+N more": the list view anchored on that day (or the week view if list is not available). */
|
|
955
|
+
showDay(date: unknown): void;
|
|
956
|
+
private datesClickable;
|
|
957
|
+
private eventsClickable;
|
|
958
|
+
selectDate(date: unknown): Promise<void>;
|
|
959
|
+
/** The id comes from the browser: the event is looked up among those of the displayed period, never trusted as-is. */
|
|
960
|
+
selectEvent(id: unknown): Promise<void>;
|
|
961
|
+
render(): Promise<string>;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Calendar page: the same calendar as `CalendarWidget`, on a full page, with actions — so modals, forms,
|
|
965
|
+
* confirmations and slide-overs.
|
|
966
|
+
*
|
|
967
|
+
* class Planning extends CalendarPage {
|
|
968
|
+
* static slug = 'planning';
|
|
969
|
+
* async getEvents({ start, end }) { return db('shifts').where('day', '>=', start).where('day', '<=', end)… }
|
|
970
|
+
* // Day click: a modal with a form, prefilled with the date.
|
|
971
|
+
* dateAction() {
|
|
972
|
+
* return Action.make('createShift').modalHeading('New shift')
|
|
973
|
+
* .schema([Select.make('employee_id').options(…).required(), DatePicker.make('day').required()])
|
|
974
|
+
* .fillForm(({ arguments: args }) => ({ day: CalendarPage.dateOf(args) }))
|
|
975
|
+
* .action(async ({ data }) => { await db('shifts').insert(data); Notification.make().success().title('Saved').send(); });
|
|
976
|
+
* }
|
|
977
|
+
* // Event click: another action; the event is reloaded server-side.
|
|
978
|
+
* eventAction() {
|
|
979
|
+
* return Action.make('editShift').schema([…])
|
|
980
|
+
* .fillForm(async ({ livewire, arguments: args }) => (await livewire.findEvent(args.event))?.extra ?? {})
|
|
981
|
+
* .action(async ({ livewire, arguments: args, data }) => { const event = await livewire.findEvent(args.event); if (event) await db('shifts').where({ id: event.id }).update(data); });
|
|
982
|
+
* }
|
|
983
|
+
* }
|
|
984
|
+
*
|
|
985
|
+
* Three ways to handle a click: a **URL** on the event (`url`: dedicated page), an **action** (modal),
|
|
986
|
+
* or **custom code** by overriding `onDateClick()` / `onEventClick()` (redirect, notify, write to the database, mount any
|
|
987
|
+
* action with `this.mountAction(name, arguments)`). `getHeaderActions()` adds buttons to the page header, and
|
|
988
|
+
* `getCalendarActions()` declares other actions mountable from your own rendering (`renderEvent`, `renderToolbarEnd`).
|
|
989
|
+
*/
|
|
990
|
+
export declare abstract class CalendarPage extends Page {
|
|
991
|
+
static callable: string[];
|
|
992
|
+
static locked: string[];
|
|
993
|
+
view: CalendarView;
|
|
994
|
+
date: string;
|
|
995
|
+
abstract getEvents(range: {
|
|
996
|
+
start: string;
|
|
997
|
+
end: string;
|
|
998
|
+
view: CalendarView;
|
|
999
|
+
}): CalendarEvent[] | Promise<CalendarEvent[]>;
|
|
1000
|
+
getViews(): CalendarView[];
|
|
1001
|
+
getFirstDayOfWeek(): number;
|
|
1002
|
+
getLocale(): string;
|
|
1003
|
+
getLabels(): CalendarLabels;
|
|
1004
|
+
getMaxEventsPerDay(): number;
|
|
1005
|
+
getCalendarHeading(): string | null;
|
|
1006
|
+
getToday(): string;
|
|
1007
|
+
renderEvent(_event: CalendarEvent, _context: {
|
|
1008
|
+
day: string;
|
|
1009
|
+
view: CalendarView;
|
|
1010
|
+
}): string | null;
|
|
1011
|
+
renderDayFooter(_day: string, _events: CalendarEvent[]): string;
|
|
1012
|
+
renderToolbarEnd(): string;
|
|
1013
|
+
getExtraClasses(): string[];
|
|
1014
|
+
getStyle(): Record<string, string>;
|
|
1015
|
+
/** Action opened on day click; it receives `arguments.date`. `null`: days are not clickable (unless `onDateClick` is overridden). */
|
|
1016
|
+
dateAction(): Action | null;
|
|
1017
|
+
/** Action opened on click on an event without a URL; it receives `arguments.event` (an id, to resolve with `findEvent`). */
|
|
1018
|
+
eventAction(): Action | null;
|
|
1019
|
+
/** Other actions mountable from your own HTML: `wire:click="mountAction('name', { … })"`. */
|
|
1020
|
+
getCalendarActions(): Action[];
|
|
1021
|
+
/** Opens `dateAction()` by default. Override to do something else (e.g. redirect to a create page). */
|
|
1022
|
+
onDateClick(date: string): Promise<void>;
|
|
1023
|
+
/** Opens `eventAction()` by default. The event has been resolved server-side before the call. */
|
|
1024
|
+
onEventClick(event: CalendarEvent): Promise<void>;
|
|
1025
|
+
/** Clicked date, read from an action's arguments. They come from the browser: only a valid date is returned. */
|
|
1026
|
+
static dateOf(args: Record<string, unknown> | null | undefined): string | null;
|
|
1027
|
+
/** Event of the displayed period with this id, or `null`. Never act on a received id without going through this. */
|
|
1028
|
+
findEvent(id: unknown): Promise<CalendarEvent | null>;
|
|
1029
|
+
protected getMountableActions(context: Record<string, unknown>): Promise<Action[]>;
|
|
1030
|
+
private firstDay;
|
|
1031
|
+
private anchor;
|
|
1032
|
+
private currentView;
|
|
1033
|
+
private shift;
|
|
1034
|
+
previousPeriod(): void;
|
|
1035
|
+
nextPeriod(): void;
|
|
1036
|
+
goToToday(): void;
|
|
1037
|
+
setView(view: unknown): void;
|
|
1038
|
+
showDay(date: unknown): void;
|
|
1039
|
+
private datesClickable;
|
|
1040
|
+
private eventsClickable;
|
|
1041
|
+
selectDate(date: unknown): Promise<void>;
|
|
1042
|
+
selectEvent(id: unknown): Promise<void>;
|
|
1043
|
+
protected renderContent(): Promise<string>;
|
|
1044
|
+
}
|
|
1045
|
+
/** Signed-in user's account: avatar, name, logout. */
|
|
1046
|
+
export declare class AccountWidget extends Widget {
|
|
1047
|
+
static isLazy: boolean;
|
|
1048
|
+
render(): string;
|
|
1049
|
+
}
|
|
1050
|
+
/** Navette version and useful links. */
|
|
1051
|
+
export declare class NavetteInfoWidget extends Widget {
|
|
1052
|
+
static isLazy: boolean;
|
|
1053
|
+
static homeUrl: string;
|
|
1054
|
+
static documentationUrl: string;
|
|
1055
|
+
static githubUrl: string;
|
|
1056
|
+
static version: string;
|
|
1057
|
+
render(): string;
|
|
1058
|
+
}
|
|
1059
|
+
/** One stat of a StatsOverviewWidget. */
|
|
1060
|
+
export declare class Stat {
|
|
1061
|
+
private _description;
|
|
1062
|
+
private _descriptionIcon;
|
|
1063
|
+
private _descriptionIconPosition;
|
|
1064
|
+
private _color;
|
|
1065
|
+
private _icon;
|
|
1066
|
+
private _chart;
|
|
1067
|
+
private _url;
|
|
1068
|
+
private label;
|
|
1069
|
+
private value;
|
|
1070
|
+
constructor(label: string, value: string | number | null);
|
|
1071
|
+
static make(label: string, value: string | number | null): Stat;
|
|
1072
|
+
description(text: string | null): this;
|
|
1073
|
+
descriptionIcon(name: string | null, position?: 'before' | 'after'): this;
|
|
1074
|
+
/** Color of the description and chart. */
|
|
1075
|
+
color(color: string | null): this;
|
|
1076
|
+
icon(name: string | null): this;
|
|
1077
|
+
/** Trend chart: a list of values, or values keyed by label. */
|
|
1078
|
+
chart(values: Record<string, number> | number[] | null): this;
|
|
1079
|
+
url(url: string | null): this;
|
|
1080
|
+
hasChart(): boolean;
|
|
1081
|
+
toHtml(panel: Panel, key: string): string;
|
|
1082
|
+
}
|
|
1083
|
+
/** A row of stats. */
|
|
1084
|
+
export declare abstract class StatsOverviewWidget extends Widget {
|
|
1085
|
+
static columnSpan: ColumnSpan;
|
|
1086
|
+
/** Polling interval, or `null` to disable polling. */
|
|
1087
|
+
static pollingInterval: string | null;
|
|
1088
|
+
abstract getStats(): Stat[] | Promise<Stat[]>;
|
|
1089
|
+
/** Row columns: three, or four when the number of stats fits better. */
|
|
1090
|
+
protected getColumns(count: number): number;
|
|
1091
|
+
render(): Promise<string>;
|
|
1092
|
+
}
|
|
1093
|
+
/** Chart data in Chart.js format: `{ datasets: [{ label, data, … }], labels: [...] }`. */
|
|
1094
|
+
export type ChartData = {
|
|
1095
|
+
datasets?: Record<string, unknown>[];
|
|
1096
|
+
labels?: unknown[];
|
|
1097
|
+
[key: string]: unknown;
|
|
1098
|
+
};
|
|
1099
|
+
/**
|
|
1100
|
+
* Chart.js chart. A subclass provides `getType()` (`'line'`, `'bar'`, `'pie'`, `'doughnut'`, `'radar'`, `'polarArea'`,
|
|
1101
|
+
* `'scatter'`, `'bubble'`) and `getData()`. Rendering happens in the browser; the server only sends new data when it
|
|
1102
|
+
* has changed (checksum).
|
|
1103
|
+
*/
|
|
1104
|
+
export declare abstract class ChartWidget extends Widget {
|
|
1105
|
+
static callable: string[];
|
|
1106
|
+
static locked: string[];
|
|
1107
|
+
/** Polling interval, or `null` to disable polling. */
|
|
1108
|
+
static pollingInterval: string | null;
|
|
1109
|
+
static heading: string | null;
|
|
1110
|
+
static description: string | null;
|
|
1111
|
+
/** Color of datasets that do not set one. */
|
|
1112
|
+
static color: string;
|
|
1113
|
+
/** Maximum chart height (`'300px'`). */
|
|
1114
|
+
static maxHeight: string | null;
|
|
1115
|
+
static isCollapsible: boolean;
|
|
1116
|
+
dataChecksum: string | null;
|
|
1117
|
+
/** Selected filter, one of `getFilters()`. */
|
|
1118
|
+
filter: string | null;
|
|
1119
|
+
private _cachedData;
|
|
1120
|
+
abstract getType(): string;
|
|
1121
|
+
getData(): ChartData | Promise<ChartData>;
|
|
1122
|
+
/** Chart.js options. */
|
|
1123
|
+
getOptions(): Record<string, unknown> | null;
|
|
1124
|
+
/** Filters offered in the header: value → label. */
|
|
1125
|
+
getFilters(): Record<string, string> | null;
|
|
1126
|
+
getHeading(): string | null;
|
|
1127
|
+
getDescription(): string | null;
|
|
1128
|
+
getColor(): string;
|
|
1129
|
+
getMaxHeight(): string | null;
|
|
1130
|
+
/** Text read by screen readers instead of the chart. */
|
|
1131
|
+
getChartAssistiveContent(): string | null;
|
|
1132
|
+
protected getCachedData(): Promise<ChartData>;
|
|
1133
|
+
protected generateDataChecksum(): Promise<string>;
|
|
1134
|
+
mount(): Promise<void>;
|
|
1135
|
+
/** Called by polling and before each render: only emits data when it has changed. */
|
|
1136
|
+
updateChartData(): Promise<void>;
|
|
1137
|
+
render(): Promise<string>;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Table in a widget: search, sort, simple pagination (previous / next).
|
|
1141
|
+
* A subclass provides `table(table)` and `getDataAdapterForTable()`. No actions or filters yet.
|
|
1142
|
+
*/
|
|
1143
|
+
export declare abstract class TableWidget extends Widget implements TableHost {
|
|
1144
|
+
static columnSpan: ColumnSpan;
|
|
1145
|
+
static callable: string[];
|
|
1146
|
+
/** Table heading; derived from the class name by default (`FlaggedOrders` → "Flagged Orders"). */
|
|
1147
|
+
static heading: string | null;
|
|
1148
|
+
tableSearch: string;
|
|
1149
|
+
tableSort: string | null;
|
|
1150
|
+
tableColumnSearches: Record<string, string>;
|
|
1151
|
+
tableRecordsPerPage: number;
|
|
1152
|
+
paginators: Record<string, number>;
|
|
1153
|
+
tableColumns: ColumnState[];
|
|
1154
|
+
abstract table(table: Table<any>): Table<any>;
|
|
1155
|
+
abstract getDataAdapterForTable(): DataAdapter;
|
|
1156
|
+
getTableHeading(): string;
|
|
1157
|
+
getTable(): Table<any>;
|
|
1158
|
+
mount(): void;
|
|
1159
|
+
tableGrouping: string | null;
|
|
1160
|
+
sortTable(column?: string | null, direction?: string | null): void;
|
|
1161
|
+
gotoPage(page: number, _pageName?: string): void;
|
|
1162
|
+
nextPage(_pageName?: string): void;
|
|
1163
|
+
previousPage(_pageName?: string): void;
|
|
1164
|
+
applyTableColumnManager(state?: unknown, _wasReordered?: unknown): void;
|
|
1165
|
+
resetTableColumnManager(): void;
|
|
1166
|
+
updatedTableSearch(): void;
|
|
1167
|
+
updatedTableColumnSearches(): void;
|
|
1168
|
+
updatedTableRecordsPerPage(): void;
|
|
1169
|
+
updatedTableSort(): void;
|
|
1170
|
+
render(): Promise<string>;
|
|
1171
|
+
}
|
|
1172
|
+
/** For widgets that receive the dashboard filters: `static reactive = PAGE_FILTERS` plus a `pageFilters` property. */
|
|
1173
|
+
export declare const PAGE_FILTERS: string[];
|
|
1174
|
+
/**
|
|
1175
|
+
* Stats widget bound to a list page's table: it receives the table state (search, filters, tab…)
|
|
1176
|
+
* and can aggregate exactly the records the table displays.
|
|
1177
|
+
*/
|
|
1178
|
+
export declare abstract class PageTableStatsWidget extends StatsOverviewWidget {
|
|
1179
|
+
/** List page whose table is observed. */
|
|
1180
|
+
static tablePage: () => typeof ListRecords;
|
|
1181
|
+
static reactive: string[];
|
|
1182
|
+
activeTab: string | null;
|
|
1183
|
+
paginators: Record<string, number>;
|
|
1184
|
+
tableColumnSearches: Record<string, string>;
|
|
1185
|
+
tableFilters: Record<string, FilterState>;
|
|
1186
|
+
tableRecordsPerPage: number;
|
|
1187
|
+
tableSearch: string;
|
|
1188
|
+
tableSort: string | null;
|
|
1189
|
+
/** Aggregates over the table's current query. The received state goes through the same validation as on the page. */
|
|
1190
|
+
protected aggregatePageTable(columns?: {
|
|
1191
|
+
sum?: string[];
|
|
1192
|
+
avg?: string[];
|
|
1193
|
+
}, modify?: ((query: any) => void) | null): Promise<{
|
|
1194
|
+
count: number;
|
|
1195
|
+
sum: Record<string, number>;
|
|
1196
|
+
avg: Record<string, number>;
|
|
1197
|
+
}>;
|
|
1198
|
+
/** Monthly trend over the table's current query (see `ObjectionAdapter.trendPerMonth`). */
|
|
1199
|
+
protected trendPageTable(options: {
|
|
1200
|
+
start: Date;
|
|
1201
|
+
end: Date;
|
|
1202
|
+
dateColumn?: string;
|
|
1203
|
+
average?: string;
|
|
1204
|
+
modify?: (query: any) => void;
|
|
1205
|
+
}): Promise<number[]>;
|
|
1206
|
+
}
|
|
1207
|
+
/** Schema component that embeds the host component's table. */
|
|
1208
|
+
export declare class EmbeddedTable extends SchemaComponent {
|
|
1209
|
+
static make(): EmbeddedTable;
|
|
1210
|
+
toHtml(): Promise<string>;
|
|
1211
|
+
}
|
|
1212
|
+
/** List page tab: restricts the table query and can show a badge. */
|
|
1213
|
+
export declare class Tab {
|
|
1214
|
+
private _label;
|
|
1215
|
+
private _badge;
|
|
1216
|
+
private _badgeColor;
|
|
1217
|
+
private _hasBadgeColor;
|
|
1218
|
+
private _query;
|
|
1219
|
+
constructor(label?: string | null);
|
|
1220
|
+
static make(label?: string | null): Tab;
|
|
1221
|
+
/** Badge computed after the page is displayed. */
|
|
1222
|
+
badge(resolver: () => number | string | null | Promise<number | string | null>): this;
|
|
1223
|
+
badgeColor(color: string): this;
|
|
1224
|
+
query(modifier: (query: any) => void): this;
|
|
1225
|
+
getLabel(key: string): string;
|
|
1226
|
+
hasBadge(): boolean;
|
|
1227
|
+
getBadge(): Promise<number | string | null>;
|
|
1228
|
+
getBadgeColor(): string;
|
|
1229
|
+
/** False until `badgeColor()` is called: a lazy-loaded badge then gets no color class. */
|
|
1230
|
+
hasBadgeColor(): boolean;
|
|
1231
|
+
getQuery(): ((query: any) => void) | null;
|
|
1232
|
+
}
|
|
1233
|
+
/** Resource list page: table state and methods called by the browser. */
|
|
1234
|
+
export declare class ListRecords extends Page implements TableHost {
|
|
1235
|
+
static callable: string[];
|
|
1236
|
+
static resource: typeof Resource;
|
|
1237
|
+
tableSearch: string;
|
|
1238
|
+
tableSort: string | null;
|
|
1239
|
+
tableColumnSearches: Record<string, string>;
|
|
1240
|
+
tableRecordsPerPage: number;
|
|
1241
|
+
paginators: Record<string, number>;
|
|
1242
|
+
selectedTableRecords: string[];
|
|
1243
|
+
deselectedTableRecords: string[];
|
|
1244
|
+
isTrackingDeselectedTableRecords: boolean;
|
|
1245
|
+
tableFilters: Record<string, FilterState>;
|
|
1246
|
+
tableDeferredFilters: Record<string, FilterState>;
|
|
1247
|
+
tableColumns: ColumnState[];
|
|
1248
|
+
isTableReordering: boolean;
|
|
1249
|
+
/** Current table grouping (`id:direction`), chosen in the toolbar. */
|
|
1250
|
+
tableGrouping: string | null;
|
|
1251
|
+
updatedTableGrouping(): void;
|
|
1252
|
+
/** Toggles manual reordering mode. */
|
|
1253
|
+
toggleTableReordering(): Promise<void>;
|
|
1254
|
+
/** Saves the new order: only keys belonging to the table are kept, each gets its position. */
|
|
1255
|
+
reorderTable(order: unknown, _draggedRecordKey?: unknown): Promise<void>;
|
|
1256
|
+
mount(_params?: Record<string, unknown>): Promise<void>;
|
|
1257
|
+
/** Filters form: one group per filter, bound to `tableDeferredFilters.<filter>`. */
|
|
1258
|
+
tableFiltersFormSchema(schema: Schema): Schema;
|
|
1259
|
+
applyTableFilters(): void;
|
|
1260
|
+
/** Removes an active filter indicator: the field is cleared from both the applied state and the form. */
|
|
1261
|
+
removeTableFilter(filterName: unknown, field?: unknown): void;
|
|
1262
|
+
/** Live field in the filters form (e.g. a rule's operator changed): runs its `afterStateUpdated`. */
|
|
1263
|
+
updatedTableDeferredFilters(_value: unknown, key: string | null): Promise<void>;
|
|
1264
|
+
resetTableFiltersForm(): void;
|
|
1265
|
+
removeTableFilters(): void;
|
|
1266
|
+
applyTableColumnManager(state?: unknown, _wasReordered?: unknown): void;
|
|
1267
|
+
resetTableColumnManager(): void;
|
|
1268
|
+
activeTab: string | null;
|
|
1269
|
+
getTabs(): Record<string, Tab>;
|
|
1270
|
+
/** Active tab, coerced to a declared key (an unknown value from the browser means the default tab). */
|
|
1271
|
+
getActiveTabKey(): string;
|
|
1272
|
+
updatedActiveTab(): void;
|
|
1273
|
+
modifyTableQuery(query: {
|
|
1274
|
+
modifiers?: ((q: any) => void)[];
|
|
1275
|
+
}): void;
|
|
1276
|
+
get resource(): typeof Resource;
|
|
1277
|
+
getHeaderWidgets(): (typeof Widget)[];
|
|
1278
|
+
/** The table state is passed to widgets, which can rerun the same query. */
|
|
1279
|
+
getWidgetData(): Record<string, unknown>;
|
|
1280
|
+
protected rendersActionModalsInPage(): boolean;
|
|
1281
|
+
getBulkActions(): Action[];
|
|
1282
|
+
/** Row actions declared by the table, with groups flattened. */
|
|
1283
|
+
getRecordActions(): Action[];
|
|
1284
|
+
protected getMountableActions(context: Record<string, unknown>): Action[] | Promise<Action[]>;
|
|
1285
|
+
/** Only known context shapes are kept; the record key is checked again in the database on mount. */
|
|
1286
|
+
protected resolveMountContext(clientContext: unknown): Record<string, unknown>;
|
|
1287
|
+
protected resolveActionRecord(context: Record<string, unknown>): Promise<unknown>;
|
|
1288
|
+
/**
|
|
1289
|
+
* Writes an editable cell. Everything comes from the browser: the column must exist and be editable and visible, the record
|
|
1290
|
+
* must be in the table's scope and editable by the user, and the value must be valid.
|
|
1291
|
+
*/
|
|
1292
|
+
updateTableColumnState(columnName: unknown, recordKey: unknown, input: unknown): Promise<unknown>;
|
|
1293
|
+
/** Selected keys: the sent list, or, in "select all" mode, every record of the current query except deselected ones. */
|
|
1294
|
+
getSelectedRecordKeys(): Promise<string[]>;
|
|
1295
|
+
deselectAllTableRecords(): void;
|
|
1296
|
+
getTable(): Table;
|
|
1297
|
+
renderTable(): Promise<string>;
|
|
1298
|
+
/** Table header actions (none on a list page: they go in the page header). */
|
|
1299
|
+
protected renderTableHeaderActions(ctx: any): Promise<string[]>;
|
|
1300
|
+
sortTable(column?: string | null, direction?: string | null): void;
|
|
1301
|
+
gotoPage(page: number, _pageName?: string): void;
|
|
1302
|
+
nextPage(_pageName?: string): void;
|
|
1303
|
+
previousPage(_pageName?: string): void;
|
|
1304
|
+
updatedTableSearch(): void;
|
|
1305
|
+
getDataAdapterForTable(): DataAdapter;
|
|
1306
|
+
getDataAdapter(): DataAdapter;
|
|
1307
|
+
updatedTableColumnSearches(): void;
|
|
1308
|
+
updatedTableRecordsPerPage(): void;
|
|
1309
|
+
updatedTableSort(): void;
|
|
1310
|
+
getBreadcrumbs(): {
|
|
1311
|
+
label: string;
|
|
1312
|
+
url: string | null;
|
|
1313
|
+
}[];
|
|
1314
|
+
getHeaderActions(): Action[];
|
|
1315
|
+
getPageClasses(): string[];
|
|
1316
|
+
contentSchema(schema: Schema): Schema;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Table of records related to another one: a child component of the edit page, loaded when it becomes visible.
|
|
1320
|
+
* Subclasses declare `relationship`, `adapterFor()`, `table()` and `form()`.
|
|
1321
|
+
*/
|
|
1322
|
+
export declare class RelationManager extends ListRecords {
|
|
1323
|
+
static relationship: string;
|
|
1324
|
+
static modelLabel: string;
|
|
1325
|
+
static pluralModelLabel: string | null;
|
|
1326
|
+
static recordTitleAttribute: string | null;
|
|
1327
|
+
/** Data adapter limited to records related to the given owner. */
|
|
1328
|
+
static adapterFor(_ownerKey: string): DataAdapter;
|
|
1329
|
+
/** Policy for related records (same abilities as a resource policy). */
|
|
1330
|
+
static policy: Policy | null;
|
|
1331
|
+
protected isAccessAuthorized(ctx: PanelContext): Promise<boolean>;
|
|
1332
|
+
static table(table: Table): Table;
|
|
1333
|
+
static form(schema: Schema): Schema;
|
|
1334
|
+
static getTitle(): string;
|
|
1335
|
+
/** Owner record key: set on mount by the page, never writable from the browser. */
|
|
1336
|
+
ownerRecord: string;
|
|
1337
|
+
static locked: string[];
|
|
1338
|
+
_facade: any;
|
|
1339
|
+
/** What ListRecords expects from a resource, provided here by the relation manager. */
|
|
1340
|
+
get resource(): any;
|
|
1341
|
+
getTable(): Table;
|
|
1342
|
+
/** Attaches an existing record to the owner. */
|
|
1343
|
+
static attach(_ownerKey: string, _recordKey: string): Promise<void>;
|
|
1344
|
+
/** Detaches records from the owner without deleting them. */
|
|
1345
|
+
static detach(_ownerKey: string, _recordKeys: string[]): Promise<void>;
|
|
1346
|
+
/** Attachable records matching the search: [key, label]. */
|
|
1347
|
+
static searchAttachable(_ownerKey: string, _search: string): Promise<[string, string][]>;
|
|
1348
|
+
/** Label of an attachable record, or `null` if it is not attachable (also used as validation). */
|
|
1349
|
+
static attachableLabel(_ownerKey: string, _recordKey: string): Promise<string | null>;
|
|
1350
|
+
getHeaderActions(): Action[];
|
|
1351
|
+
placeholder(): string;
|
|
1352
|
+
/** A relation manager has its own render hook locations, not the list page's. */
|
|
1353
|
+
contentSchema(schema: Schema): Schema;
|
|
1354
|
+
render(): Promise<string>;
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Page listing records related to a record: a table, with create, view and edit in modals.
|
|
1358
|
+
* Declared in the owner resource's `static relatedPages`, it is served at `<slug>/{record}/<name>`.
|
|
1359
|
+
*/
|
|
1360
|
+
export declare class ManageRelatedRecords extends ListRecords {
|
|
1361
|
+
/** Owner resource: set when the page is registered. */
|
|
1362
|
+
static parentResource: typeof Resource;
|
|
1363
|
+
static relationship: string;
|
|
1364
|
+
static modelLabel: string;
|
|
1365
|
+
static pluralModelLabel: string | null;
|
|
1366
|
+
static recordTitleAttribute: string | null;
|
|
1367
|
+
static policy: Policy | null;
|
|
1368
|
+
/** Data adapter limited to records related to the given owner. */
|
|
1369
|
+
static adapterFor(_ownerKey: string): DataAdapter;
|
|
1370
|
+
static table(table: Table): Table;
|
|
1371
|
+
static form(schema: Schema): Schema;
|
|
1372
|
+
static infolist(schema: Schema): Schema;
|
|
1373
|
+
static getTitle(): string;
|
|
1374
|
+
static getNavigationLabel(): string;
|
|
1375
|
+
/** Owner record key: read from the URL on mount, never writable from the browser. */
|
|
1376
|
+
recordKey: string;
|
|
1377
|
+
static locked: string[];
|
|
1378
|
+
_owner: any;
|
|
1379
|
+
_facade: any;
|
|
1380
|
+
private get related();
|
|
1381
|
+
mount(params: Record<string, unknown>): Promise<void>;
|
|
1382
|
+
/** The owner is reloaded and access to it checked on every request. */
|
|
1383
|
+
hydrate(): Promise<void>;
|
|
1384
|
+
getRecordKey(): string | null;
|
|
1385
|
+
/** What ListRecords expects from a resource, provided here by the page. */
|
|
1386
|
+
get resource(): any;
|
|
1387
|
+
getTable(): Table;
|
|
1388
|
+
getHeaderActions(): Action[];
|
|
1389
|
+
/** The page content is a group (tabs, if any, then the table). */
|
|
1390
|
+
contentSchema(schema: Schema): Schema;
|
|
1391
|
+
getTitle(): string;
|
|
1392
|
+
getSubNavigation(): SubNavigationItem[];
|
|
1393
|
+
getBreadcrumbs(): {
|
|
1394
|
+
label: string;
|
|
1395
|
+
url: string | null;
|
|
1396
|
+
}[];
|
|
1397
|
+
getPageClasses(): string[];
|
|
1398
|
+
}
|
|
1399
|
+
/** Base class for a resource's form pages. */
|
|
1400
|
+
declare abstract class ResourceFormPage extends Page {
|
|
1401
|
+
/** Live form field (`live()` + `afterStateUpdated()`): `set(name, value)` writes next to the updated field. */
|
|
1402
|
+
updatedData(_value: unknown, key: string | null): Promise<void>;
|
|
1403
|
+
static resource: typeof Resource;
|
|
1404
|
+
data: Record<string, unknown>;
|
|
1405
|
+
get resource(): typeof Resource;
|
|
1406
|
+
getDataAdapter(): DataAdapter;
|
|
1407
|
+
getRecordKey(): string | null;
|
|
1408
|
+
abstract getOperation(): 'create' | 'edit';
|
|
1409
|
+
abstract getSubmitMethod(): string;
|
|
1410
|
+
abstract getFormActions(): Action[];
|
|
1411
|
+
protected getRecord(): unknown;
|
|
1412
|
+
/** Two columns from `lg` by default; the resource may decide otherwise. */
|
|
1413
|
+
formSchema(schema: Schema): Schema;
|
|
1414
|
+
/**
|
|
1415
|
+
* Wizard steps: as soon as this method returns some, the page shows its form step by step,
|
|
1416
|
+
* with "Back" / "Next" and the submit button on the last step.
|
|
1417
|
+
*/
|
|
1418
|
+
protected getSteps(): Step[] | null;
|
|
1419
|
+
/** `true`: steps can be visited in any order, without validation along the way. */
|
|
1420
|
+
protected hasSkippableSteps(): boolean;
|
|
1421
|
+
/** Step shown on open (1-based). */
|
|
1422
|
+
protected getStartStep(): number;
|
|
1423
|
+
protected getWizardComponent(steps: Step[]): Wizard;
|
|
1424
|
+
contentSchema(schema: Schema): Schema;
|
|
1425
|
+
/** Where "Cancel" goes when the browser has no history: the list page, unless the page decides otherwise. */
|
|
1426
|
+
protected getCancelUrl(): string;
|
|
1427
|
+
protected cancelAction(): Action;
|
|
1428
|
+
/** Validates the form; on error, sets the errors on the component and notifies the browser. */
|
|
1429
|
+
protected validateForm(): Promise<boolean>;
|
|
1430
|
+
}
|
|
1431
|
+
/** Record creation page. */
|
|
1432
|
+
export declare class CreateRecord extends ResourceFormPage {
|
|
1433
|
+
static callable: string[];
|
|
1434
|
+
mount(): void;
|
|
1435
|
+
getOperation(): 'create';
|
|
1436
|
+
getSubmitMethod(): string;
|
|
1437
|
+
getTitle(): string;
|
|
1438
|
+
getBreadcrumbs(): {
|
|
1439
|
+
label: string;
|
|
1440
|
+
url: string | null;
|
|
1441
|
+
}[];
|
|
1442
|
+
getPageClasses(): string[];
|
|
1443
|
+
getFormActions(): Action[];
|
|
1444
|
+
/** Transforms validated data before creation (add the author, compute a field…). */
|
|
1445
|
+
protected mutateFormDataBeforeCreate(data: Record<string, unknown>): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
1446
|
+
/** Right before creation; throwing cancels it. */
|
|
1447
|
+
protected beforeCreate(_data: Record<string, unknown>): void | Promise<void>;
|
|
1448
|
+
/** The creation itself; defaults to the resource's data adapter. */
|
|
1449
|
+
protected handleRecordCreation(data: Record<string, unknown>): Promise<any>;
|
|
1450
|
+
/** After creation (logging, sending a message…). */
|
|
1451
|
+
protected afterCreate(_record: any): void | Promise<void>;
|
|
1452
|
+
/** Where to go next; defaults to the new record's edit page. */
|
|
1453
|
+
protected getRedirectUrl(record: any): string;
|
|
1454
|
+
/** Success notification title; `null` to show nothing. */
|
|
1455
|
+
protected getCreatedNotificationTitle(): string | null;
|
|
1456
|
+
create(another?: boolean): Promise<void>;
|
|
1457
|
+
createAnother(): Promise<void>;
|
|
1458
|
+
}
|
|
1459
|
+
/** Delete action with confirmation. */
|
|
1460
|
+
export declare class DeleteAction {
|
|
1461
|
+
/** On an edit page, deletes the page's record and returns to the list. On a table row, deletes the row. */
|
|
1462
|
+
static make(): Action;
|
|
1463
|
+
}
|
|
1464
|
+
/** Replicate action: an `Action` with a list of attributes not to copy. */
|
|
1465
|
+
export type ReplicateActionInstance = Action & {
|
|
1466
|
+
excludeAttributes(attributes: string[]): ReplicateActionInstance;
|
|
1467
|
+
};
|
|
1468
|
+
/** Duplicates a table row: the copy takes the record's attributes, except its key, timestamps and excluded ones. */
|
|
1469
|
+
export declare class ReplicateAction {
|
|
1470
|
+
static make(): ReplicateActionInstance;
|
|
1471
|
+
}
|
|
1472
|
+
/** Create in a modal with the resource form. */
|
|
1473
|
+
export declare class CreateAction {
|
|
1474
|
+
/** Without an argument, the resource (or relation manager) is the host component's. */
|
|
1475
|
+
static make(resource?: typeof Resource | null): Action;
|
|
1476
|
+
}
|
|
1477
|
+
/** Edit a table row in a modal, with the resource form. */
|
|
1478
|
+
export declare class EditAction {
|
|
1479
|
+
/** Without an argument, the resource (or relation manager) is the host component's. */
|
|
1480
|
+
static make(resource?: typeof Resource | null): Action;
|
|
1481
|
+
}
|
|
1482
|
+
/** Link to the record's view page (when the resource has one). */
|
|
1483
|
+
export declare class ViewAction {
|
|
1484
|
+
static make(resource?: typeof Resource | null): Action;
|
|
1485
|
+
}
|
|
1486
|
+
/** Attaches an existing record to a relation manager's owner. */
|
|
1487
|
+
export declare class AttachAction {
|
|
1488
|
+
static make(): Action;
|
|
1489
|
+
}
|
|
1490
|
+
/** Detaches a row from the owner without deleting it. */
|
|
1491
|
+
export declare class DetachAction {
|
|
1492
|
+
static make(): Action;
|
|
1493
|
+
}
|
|
1494
|
+
/** Detaches the selected rows. */
|
|
1495
|
+
export declare class DetachBulkAction {
|
|
1496
|
+
static make(): Action;
|
|
1497
|
+
}
|
|
1498
|
+
/** Restores a soft-deleted record. Only visible when the record is deleted. */
|
|
1499
|
+
export declare class RestoreAction {
|
|
1500
|
+
static make(): Action;
|
|
1501
|
+
}
|
|
1502
|
+
/** Permanently deletes a soft-deleted record. Only visible when the record is deleted. */
|
|
1503
|
+
export declare class ForceDeleteAction {
|
|
1504
|
+
static make(): Action;
|
|
1505
|
+
}
|
|
1506
|
+
/** Deletes the records selected in a table. */
|
|
1507
|
+
export declare class DeleteBulkAction {
|
|
1508
|
+
static make(): Action;
|
|
1509
|
+
}
|
|
1510
|
+
/** Record edit page. */
|
|
1511
|
+
export declare class EditRecord extends ResourceFormPage {
|
|
1512
|
+
static callable: string[];
|
|
1513
|
+
recordKey: string;
|
|
1514
|
+
/** Active relation manager tab (index in `Resource.relations`). */
|
|
1515
|
+
activeRelationManager: string;
|
|
1516
|
+
/**
|
|
1517
|
+
* Previous page, captured on first display from the Referer header: only a same-site URL is accepted,
|
|
1518
|
+
* and it cannot be changed afterwards.
|
|
1519
|
+
*/
|
|
1520
|
+
previousUrl: string;
|
|
1521
|
+
protected getCancelUrl(): string;
|
|
1522
|
+
contentSchema(schema: Schema): Schema;
|
|
1523
|
+
static locked: string[];
|
|
1524
|
+
_record: any;
|
|
1525
|
+
mount(params: Record<string, unknown>): Promise<void>;
|
|
1526
|
+
/** The record is reloaded on every request (no route model binding). */
|
|
1527
|
+
hydrate(): Promise<void>;
|
|
1528
|
+
protected getRecord(): unknown;
|
|
1529
|
+
getRecordKey(): string | null;
|
|
1530
|
+
getActionMountContext(): Record<string, unknown>;
|
|
1531
|
+
protected getActionRecord(): unknown;
|
|
1532
|
+
/** Delete, plus restore and force-delete when the model uses soft deletes. */
|
|
1533
|
+
getHeaderActions(): Action[];
|
|
1534
|
+
getOperation(): 'edit';
|
|
1535
|
+
getSubmitMethod(): string;
|
|
1536
|
+
getTitle(): string;
|
|
1537
|
+
getBreadcrumbs(): {
|
|
1538
|
+
label: string;
|
|
1539
|
+
url: string | null;
|
|
1540
|
+
}[];
|
|
1541
|
+
getSubNavigation(): SubNavigationItem[];
|
|
1542
|
+
getPageClasses(): string[];
|
|
1543
|
+
getFormActions(): Action[];
|
|
1544
|
+
/** Transforms the record's values before filling the form. */
|
|
1545
|
+
protected mutateFormDataBeforeFill(data: Record<string, unknown>): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
1546
|
+
/** Transforms validated data before saving. */
|
|
1547
|
+
protected mutateFormDataBeforeSave(data: Record<string, unknown>): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
1548
|
+
/** Right before saving; throwing cancels it. */
|
|
1549
|
+
protected beforeSave(_data: Record<string, unknown>): void | Promise<void>;
|
|
1550
|
+
/** The save itself; defaults to the resource's data adapter. */
|
|
1551
|
+
protected handleRecordUpdate(record: any, data: Record<string, unknown>): Promise<any>;
|
|
1552
|
+
/** After saving. */
|
|
1553
|
+
protected afterSave(_record: any): void | Promise<void>;
|
|
1554
|
+
/** URL to go to after saving; `null` (default) stays on the page. */
|
|
1555
|
+
protected getRedirectUrl(_record: any): string | null;
|
|
1556
|
+
/** Success notification title; `null` to show nothing. */
|
|
1557
|
+
protected getSavedNotificationTitle(): string | null;
|
|
1558
|
+
save(): Promise<void>;
|
|
1559
|
+
}
|
|
1560
|
+
/** Record view page: the resource's read-only `infolist()` schema. */
|
|
1561
|
+
export declare class ViewRecord extends Page {
|
|
1562
|
+
static resource: typeof Resource;
|
|
1563
|
+
static locked: string[];
|
|
1564
|
+
recordKey: string;
|
|
1565
|
+
/** Active relation manager tab (index in `Resource.relations`). */
|
|
1566
|
+
activeRelationManager: string;
|
|
1567
|
+
_record: any;
|
|
1568
|
+
get resource(): typeof Resource;
|
|
1569
|
+
getDataAdapter(): DataAdapter;
|
|
1570
|
+
mount(params: Record<string, unknown>): Promise<void>;
|
|
1571
|
+
/** The record is reloaded on every request, as on the edit page. */
|
|
1572
|
+
hydrate(): Promise<void>;
|
|
1573
|
+
getRecordKey(): string | null;
|
|
1574
|
+
getActionMountContext(): Record<string, unknown>;
|
|
1575
|
+
protected getActionRecord(): unknown;
|
|
1576
|
+
infolistSchema(schema: Schema): Schema;
|
|
1577
|
+
contentSchema(schema: Schema): Schema;
|
|
1578
|
+
/** Defaults to a link to the edit page. */
|
|
1579
|
+
getHeaderActions(): Action[];
|
|
1580
|
+
protected editAction(): Action;
|
|
1581
|
+
getTitle(): string;
|
|
1582
|
+
getBreadcrumbs(): {
|
|
1583
|
+
label: string;
|
|
1584
|
+
url: string | null;
|
|
1585
|
+
}[];
|
|
1586
|
+
getSubNavigation(): SubNavigationItem[];
|
|
1587
|
+
getPageClasses(): string[];
|
|
1588
|
+
}
|
|
1589
|
+
/** Sidebar: logo, tenant menu, search, navigation and, without a topbar, the bell and user menu. */
|
|
1590
|
+
export declare class Sidebar extends Component {
|
|
1591
|
+
static callable: string[];
|
|
1592
|
+
currentPath: string;
|
|
1593
|
+
static locked: string[];
|
|
1594
|
+
mount(params: Record<string, unknown>): void;
|
|
1595
|
+
/** A resource item stays active on its create and edit pages. */
|
|
1596
|
+
render(): Promise<string>;
|
|
1597
|
+
/** Theme choice by the user: only a theme declared by the panel is accepted; the page reloads to apply it. */
|
|
1598
|
+
setTheme(id: unknown): void;
|
|
1599
|
+
}
|
|
1600
|
+
/** Topbar: logo, optional navigation, search, bell, user menu. */
|
|
1601
|
+
export declare class Topbar extends Component {
|
|
1602
|
+
static callable: string[];
|
|
1603
|
+
currentPath: string;
|
|
1604
|
+
static locked: string[];
|
|
1605
|
+
mount(params: Record<string, unknown>): void;
|
|
1606
|
+
render(): Promise<string>;
|
|
1607
|
+
setTheme(id: unknown): void;
|
|
1608
|
+
}
|
|
1609
|
+
/** User menu on simple pages for a signed-in user. */
|
|
1610
|
+
export declare class SimpleUserMenu extends Component {
|
|
1611
|
+
static callable: string[];
|
|
1612
|
+
render(): Promise<string>;
|
|
1613
|
+
setTheme(id: unknown): void;
|
|
1614
|
+
}
|
|
1615
|
+
/** Resources defined in a folder: `.resources(await discoverResources(new URL('./resources/', import.meta.url)))`. New files are picked up on the next start. */
|
|
1616
|
+
export declare const discoverResources: (directory: string | URL) => Promise<(typeof Resource)[]>;
|
|
1617
|
+
/** Custom pages (and dashboards) defined in a folder. Resource and authentication pages are excluded. */
|
|
1618
|
+
export declare const discoverPages: (directory: string | URL) => Promise<(typeof Page)[]>;
|
|
1619
|
+
/** Widgets defined in a folder. */
|
|
1620
|
+
export declare const discoverWidgets: (directory: string | URL) => Promise<(typeof Widget)[]>;
|
|
1621
|
+
/** Panels default-exported (`export default Panel.make()…`) by a folder's modules. */
|
|
1622
|
+
export declare function discoverPanels(directory: string | URL): Promise<Panel[]>;
|
|
1623
|
+
/** Express router for a panel: assets, runtime endpoint, authentication, tenants, protected pages. */
|
|
1624
|
+
export declare function panelRouter(panel: Panel, runtime: WireRuntime): Router;
|