@adminforth/dashboard 1.0.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.
Files changed (107) hide show
  1. package/.woodpecker/buildRelease.sh +13 -0
  2. package/.woodpecker/buildSlackNotify.sh +46 -0
  3. package/.woodpecker/release.yml +57 -0
  4. package/README.md +59 -0
  5. package/custom/api/dashboardApi.ts +213 -0
  6. package/custom/composables/useElementSize.ts +41 -0
  7. package/custom/model/dashboard.types.ts +73 -0
  8. package/custom/package.json +9 -0
  9. package/custom/pnpm-lock.yaml +24 -0
  10. package/custom/queries/useDashboardConfig.ts +51 -0
  11. package/custom/queries/useWidgetData.ts +51 -0
  12. package/custom/runtime/DashboardGroup.vue +185 -0
  13. package/custom/runtime/DashboardPage.vue +122 -0
  14. package/custom/runtime/DashboardRuntime.vue +435 -0
  15. package/custom/runtime/WidgetRenderer.vue +60 -0
  16. package/custom/runtime/WidgetShell.vue +152 -0
  17. package/custom/skills/adminforth-dashboard/SKILL.md +125 -0
  18. package/custom/widgets/chart/ChartWidget.vue +188 -0
  19. package/custom/widgets/chart/bar/BarChart.vue +167 -0
  20. package/custom/widgets/chart/chart.types.ts +34 -0
  21. package/custom/widgets/chart/chart.utils.ts +54 -0
  22. package/custom/widgets/chart/funnel/FunnelChart.vue +197 -0
  23. package/custom/widgets/chart/histogram/HistogramChart.vue +21 -0
  24. package/custom/widgets/chart/line/LineChart.vue +175 -0
  25. package/custom/widgets/chart/pie/PieChart.vue +161 -0
  26. package/custom/widgets/chart/stacked-bar/StackedBarChart.vue +256 -0
  27. package/custom/widgets/gauge-card/GaugeCardWidget.vue +107 -0
  28. package/custom/widgets/kpi-card/KpiCardWidget.vue +73 -0
  29. package/custom/widgets/pivot-table/PivotTableWidget.vue +122 -0
  30. package/custom/widgets/registry.ts +51 -0
  31. package/custom/widgets/table/TableWidget.vue +110 -0
  32. package/dist/custom/api/dashboardApi.d.ts +32 -0
  33. package/dist/custom/api/dashboardApi.js +179 -0
  34. package/dist/custom/api/dashboardApi.ts +213 -0
  35. package/dist/custom/composables/useElementSize.d.ts +8 -0
  36. package/dist/custom/composables/useElementSize.js +30 -0
  37. package/dist/custom/composables/useElementSize.ts +41 -0
  38. package/dist/custom/model/dashboard.types.d.ts +45 -0
  39. package/dist/custom/model/dashboard.types.js +14 -0
  40. package/dist/custom/model/dashboard.types.ts +73 -0
  41. package/dist/custom/package.json +9 -0
  42. package/dist/custom/pnpm-lock.yaml +24 -0
  43. package/dist/custom/queries/useDashboardConfig.d.ts +112 -0
  44. package/dist/custom/queries/useDashboardConfig.js +57 -0
  45. package/dist/custom/queries/useDashboardConfig.ts +51 -0
  46. package/dist/custom/queries/useWidgetData.d.ts +90 -0
  47. package/dist/custom/queries/useWidgetData.js +57 -0
  48. package/dist/custom/queries/useWidgetData.ts +51 -0
  49. package/dist/custom/runtime/DashboardGroup.vue +185 -0
  50. package/dist/custom/runtime/DashboardPage.vue +122 -0
  51. package/dist/custom/runtime/DashboardRuntime.vue +435 -0
  52. package/dist/custom/runtime/WidgetRenderer.vue +60 -0
  53. package/dist/custom/runtime/WidgetShell.vue +152 -0
  54. package/dist/custom/skills/adminforth-dashboard/SKILL.md +125 -0
  55. package/dist/custom/widgets/chart/ChartWidget.vue +188 -0
  56. package/dist/custom/widgets/chart/bar/BarChart.vue +167 -0
  57. package/dist/custom/widgets/chart/chart.types.d.ts +25 -0
  58. package/dist/custom/widgets/chart/chart.types.js +2 -0
  59. package/dist/custom/widgets/chart/chart.types.ts +34 -0
  60. package/dist/custom/widgets/chart/chart.utils.d.ts +5 -0
  61. package/dist/custom/widgets/chart/chart.utils.js +52 -0
  62. package/dist/custom/widgets/chart/chart.utils.ts +54 -0
  63. package/dist/custom/widgets/chart/funnel/FunnelChart.vue +197 -0
  64. package/dist/custom/widgets/chart/histogram/HistogramChart.vue +21 -0
  65. package/dist/custom/widgets/chart/line/LineChart.vue +175 -0
  66. package/dist/custom/widgets/chart/pie/PieChart.vue +161 -0
  67. package/dist/custom/widgets/chart/stacked-bar/StackedBarChart.vue +256 -0
  68. package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +107 -0
  69. package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +73 -0
  70. package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +122 -0
  71. package/dist/custom/widgets/registry.d.ts +11 -0
  72. package/dist/custom/widgets/registry.js +47 -0
  73. package/dist/custom/widgets/registry.ts +51 -0
  74. package/dist/custom/widgets/table/TableWidget.vue +110 -0
  75. package/dist/endpoint/dashboard.d.ts +7 -0
  76. package/dist/endpoint/dashboard.js +29 -0
  77. package/dist/endpoint/groups.d.ts +30 -0
  78. package/dist/endpoint/groups.js +131 -0
  79. package/dist/endpoint/widgets.d.ts +15 -0
  80. package/dist/endpoint/widgets.js +182 -0
  81. package/dist/index.d.ts +13 -0
  82. package/dist/index.js +124 -0
  83. package/dist/schema/api.d.ts +1205 -0
  84. package/dist/schema/api.js +84 -0
  85. package/dist/schema/widget.d.ts +514 -0
  86. package/dist/schema/widget.js +133 -0
  87. package/dist/services/dashboardConfigService.d.ts +35 -0
  88. package/dist/services/dashboardConfigService.js +79 -0
  89. package/dist/services/widgetConfigValidator.d.ts +8 -0
  90. package/dist/services/widgetConfigValidator.js +65 -0
  91. package/dist/services/widgetDataService.d.ts +20 -0
  92. package/dist/services/widgetDataService.js +32 -0
  93. package/dist/types.d.ts +8 -0
  94. package/dist/types.js +1 -0
  95. package/endpoint/dashboard.ts +32 -0
  96. package/endpoint/groups.ts +213 -0
  97. package/endpoint/widgets.ts +255 -0
  98. package/index.ts +141 -0
  99. package/package.json +64 -0
  100. package/schema/api.ts +99 -0
  101. package/schema/widget.ts +159 -0
  102. package/services/dashboardConfigService.ts +136 -0
  103. package/services/widgetConfigValidator.ts +93 -0
  104. package/services/widgetDataService.ts +57 -0
  105. package/shims-vue.d.ts +5 -0
  106. package/tsconfig.json +18 -0
  107. package/types.ts +8 -0
