@easy-cms/core 0.26.0 → 0.27.0
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/dist/index.d.ts +52 -2
- package/dist/index.js +117 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1526,7 +1526,7 @@ interface GlobalConfig {
|
|
|
1526
1526
|
}
|
|
1527
1527
|
type AdminLocale = 'en' | 'th';
|
|
1528
1528
|
/** Icons a collection or global can show in the admin menu ([Lucide](https://lucide.dev) names). */
|
|
1529
|
-
declare const ADMIN_ICONS: readonly ["file-text", "newspaper", "book-open", "notebook", "folder", "tag", "tags", "image", "images", "video", "music", "file", "users", "user", "building", "store", "shopping-bag", "shopping-cart", "package", "box", "calendar", "calendar-days", "map-pin", "globe", "house", "layout-grid", "layers", "star", "heart", "message-square", "mail", "phone", "briefcase", "graduation-cap", "utensils", "car", "settings", "sliders-horizontal", "palette", "megaphone", "bell", "link", "quote", "circle-help", "award", "ticket", "camera", "key"];
|
|
1529
|
+
declare const ADMIN_ICONS: readonly ["file-text", "newspaper", "book-open", "notebook", "folder", "tag", "tags", "image", "images", "video", "music", "file", "users", "user", "building", "store", "shopping-bag", "shopping-cart", "package", "box", "calendar", "calendar-days", "map-pin", "globe", "house", "layout-grid", "layers", "star", "heart", "message-square", "mail", "phone", "briefcase", "graduation-cap", "utensils", "car", "settings", "sliders-horizontal", "palette", "megaphone", "bell", "link", "quote", "circle-help", "award", "ticket", "camera", "key", "chart-column", "chart-line"];
|
|
1530
1530
|
type AdminIcon = (typeof ADMIN_ICONS)[number];
|
|
1531
1531
|
/** Your or your client's brand in the admin UI. */
|
|
1532
1532
|
interface AdminBrand {
|
|
@@ -1537,6 +1537,34 @@ interface AdminBrand {
|
|
|
1537
1537
|
/** Main color as `#rrggbb`; lighter and darker shades are derived from it. */
|
|
1538
1538
|
readonly color?: string;
|
|
1539
1539
|
}
|
|
1540
|
+
/** Who may see an admin page or dashboard widget. Default: every logged-in user. */
|
|
1541
|
+
type AdminViewAccess = (args: {
|
|
1542
|
+
readonly user: AuthUser;
|
|
1543
|
+
}) => boolean | Promise<boolean>;
|
|
1544
|
+
/** A page of its own in the admin, e.g. a plugin's report, at `<admin>/p/<path>`. */
|
|
1545
|
+
interface AdminPage {
|
|
1546
|
+
/** Its address under `<admin>/p/`: lowercase letters, digits and `-`, e.g. `forms-overview`. */
|
|
1547
|
+
readonly path: string;
|
|
1548
|
+
/** The page's body: a Web Component from an admin module. The admin draws the header. */
|
|
1549
|
+
readonly component: AdminComponent;
|
|
1550
|
+
/** Its title in the header and the menu. */
|
|
1551
|
+
readonly label: Label;
|
|
1552
|
+
/** Icon in the admin menu. Default `file-text`. */
|
|
1553
|
+
readonly icon?: AdminIcon;
|
|
1554
|
+
/** Listed under Content (default) or Settings in the menu, or not listed (`false`): reached by links. */
|
|
1555
|
+
readonly group?: 'content' | 'settings' | false;
|
|
1556
|
+
/** Who may open it. Pages a user may not open are left out of their admin. */
|
|
1557
|
+
readonly access?: AdminViewAccess;
|
|
1558
|
+
}
|
|
1559
|
+
/** A panel on the admin's dashboard, after the built-in ones. */
|
|
1560
|
+
interface DashboardWidget {
|
|
1561
|
+
/** A Web Component from an admin module. */
|
|
1562
|
+
readonly component: AdminComponent;
|
|
1563
|
+
/** Half the dashboard's width (default) or all of it. Full width on phones. */
|
|
1564
|
+
readonly width?: 'half' | 'full';
|
|
1565
|
+
/** Who sees it. */
|
|
1566
|
+
readonly access?: AdminViewAccess;
|
|
1567
|
+
}
|
|
1540
1568
|
interface AdminConfig {
|
|
1541
1569
|
/** Where the admin UI is served. Default `/admin`. */
|
|
1542
1570
|
readonly path?: string;
|
|
@@ -1562,6 +1590,10 @@ interface AdminConfig {
|
|
|
1562
1590
|
* module file. Remote URLs are not allowed.
|
|
1563
1591
|
*/
|
|
1564
1592
|
readonly modules?: readonly string[];
|
|
1593
|
+
/** Pages of their own, e.g. from plugins, at `<admin>/p/<path>`. */
|
|
1594
|
+
readonly pages?: readonly AdminPage[];
|
|
1595
|
+
/** Panels on the dashboard, after the built-in ones. */
|
|
1596
|
+
readonly dashboard?: readonly DashboardWidget[];
|
|
1565
1597
|
}
|
|
1566
1598
|
interface ImageSize {
|
|
1567
1599
|
/** Key in `media.sizes`, e.g. `thumbnail`. */
|
|
@@ -2069,6 +2101,20 @@ interface AdminGlobal {
|
|
|
2069
2101
|
update: boolean;
|
|
2070
2102
|
};
|
|
2071
2103
|
}
|
|
2104
|
+
/** A page of its own in the admin (`admin.pages`) that this user may open. */
|
|
2105
|
+
interface AdminPageRef {
|
|
2106
|
+
path: string;
|
|
2107
|
+
label: Label;
|
|
2108
|
+
icon?: string;
|
|
2109
|
+
/** Where it is listed in the menu; `false`: not listed. */
|
|
2110
|
+
group: 'content' | 'settings' | false;
|
|
2111
|
+
component: AdminComponentRef;
|
|
2112
|
+
}
|
|
2113
|
+
/** A dashboard panel (`admin.dashboard`) this user may see. */
|
|
2114
|
+
interface AdminWidgetRef {
|
|
2115
|
+
component: AdminComponentRef;
|
|
2116
|
+
width: 'half' | 'full';
|
|
2117
|
+
}
|
|
2072
2118
|
interface AdminSchema {
|
|
2073
2119
|
locale: AdminLocale;
|
|
2074
2120
|
/** Admins can email users links to set their password (needs `email` and `serverURL`). */
|
|
@@ -2084,6 +2130,10 @@ interface AdminSchema {
|
|
|
2084
2130
|
globals: AdminGlobal[];
|
|
2085
2131
|
/** URLs under the API of the admin modules to load (`admin.modules`). */
|
|
2086
2132
|
modules: string[];
|
|
2133
|
+
/** Pages this user may open (`admin.pages`). */
|
|
2134
|
+
pages: AdminPageRef[];
|
|
2135
|
+
/** Dashboard panels this user may see (`admin.dashboard`). */
|
|
2136
|
+
dashboard: AdminWidgetRef[];
|
|
2087
2137
|
}
|
|
2088
2138
|
|
|
2089
2139
|
declare const SESSION_COOKIE = "ecms-session";
|
|
@@ -2121,4 +2171,4 @@ declare const BUILTIN_COLLECTIONS: readonly ["users", "media"];
|
|
|
2121
2171
|
/** Checks a config and returns every problem found. An empty array means it is valid. */
|
|
2122
2172
|
declare function validateConfig(config: Config): ConfigIssue[];
|
|
2123
2173
|
|
|
2124
|
-
export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminField, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminSchema, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, Auth, type AuthConfig, type AuthUser, BUILTIN_COLLECTIONS, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinUsersCollection, type BundleHints, CONFIG_FILE_NAMES, CSRF_COOKIE, CSRF_HEADER, type CliCommand, type CollectionAccess, type CollectionAdmin, type CollectionConfig, type CollectionDocument, type CollectionHooks, type CollectionListAdmin, type CollectionSlug, type Config, ConfigError, type ConfigIssue, type ContainerAdmin, type CopyProgress, type CopyResult, type CreateEasyCMSOptions, type CreateInput, type CreateMigrationResult, type CustomField, type CustomFieldTypes, DEFAULT_ADMIN_PATH, DEFAULT_API_PATH, DEFAULT_DEPTH, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_VERSIONS, DEFAULT_PASSWORD_EMAILS, DEFAULT_TOKEN_EXPIRATION, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DepthOptions, type DocumentOf, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailField, type EmailMessage, type Endpoint, type EndpointRequest, FIELD_TYPES, FIELD_TYPE_BASES, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldType, type FieldTypeBase, type FieldTypeDefinition, type FieldTypeValidateContext, type FieldValidate, type FieldValidateContext, type FieldValue, type FieldsInput, type FieldsValue, type FilterOptions, type FilterOptionsArgs, type FindArgs, type FindOptions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type InferCollection, type InferGlobal, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type Operation, type PaginatedDocs, type PasswordEmail, type PasswordEmailArgs, type PasswordEmailFn, type PasswordLinkOptions, PayloadTooLargeError, type Plugin, type PluginTypes, type PreviewTarget, type PreviewURL, QueryError, type RawDocument, type ReadOptions, type RelationshipField, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoutesConfig, SESSION_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type SlugOf, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, type TypedPlugin, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, configSignature, consoleEmail, consoleLogger, copyDatabase, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, defineFieldType, definePlugin, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, silentLogger, singularize, slugify, sniffMimeType, validateConfig, validateFields, verifyPassword };
|
|
2174
|
+
export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminField, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminPage, type AdminPageRef, type AdminSchema, type AdminViewAccess, type AdminWidgetRef, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, Auth, type AuthConfig, type AuthUser, BUILTIN_COLLECTIONS, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinUsersCollection, type BundleHints, CONFIG_FILE_NAMES, CSRF_COOKIE, CSRF_HEADER, type CliCommand, type CollectionAccess, type CollectionAdmin, type CollectionConfig, type CollectionDocument, type CollectionHooks, type CollectionListAdmin, type CollectionSlug, type Config, ConfigError, type ConfigIssue, type ContainerAdmin, type CopyProgress, type CopyResult, type CreateEasyCMSOptions, type CreateInput, type CreateMigrationResult, type CustomField, type CustomFieldTypes, DEFAULT_ADMIN_PATH, DEFAULT_API_PATH, DEFAULT_DEPTH, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_VERSIONS, DEFAULT_PASSWORD_EMAILS, DEFAULT_TOKEN_EXPIRATION, type DashboardWidget, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DepthOptions, type DocumentOf, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailField, type EmailMessage, type Endpoint, type EndpointRequest, FIELD_TYPES, FIELD_TYPE_BASES, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldType, type FieldTypeBase, type FieldTypeDefinition, type FieldTypeValidateContext, type FieldValidate, type FieldValidateContext, type FieldValue, type FieldsInput, type FieldsValue, type FilterOptions, type FilterOptionsArgs, type FindArgs, type FindOptions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type InferCollection, type InferGlobal, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type Operation, type PaginatedDocs, type PasswordEmail, type PasswordEmailArgs, type PasswordEmailFn, type PasswordLinkOptions, PayloadTooLargeError, type Plugin, type PluginTypes, type PreviewTarget, type PreviewURL, QueryError, type RawDocument, type ReadOptions, type RelationshipField, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoutesConfig, SESSION_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type SlugOf, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, type TypedPlugin, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, configSignature, consoleEmail, consoleLogger, copyDatabase, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, defineFieldType, definePlugin, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, silentLogger, singularize, slugify, sniffMimeType, validateConfig, validateFields, verifyPassword };
|
package/dist/index.js
CHANGED
|
@@ -1138,7 +1138,9 @@ var ADMIN_ICONS = [
|
|
|
1138
1138
|
"award",
|
|
1139
1139
|
"ticket",
|
|
1140
1140
|
"camera",
|
|
1141
|
-
"key"
|
|
1141
|
+
"key",
|
|
1142
|
+
"chart-column",
|
|
1143
|
+
"chart-line"
|
|
1142
1144
|
];
|
|
1143
1145
|
function definePlugin(plugin) {
|
|
1144
1146
|
return plugin;
|
|
@@ -1994,6 +1996,7 @@ function validateConfig(config) {
|
|
|
1994
1996
|
add("db", "is required", "pass a database adapter, e.g. db: sqlite({ url: 'file:./cms.db' })");
|
|
1995
1997
|
}
|
|
1996
1998
|
validateAdmin(config, add);
|
|
1999
|
+
validateAdminViews(config, add);
|
|
1997
2000
|
validateUpload(config, add);
|
|
1998
2001
|
validateAuth(config, add);
|
|
1999
2002
|
validateCors(config.cors, add);
|
|
@@ -2114,6 +2117,83 @@ function validateAdmin(config, add) {
|
|
|
2114
2117
|
add("admin.brand.color", `must be a hex color like "#0f766e" (got ${JSON.stringify(color)})`);
|
|
2115
2118
|
}
|
|
2116
2119
|
}
|
|
2120
|
+
var PAGE_PATH = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
2121
|
+
function validateAdminViews(config, add) {
|
|
2122
|
+
const access = (value, path) => {
|
|
2123
|
+
if (value !== void 0 && typeof value !== "function")
|
|
2124
|
+
add(
|
|
2125
|
+
`${path}.access`,
|
|
2126
|
+
"must be a function",
|
|
2127
|
+
'e.g. access: ({ user }) => user.role === "admin"'
|
|
2128
|
+
);
|
|
2129
|
+
};
|
|
2130
|
+
const pages2 = config.admin?.pages;
|
|
2131
|
+
if (pages2 !== void 0) {
|
|
2132
|
+
if (!Array.isArray(pages2)) {
|
|
2133
|
+
add(
|
|
2134
|
+
"admin.pages",
|
|
2135
|
+
"must be an array",
|
|
2136
|
+
"e.g. pages: [{ path: 'stats', label: 'Stats', component: 'ecms-stats' }]"
|
|
2137
|
+
);
|
|
2138
|
+
} else {
|
|
2139
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2140
|
+
pages2.forEach((page, i) => {
|
|
2141
|
+
const path = `admin.pages[${i}]`;
|
|
2142
|
+
if (typeof page !== "object" || page === null) {
|
|
2143
|
+
add(path, "must be an object");
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
const p = page;
|
|
2147
|
+
if (typeof p.path !== "string" || !PAGE_PATH.test(p.path)) {
|
|
2148
|
+
add(
|
|
2149
|
+
`${path}.path`,
|
|
2150
|
+
`must be lowercase letters, digits and "-" (got ${JSON.stringify(p.path)})`,
|
|
2151
|
+
"e.g. path: 'forms-overview'"
|
|
2152
|
+
);
|
|
2153
|
+
} else if (seen.has(p.path)) {
|
|
2154
|
+
add(`${path}.path`, `"${p.path}" is used by another page`);
|
|
2155
|
+
} else {
|
|
2156
|
+
seen.add(p.path);
|
|
2157
|
+
}
|
|
2158
|
+
validateComponent(p.component, `${path}.component`, add);
|
|
2159
|
+
const label = p.label;
|
|
2160
|
+
if (!(typeof label === "string" && label.trim() !== "") && !(typeof label === "object" && label !== null && !Array.isArray(label)))
|
|
2161
|
+
add(
|
|
2162
|
+
`${path}.label`,
|
|
2163
|
+
"must be a string or { en, th }",
|
|
2164
|
+
"e.g. label: { en: 'Stats', th: '\u0E2A\u0E16\u0E34\u0E15\u0E34' }"
|
|
2165
|
+
);
|
|
2166
|
+
validateIcon(p, path, add);
|
|
2167
|
+
if (p.group !== void 0 && p.group !== "content" && p.group !== "settings" && p.group !== false)
|
|
2168
|
+
add(`${path}.group`, 'must be "content", "settings" or false');
|
|
2169
|
+
access(p.access, path);
|
|
2170
|
+
});
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
const widgets2 = config.admin?.dashboard;
|
|
2174
|
+
if (widgets2 !== void 0) {
|
|
2175
|
+
if (!Array.isArray(widgets2)) {
|
|
2176
|
+
add(
|
|
2177
|
+
"admin.dashboard",
|
|
2178
|
+
"must be an array",
|
|
2179
|
+
"e.g. dashboard: [{ component: 'ecms-stats-widget' }]"
|
|
2180
|
+
);
|
|
2181
|
+
} else {
|
|
2182
|
+
widgets2.forEach((widget, i) => {
|
|
2183
|
+
const path = `admin.dashboard[${i}]`;
|
|
2184
|
+
if (typeof widget !== "object" || widget === null) {
|
|
2185
|
+
add(path, "must be an object");
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
const w = widget;
|
|
2189
|
+
validateComponent(w.component, `${path}.component`, add);
|
|
2190
|
+
if (w.width !== void 0 && w.width !== "half" && w.width !== "full")
|
|
2191
|
+
add(`${path}.width`, 'must be "half" or "full"');
|
|
2192
|
+
access(w.access, path);
|
|
2193
|
+
});
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2117
2197
|
function validateIcon(container, path, add) {
|
|
2118
2198
|
const icon = container.icon;
|
|
2119
2199
|
if (icon === void 0 || ADMIN_ICONS.includes(icon)) return;
|
|
@@ -2751,7 +2831,9 @@ async function resolveConfig(input) {
|
|
|
2751
2831
|
brand: config.admin?.brand ?? {},
|
|
2752
2832
|
siteUrl: config.admin?.siteUrl ?? "",
|
|
2753
2833
|
menu: config.admin?.menu ?? [],
|
|
2754
|
-
modules: config.admin?.modules ?? []
|
|
2834
|
+
modules: config.admin?.modules ?? [],
|
|
2835
|
+
pages: config.admin?.pages ?? [],
|
|
2836
|
+
dashboard: config.admin?.dashboard ?? []
|
|
2755
2837
|
},
|
|
2756
2838
|
upload: {
|
|
2757
2839
|
dir: config.upload?.dir ?? "uploads",
|
|
@@ -5001,9 +5083,41 @@ async function adminSchema(cms, user, origin) {
|
|
|
5001
5083
|
localization: localization ? { locales: [...localization.locales], defaultLocale: localization.defaultLocale } : null,
|
|
5002
5084
|
collections: await Promise.all(collections.map((c) => collection(c, user, localized))),
|
|
5003
5085
|
globals: await Promise.all(cms.config.globals.map((g) => global(g, user, localized))),
|
|
5004
|
-
modules: adminModuleUrls(cms)
|
|
5086
|
+
modules: adminModuleUrls(cms),
|
|
5087
|
+
pages: await pages(cms, user),
|
|
5088
|
+
dashboard: await widgets(cms, user)
|
|
5005
5089
|
};
|
|
5006
5090
|
}
|
|
5091
|
+
async function shown(access, user) {
|
|
5092
|
+
if (!access) return true;
|
|
5093
|
+
try {
|
|
5094
|
+
return await access({ user }) === true;
|
|
5095
|
+
} catch {
|
|
5096
|
+
return false;
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
async function pages(cms, user) {
|
|
5100
|
+
const out = [];
|
|
5101
|
+
for (const page of cms.config.admin.pages) {
|
|
5102
|
+
if (!await shown(page.access, user)) continue;
|
|
5103
|
+
out.push({
|
|
5104
|
+
path: page.path,
|
|
5105
|
+
label: page.label,
|
|
5106
|
+
...page.icon ? { icon: page.icon } : {},
|
|
5107
|
+
group: page.group ?? "content",
|
|
5108
|
+
component: componentRef(page.component)
|
|
5109
|
+
});
|
|
5110
|
+
}
|
|
5111
|
+
return out;
|
|
5112
|
+
}
|
|
5113
|
+
async function widgets(cms, user) {
|
|
5114
|
+
const out = [];
|
|
5115
|
+
for (const widget of cms.config.admin.dashboard) {
|
|
5116
|
+
if (!await shown(widget.access, user)) continue;
|
|
5117
|
+
out.push({ component: componentRef(widget.component), width: widget.width ?? "half" });
|
|
5118
|
+
}
|
|
5119
|
+
return out;
|
|
5120
|
+
}
|
|
5007
5121
|
|
|
5008
5122
|
// src/rest/filter-options.ts
|
|
5009
5123
|
function fieldAt(fields, path) {
|