@@ -0,0 +1,159 @@
1
+ import { z } from 'zod'
2
+
3
+ export type DashboardWidgetConfigValidationError = {
4
+ field: string
5
+ message: string
6
+ }
7
+
8
+ const DashboardWidgetSizeSchema = z.enum([
9
+ 'small',
10
+ 'medium',
11
+ 'large',
12
+ 'wide',
13
+ 'full',
14
+ ])
15
+
16
+ const WidgetBaseSchema = z.object({
17
+ id: z.string().optional(),
18
+ group_id: z.string().optional(),
19
+ label: z.string().optional(),
20
+ size: DashboardWidgetSizeSchema.optional(),
21
+ width: z.number().positive('Width must be greater than 0').optional(),
22
+ height: z.number().positive('Height must be greater than 0').optional(),
23
+ minWidth: z.number().nonnegative('Min width must be a non-negative number').optional(),
24
+ maxWidth: z.number().nonnegative('Max width must be a non-negative number').nullable().optional(),
25
+ order: z.number().optional(),
26
+ })
27
+
28
+ const ChartBaseSchema = z.object({
29
+ title: z.string().optional(),
30
+ })
31
+
32
+ const ChartBucketSchema = z.object({
33
+ label: z.string().min(1, 'Bucket label is required'),
34
+ min: z.number().optional(),
35
+ max: z.number().optional(),
36
+ })
37
+
38
+ const ChartSeriesSchema = z.object({
39
+ name: z.string().min(1, 'Series name is required'),
40
+ field: z.string().min(1, 'Series field is required'),
41
+ color: z.string().optional(),
42
+ })
43
+
44
+ const LineChartSchema = ChartBaseSchema.extend({
45
+ type: z.literal('line'),
46
+ x_field: z.string().optional(),
47
+ y_field: z.string().optional(),
48
+ series_name: z.string().optional(),
49
+ color: z.string().optional(),
50
+ })
51
+
52
+ const BarChartSchema = ChartBaseSchema.extend({
53
+ type: z.literal('bar'),
54
+ label_field: z.string().optional(),
55
+ value_field: z.string().optional(),
56
+ bucket_field: z.string().optional(),
57
+ buckets: z.array(ChartBucketSchema).optional(),
58
+ color: z.string().optional(),
59
+ })
60
+
61
+ const StackedBarChartSchema = ChartBaseSchema.extend({
62
+ type: z.literal('stacked_bar'),
63
+ x_field: z.string().optional(),
64
+ series: z.array(ChartSeriesSchema).optional(),
65
+ colors: z.array(z.string()).optional(),
66
+ })
67
+
68
+ const PieChartSchema = ChartBaseSchema.extend({
69
+ type: z.literal('pie'),
70
+ label_field: z.string().optional(),
71
+ value_field: z.string().optional(),
72
+ colors: z.array(z.string()).optional(),
73
+ })
74
+
75
+ const HistogramChartSchema = ChartBaseSchema.extend({
76
+ type: z.literal('histogram'),
77
+ label_field: z.string().optional(),
78
+ value_field: z.string().optional(),
79
+ bucket_field: z.string().optional(),
80
+ buckets: z.array(ChartBucketSchema).optional(),
81
+ color: z.string().optional(),
82
+ })
83
+
84
+ const FunnelChartSchema = ChartBaseSchema.extend({
85
+ type: z.literal('funnel'),
86
+ label_field: z.string().optional(),
87
+ value_field: z.string().optional(),
88
+ colors: z.array(z.string()).optional(),
89
+ })
90
+
91
+ export const ChartConfigSchema = z.discriminatedUnion('type', [
92
+ LineChartSchema,
93
+ BarChartSchema,
94
+ StackedBarChartSchema,
95
+ PieChartSchema,
96
+ HistogramChartSchema,
97
+ FunnelChartSchema,
98
+ ])
99
+
100
+ export const DashboardWidgetQuerySchema = z.object({
101
+ resource: z.string().min(1, 'Query resource must be a non-empty string'),
102
+ select: z.array(z.string()).optional(),
103
+ order: z.object({
104
+ field: z.string().min(1, 'Order field is required'),
105
+ direction: z.enum(['asc', 'desc']),
106
+ }).optional(),
107
+ limit: z.number().optional(),
108
+ })
109
+
110
+ export const EmptyWidgetConfigSchema = WidgetBaseSchema.extend({
111
+ target: z.literal('empty'),
112
+ })
113
+
114
+ const TableWidgetConfigSchema = WidgetBaseSchema.extend({
115
+ target: z.literal('table'),
116
+ table: z.unknown().optional(),
117
+ query: DashboardWidgetQuerySchema.optional(),
118
+ })
119
+
120
+ const ChartWidgetTargetConfigSchema = WidgetBaseSchema.extend({
121
+ target: z.literal('chart'),
122
+ chart: ChartConfigSchema,
123
+ query: DashboardWidgetQuerySchema,
124
+ })
125
+
126
+ const KpiCardWidgetConfigSchema = WidgetBaseSchema.extend({
127
+ target: z.literal('kpi_card'),
128
+ kpi_card: z.unknown().optional(),
129
+ query: DashboardWidgetQuerySchema.optional(),
130
+ })
131
+
132
+ const GaugeCardWidgetConfigSchema = WidgetBaseSchema.extend({
133
+ target: z.literal('gauge_card'),
134
+ gauge_card: z.unknown().optional(),
135
+ query: DashboardWidgetQuerySchema.optional(),
136
+ })
137
+
138
+ const PivotTableWidgetConfigSchema = WidgetBaseSchema.extend({
139
+ target: z.literal('pivot_table'),
140
+ pivot_table: z.unknown().optional(),
141
+ query: DashboardWidgetQuerySchema.optional(),
142
+ })
143
+
144
+ export const WidgetConfigSchema = z.discriminatedUnion('target', [
145
+ TableWidgetConfigSchema,
146
+ ChartWidgetTargetConfigSchema,
147
+ KpiCardWidgetConfigSchema,
148
+ GaugeCardWidgetConfigSchema,
149
+ PivotTableWidgetConfigSchema,
150
+ ])
151
+
152
+ export const StoredWidgetConfigSchema = z.discriminatedUnion('target', [
153
+ EmptyWidgetConfigSchema,
154
+ TableWidgetConfigSchema,
155
+ ChartWidgetTargetConfigSchema,
156
+ KpiCardWidgetConfigSchema,
157
+ GaugeCardWidgetConfigSchema,
158
+ PivotTableWidgetConfigSchema,
159
+ ])
@@ -0,0 +1,136 @@
1
+ import { Filters } from 'adminforth';
2
+ import type { IAdminForth } from 'adminforth';
3
+ import { normalizeDashboardConfig } from '../custom/model/dashboard.types.js';
4
+ import type { DashboardConfig, DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
5
+
6
+ const DASHBOARD_CONFIG_UPDATED_TOPIC_PREFIX = '/opentopic/dashboard-config-updated';
7
+
8
+ export type DashboardRecord = {
9
+ id: string;
10
+ slug: string;
11
+ label: string;
12
+ revision: number;
13
+ config: unknown;
14
+ };
15
+
16
+ export function parseStoredDashboardConfig(config: unknown): DashboardConfig {
17
+ if (typeof config === 'string') {
18
+ return normalizeDashboardConfig(JSON.parse(config));
19
+ }
20
+
21
+ return normalizeDashboardConfig(config);
22
+ }
23
+
24
+ export function buildDashboardResponse(dashboard: DashboardRecord) {
25
+ return {
26
+ id: dashboard.id,
27
+ slug: dashboard.slug,
28
+ label: dashboard.label,
29
+ revision: dashboard.revision,
30
+ config: parseStoredDashboardConfig(dashboard.config),
31
+ };
32
+ }
33
+
34
+ export type PersistedDashboardResponse = {
35
+ id: string;
36
+ slug: string;
37
+ label: string;
38
+ revision: number;
39
+ config: DashboardConfig;
40
+ };
41
+
42
+ export function dashboardConfigUpdatedTopic(slug: string) {
43
+ return `${DASHBOARD_CONFIG_UPDATED_TOPIC_PREFIX}/${slug}`;
44
+ }
45
+
46
+ export function normalizeDashboardOrder(config: DashboardConfig): DashboardConfig {
47
+ const widgetsByGroupId = new Map<string, DashboardWidgetConfig[]>();
48
+
49
+ for (const widget of config.widgets) {
50
+ const groupWidgets = widgetsByGroupId.get(widget.group_id) ?? [];
51
+ groupWidgets.push(widget);
52
+ widgetsByGroupId.set(widget.group_id, groupWidgets);
53
+ }
54
+
55
+ for (const [groupId, widgets] of widgetsByGroupId.entries()) {
56
+ widgetsByGroupId.set(groupId, [...widgets].sort((a, b) => a.order - b.order));
57
+ }
58
+
59
+ return {
60
+ ...config,
61
+ groups: config.groups.map((group, index) => ({
62
+ ...group,
63
+ order: index + 1,
64
+ })),
65
+ widgets: config.widgets.map((widget) => ({
66
+ ...widget,
67
+ order: widgetsByGroupId.get(widget.group_id)!.findIndex((item) => item.id === widget.id) + 1,
68
+ })),
69
+ };
70
+ }
71
+
72
+ export async function getDashboardRecord(
73
+ adminforth: IAdminForth,
74
+ dashboardConfigsResourceId: string,
75
+ slug: string,
76
+ ): Promise<DashboardRecord | null> {
77
+ const dashboardConfigs = adminforth.resource(dashboardConfigsResourceId);
78
+ const dashboard = await dashboardConfigs.get(Filters.EQ('slug', slug));
79
+
80
+ return dashboard || null;
81
+ }
82
+
83
+ export async function persistDashboardConfig(
84
+ adminforth: IAdminForth,
85
+ dashboardConfigsResourceId: string,
86
+ dashboard: DashboardRecord,
87
+ config: DashboardConfig,
88
+ ): Promise<PersistedDashboardResponse> {
89
+ const normalizedConfig = normalizeDashboardOrder(config);
90
+
91
+ await adminforth.resource(dashboardConfigsResourceId).update(dashboard.id, {
92
+ config: normalizedConfig,
93
+ revision: dashboard.revision + 1,
94
+ });
95
+
96
+ await adminforth.websocket.publish(dashboardConfigUpdatedTopic(dashboard.slug), {
97
+ id: dashboard.id,
98
+ slug: dashboard.slug,
99
+ revision: dashboard.revision + 1,
100
+ });
101
+
102
+ return {
103
+ id: dashboard.id,
104
+ slug: dashboard.slug,
105
+ label: dashboard.label,
106
+ revision: dashboard.revision + 1,
107
+ config: normalizedConfig,
108
+ };
109
+ }
110
+
111
+ export type DashboardConfigService = {
112
+ getDashboardRecord: (slug: string) => Promise<DashboardRecord | null>;
113
+ parseStoredDashboardConfig: typeof parseStoredDashboardConfig;
114
+ persistDashboardConfig: (
115
+ dashboard: DashboardRecord,
116
+ config: DashboardConfig,
117
+ ) => Promise<PersistedDashboardResponse>;
118
+ buildDashboardResponse: typeof buildDashboardResponse;
119
+ };
120
+
121
+ export function createDashboardConfigService(
122
+ adminforth: IAdminForth,
123
+ dashboardConfigsResourceId: string,
124
+ ): DashboardConfigService {
125
+ return {
126
+ getDashboardRecord: (slug) => getDashboardRecord(adminforth, dashboardConfigsResourceId, slug),
127
+ parseStoredDashboardConfig,
128
+ persistDashboardConfig: (dashboard, config) => persistDashboardConfig(
129
+ adminforth,
130
+ dashboardConfigsResourceId,
131
+ dashboard,
132
+ config,
133
+ ),
134
+ buildDashboardResponse,
135
+ };
136
+ }
@@ -0,0 +1,93 @@
1
+ import type { IAdminForth } from 'adminforth';
2
+ import type { DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
3
+ import type { DashboardWidgetConfigValidationError } from '../schema/widget.js';
4
+ import type { DashboardWidgetQueryConfig } from './widgetDataService.js';
5
+
6
+ export type WidgetConfigValidatorService = {
7
+ validateDashboardWidgetApiConfig: (
8
+ widget: DashboardWidgetConfig,
9
+ ) => DashboardWidgetConfigValidationError[];
10
+ };
11
+
12
+ export function validateDashboardWidgetApiConfig(
13
+ adminforth: IAdminForth,
14
+ widget: DashboardWidgetConfig,
15
+ ): DashboardWidgetConfigValidationError[] {
16
+ if (widget.target !== 'chart') {
17
+ return [];
18
+ }
19
+
20
+ const errors: DashboardWidgetConfigValidationError[] = [];
21
+
22
+ if (!widget.query) {
23
+ errors.push({
24
+ field: 'query',
25
+ message: 'Chart widget must have query config',
26
+ });
27
+ return errors;
28
+ }
29
+
30
+ if (!widget.chart) {
31
+ errors.push({
32
+ field: 'chart',
33
+ message: 'Chart widget must have chart config',
34
+ });
35
+ return errors;
36
+ }
37
+
38
+ const query = widget.query as DashboardWidgetQueryConfig;
39
+ const chart = widget.chart;
40
+
41
+ const resource = adminforth.config.resources.find((item) => item.resourceId === query.resource);
42
+
43
+ if (!resource) {
44
+ errors.push({
45
+ field: 'query.resource',
46
+ message: `Resource "${query.resource}" is not registered`,
47
+ });
48
+ return errors;
49
+ }
50
+
51
+ if (!query.select) {
52
+ return errors;
53
+ }
54
+
55
+ const resourceFields = resource.columns.map((column) => column.name);
56
+
57
+ for (const field of query.select) {
58
+ if (!resourceFields.includes(field)) {
59
+ errors.push({
60
+ field: 'query.select',
61
+ message: `Field "${field}" is not in resource "${query.resource}"`,
62
+ });
63
+ }
64
+ }
65
+
66
+ const chartFields = [
67
+ chart.x_field,
68
+ chart.y_field,
69
+ chart.label_field,
70
+ chart.value_field,
71
+ chart.bucket_field,
72
+ ...(chart.series?.map((series: { field: string }) => series.field) ?? []),
73
+ ].filter((field): field is string => typeof field === 'string');
74
+
75
+ for (const field of chartFields) {
76
+ if (!query.select.includes(field)) {
77
+ errors.push({
78
+ field: 'query.select',
79
+ message: `Query select must include chart field "${field}"`,
80
+ });
81
+ }
82
+ }
83
+
84
+ return errors;
85
+ }
86
+
87
+ export function createWidgetConfigValidatorService(
88
+ adminforth: IAdminForth,
89
+ ): WidgetConfigValidatorService {
90
+ return {
91
+ validateDashboardWidgetApiConfig: (widget) => validateDashboardWidgetApiConfig(adminforth, widget),
92
+ };
93
+ }
@@ -0,0 +1,57 @@
1
+ import { Sorts } from 'adminforth';
2
+ import type { IAdminForth } from 'adminforth';
3
+ import type { DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
4
+
5
+ export type DashboardWidgetQueryConfig = {
6
+ resource: string;
7
+ select?: string[];
8
+ order?: {
9
+ field: string;
10
+ direction: 'asc' | 'desc';
11
+ };
12
+ limit?: number;
13
+ };
14
+
15
+ export type DashboardWidgetData = {
16
+ columns: string[];
17
+ rows: Record<string, unknown>[];
18
+ };
19
+
20
+ export type WidgetDataService = {
21
+ getWidgetData: (widget: DashboardWidgetConfig) => Promise<DashboardWidgetData | null>;
22
+ };
23
+
24
+ export async function getWidgetData(
25
+ adminforth: IAdminForth,
26
+ widget: DashboardWidgetConfig,
27
+ ): Promise<DashboardWidgetData | null> {
28
+ if (!widget.query) {
29
+ return null;
30
+ }
31
+
32
+ const query = widget.query as DashboardWidgetQueryConfig;
33
+
34
+ const rows = await adminforth.resource(query.resource).list(
35
+ [],
36
+ query.limit,
37
+ 0,
38
+ query.order
39
+ ? [query.order.direction === 'desc' ? Sorts.DESC(query.order.field) : Sorts.ASC(query.order.field)]
40
+ : undefined,
41
+ );
42
+
43
+ const columns = query.select ?? Object.keys(rows[0] ?? {});
44
+
45
+ return {
46
+ columns,
47
+ rows: rows.map((row) => (
48
+ Object.fromEntries(columns.map((column) => [column, row[column]]))
49
+ )),
50
+ };
51
+ }
52
+
53
+ export function createWidgetDataService(adminforth: IAdminForth): WidgetDataService {
54
+ return {
55
+ getWidgetData: (widget) => getWidgetData(adminforth, widget),
56
+ };
57
+ }
package/shims-vue.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ declare module '*.vue' {
2
+ import type { DefineComponent } from 'vue';
3
+ const component: DefineComponent<{}, {}, any>;
4
+ export default component;
5
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2016",
4
+ "lib": ["ES2021", "DOM", "DOM.Iterable"],
5
+ "module": "node16",
6
+ "outDir": "./dist",
7
+ "declaration": true,
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "strict": true,
11
+ "skipLibCheck": true,
12
+ "paths": {
13
+ "@/afcl": ["./node_modules/adminforth/dist/spa/src/afcl/index.ts"],
14
+ "@/*": ["./node_modules/adminforth/dist/spa/src/*"]
15
+ }
16
+ },
17
+ "exclude": ["node_modules", "dist"]
18
+ }
package/types.ts ADDED
@@ -0,0 +1,8 @@
1
+ export type PluginOptions = {
2
+ /**
3
+ * ResourceId of a resource that stores dashboard configs.
4
+ *
5
+ * Expected columns: id, slug, label, revision, config (JSON).
6
+ */
7
+ dashboardConfigsResourceId: string;
8
+ };