@gridframe/core 1.0.0 → 1.0.1
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 +1550 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +322 -0
- package/package.json +11 -3
- package/src/index.test.ts +0 -133
- package/src/index.ts +0 -454
package/src/index.ts
DELETED
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
const nullableScalarSchema = z.union([z.string(), z.number(), z.null()]);
|
|
4
|
-
|
|
5
|
-
export const VisualizationTypeSchema = z.enum([
|
|
6
|
-
"metric",
|
|
7
|
-
"area",
|
|
8
|
-
"bar",
|
|
9
|
-
"line",
|
|
10
|
-
"pie",
|
|
11
|
-
"radar",
|
|
12
|
-
"radial",
|
|
13
|
-
"table",
|
|
14
|
-
]);
|
|
15
|
-
export type VisualizationType = z.infer<typeof VisualizationTypeSchema>;
|
|
16
|
-
|
|
17
|
-
export const DashboardFooterConfigSchema = z.object({
|
|
18
|
-
text: z.string(),
|
|
19
|
-
href: z.string().optional(),
|
|
20
|
-
});
|
|
21
|
-
export type DashboardFooterConfig = z.infer<typeof DashboardFooterConfigSchema>;
|
|
22
|
-
|
|
23
|
-
export const CardDeeplinkConfigSchema = z.object({
|
|
24
|
-
href: z.string(),
|
|
25
|
-
label: z.string().optional(),
|
|
26
|
-
});
|
|
27
|
-
export type CardDeeplinkConfig = z.infer<typeof CardDeeplinkConfigSchema>;
|
|
28
|
-
|
|
29
|
-
export const DashboardCardLayoutSchema = z.object({
|
|
30
|
-
x: z.number().int().nonnegative(),
|
|
31
|
-
y: z.number().int().nonnegative(),
|
|
32
|
-
width: z.number().int().positive(),
|
|
33
|
-
height: z.number().int().positive(),
|
|
34
|
-
});
|
|
35
|
-
export type DashboardCardLayout = z.infer<typeof DashboardCardLayoutSchema>;
|
|
36
|
-
|
|
37
|
-
export const DashboardCardConfigSchema = z.object({
|
|
38
|
-
id: z.string(),
|
|
39
|
-
name: z.string(),
|
|
40
|
-
visualization: VisualizationTypeSchema,
|
|
41
|
-
query: z.string(),
|
|
42
|
-
deeplink: CardDeeplinkConfigSchema.optional(),
|
|
43
|
-
layout: DashboardCardLayoutSchema.optional(),
|
|
44
|
-
});
|
|
45
|
-
export type DashboardCardConfig = z.infer<typeof DashboardCardConfigSchema>;
|
|
46
|
-
|
|
47
|
-
export const ApiDashboardCardConfigSchema = DashboardCardConfigSchema.extend({
|
|
48
|
-
layout: DashboardCardLayoutSchema,
|
|
49
|
-
});
|
|
50
|
-
export type ApiDashboardCardConfig = z.infer<
|
|
51
|
-
typeof ApiDashboardCardConfigSchema
|
|
52
|
-
>;
|
|
53
|
-
|
|
54
|
-
export const PanelDashboardConfigSchema = z.object({
|
|
55
|
-
title: z.string(),
|
|
56
|
-
description: z.string().optional(),
|
|
57
|
-
footer: DashboardFooterConfigSchema.optional(),
|
|
58
|
-
cards: z.array(DashboardCardConfigSchema),
|
|
59
|
-
});
|
|
60
|
-
export type PanelDashboardConfig = z.infer<typeof PanelDashboardConfigSchema>;
|
|
61
|
-
|
|
62
|
-
export const ApiPanelDashboardConfigSchema = PanelDashboardConfigSchema.extend({
|
|
63
|
-
cards: z.array(ApiDashboardCardConfigSchema),
|
|
64
|
-
});
|
|
65
|
-
export type ApiPanelDashboardConfig = z.infer<
|
|
66
|
-
typeof ApiPanelDashboardConfigSchema
|
|
67
|
-
>;
|
|
68
|
-
|
|
69
|
-
export const MetricTrendSchema = z.object({
|
|
70
|
-
direction: z.enum(["up", "down", "neutral"]),
|
|
71
|
-
value: z.string(),
|
|
72
|
-
label: z.string().optional(),
|
|
73
|
-
});
|
|
74
|
-
export type MetricTrend = z.infer<typeof MetricTrendSchema>;
|
|
75
|
-
|
|
76
|
-
export const MetricCardDataSchema = z.object({
|
|
77
|
-
visualization: z.literal("metric"),
|
|
78
|
-
value: z.union([z.string(), z.number()]),
|
|
79
|
-
label: z.string().optional(),
|
|
80
|
-
helperText: z.string().optional(),
|
|
81
|
-
trend: MetricTrendSchema.optional(),
|
|
82
|
-
});
|
|
83
|
-
export type MetricCardData = z.infer<typeof MetricCardDataSchema>;
|
|
84
|
-
|
|
85
|
-
export const ChartSeriesSchema = z.object({
|
|
86
|
-
key: z.string(),
|
|
87
|
-
label: z.string(),
|
|
88
|
-
color: z.string(),
|
|
89
|
-
icon: z.string().optional(),
|
|
90
|
-
});
|
|
91
|
-
export type ChartSeries = z.infer<typeof ChartSeriesSchema>;
|
|
92
|
-
|
|
93
|
-
export const ChartDatumSchema = z.record(z.string(), nullableScalarSchema);
|
|
94
|
-
export type ChartDatum = z.infer<typeof ChartDatumSchema>;
|
|
95
|
-
|
|
96
|
-
export const ChartTooltipOptionsSchema = z.object({
|
|
97
|
-
indicator: z.enum(["dot", "line", "dashed", "none"]).optional(),
|
|
98
|
-
hideLabel: z.boolean().optional(),
|
|
99
|
-
label: z.string().optional(),
|
|
100
|
-
labelFormatter: z.literal("date").optional(),
|
|
101
|
-
valueFormatter: z.enum(["compact", "currency", "percent"]).optional(),
|
|
102
|
-
advanced: z.boolean().optional(),
|
|
103
|
-
});
|
|
104
|
-
export type ChartTooltipOptions = z.infer<typeof ChartTooltipOptionsSchema>;
|
|
105
|
-
|
|
106
|
-
export const BarChartCardDataSchema = z.object({
|
|
107
|
-
visualization: z.literal("bar"),
|
|
108
|
-
indexKey: z.string(),
|
|
109
|
-
data: z.array(ChartDatumSchema),
|
|
110
|
-
series: z.array(ChartSeriesSchema),
|
|
111
|
-
variant: z.string().optional(),
|
|
112
|
-
layout: z.enum(["vertical", "horizontal"]).optional(),
|
|
113
|
-
stacked: z.boolean().optional(),
|
|
114
|
-
showLabels: z.boolean().optional(),
|
|
115
|
-
customLabels: z.boolean().optional(),
|
|
116
|
-
mixed: z.boolean().optional(),
|
|
117
|
-
activeIndex: z.number().int().optional(),
|
|
118
|
-
tooltip: ChartTooltipOptionsSchema.optional(),
|
|
119
|
-
});
|
|
120
|
-
export type BarChartCardData = z.infer<typeof BarChartCardDataSchema>;
|
|
121
|
-
|
|
122
|
-
export const AreaChartCardDataSchema = z.object({
|
|
123
|
-
visualization: z.literal("area"),
|
|
124
|
-
indexKey: z.string(),
|
|
125
|
-
data: z.array(ChartDatumSchema),
|
|
126
|
-
series: z.array(ChartSeriesSchema),
|
|
127
|
-
variant: z.string().optional(),
|
|
128
|
-
curveType: z.enum(["natural", "linear", "step"]).optional(),
|
|
129
|
-
stacked: z.boolean().optional(),
|
|
130
|
-
stackOffset: z.literal("expand").optional(),
|
|
131
|
-
showLegend: z.boolean().optional(),
|
|
132
|
-
showGradient: z.boolean().optional(),
|
|
133
|
-
showAxes: z.boolean().optional(),
|
|
134
|
-
interactive: z.boolean().optional(),
|
|
135
|
-
tooltip: ChartTooltipOptionsSchema.optional(),
|
|
136
|
-
});
|
|
137
|
-
export type AreaChartCardData = z.infer<typeof AreaChartCardDataSchema>;
|
|
138
|
-
|
|
139
|
-
export const LineChartCardDataSchema = z.object({
|
|
140
|
-
visualization: z.literal("line"),
|
|
141
|
-
indexKey: z.string(),
|
|
142
|
-
data: z.array(ChartDatumSchema),
|
|
143
|
-
series: z.array(ChartSeriesSchema),
|
|
144
|
-
variant: z.string().optional(),
|
|
145
|
-
curveType: z.enum(["monotone", "linear", "step"]).optional(),
|
|
146
|
-
showDots: z.boolean().optional(),
|
|
147
|
-
customDots: z.boolean().optional(),
|
|
148
|
-
colorDots: z.boolean().optional(),
|
|
149
|
-
showLabels: z.boolean().optional(),
|
|
150
|
-
customLabels: z.boolean().optional(),
|
|
151
|
-
interactive: z.boolean().optional(),
|
|
152
|
-
tooltip: ChartTooltipOptionsSchema.optional(),
|
|
153
|
-
});
|
|
154
|
-
export type LineChartCardData = z.infer<typeof LineChartCardDataSchema>;
|
|
155
|
-
|
|
156
|
-
export const PieChartCardDataSchema = z.object({
|
|
157
|
-
visualization: z.literal("pie"),
|
|
158
|
-
nameKey: z.string(),
|
|
159
|
-
valueKey: z.string(),
|
|
160
|
-
data: z.array(ChartDatumSchema),
|
|
161
|
-
series: z.array(ChartSeriesSchema),
|
|
162
|
-
variant: z.string().optional(),
|
|
163
|
-
separator: z.boolean().optional(),
|
|
164
|
-
showLabels: z.boolean().optional(),
|
|
165
|
-
customLabels: z.boolean().optional(),
|
|
166
|
-
labelList: z.boolean().optional(),
|
|
167
|
-
showLegend: z.boolean().optional(),
|
|
168
|
-
donut: z.boolean().optional(),
|
|
169
|
-
activeIndex: z.number().int().optional(),
|
|
170
|
-
centerText: z.string().optional(),
|
|
171
|
-
stacked: z.boolean().optional(),
|
|
172
|
-
interactive: z.boolean().optional(),
|
|
173
|
-
tooltip: ChartTooltipOptionsSchema.optional(),
|
|
174
|
-
});
|
|
175
|
-
export type PieChartCardData = z.infer<typeof PieChartCardDataSchema>;
|
|
176
|
-
|
|
177
|
-
export const RadarChartCardDataSchema = z.object({
|
|
178
|
-
visualization: z.literal("radar"),
|
|
179
|
-
indexKey: z.string(),
|
|
180
|
-
data: z.array(ChartDatumSchema),
|
|
181
|
-
series: z.array(ChartSeriesSchema),
|
|
182
|
-
variant: z.string().optional(),
|
|
183
|
-
showDots: z.boolean().optional(),
|
|
184
|
-
linesOnly: z.boolean().optional(),
|
|
185
|
-
customLabels: z.boolean().optional(),
|
|
186
|
-
gridType: z.enum(["polygon", "circle"]).optional(),
|
|
187
|
-
gridFill: z.boolean().optional(),
|
|
188
|
-
gridLines: z.boolean().optional(),
|
|
189
|
-
radialLines: z.boolean().optional(),
|
|
190
|
-
showLegend: z.boolean().optional(),
|
|
191
|
-
tooltip: ChartTooltipOptionsSchema.optional(),
|
|
192
|
-
});
|
|
193
|
-
export type RadarChartCardData = z.infer<typeof RadarChartCardDataSchema>;
|
|
194
|
-
|
|
195
|
-
export const RadialChartCardDataSchema = z.object({
|
|
196
|
-
visualization: z.literal("radial"),
|
|
197
|
-
nameKey: z.string(),
|
|
198
|
-
valueKey: z.string(),
|
|
199
|
-
data: z.array(ChartDatumSchema),
|
|
200
|
-
series: z.array(ChartSeriesSchema),
|
|
201
|
-
variant: z.string().optional(),
|
|
202
|
-
showLabel: z.boolean().optional(),
|
|
203
|
-
showGrid: z.boolean().optional(),
|
|
204
|
-
centerText: z.string().optional(),
|
|
205
|
-
shape: z.enum(["round", "square"]).optional(),
|
|
206
|
-
stacked: z.boolean().optional(),
|
|
207
|
-
tooltip: ChartTooltipOptionsSchema.optional(),
|
|
208
|
-
});
|
|
209
|
-
export type RadialChartCardData = z.infer<typeof RadialChartCardDataSchema>;
|
|
210
|
-
|
|
211
|
-
export const TableColumnSchema = z.object({
|
|
212
|
-
key: z.string(),
|
|
213
|
-
label: z.string(),
|
|
214
|
-
align: z.enum(["left", "right"]).optional(),
|
|
215
|
-
});
|
|
216
|
-
export type TableColumn = z.infer<typeof TableColumnSchema>;
|
|
217
|
-
|
|
218
|
-
export const TableRowSchema = z.record(z.string(), nullableScalarSchema);
|
|
219
|
-
export type TableRow = z.infer<typeof TableRowSchema>;
|
|
220
|
-
|
|
221
|
-
export const TableCardDataSchema = z.object({
|
|
222
|
-
visualization: z.literal("table"),
|
|
223
|
-
columns: z.array(TableColumnSchema),
|
|
224
|
-
rows: z.array(TableRowSchema),
|
|
225
|
-
});
|
|
226
|
-
export type TableCardData = z.infer<typeof TableCardDataSchema>;
|
|
227
|
-
|
|
228
|
-
export const PanelCardPayloadSchema = z.discriminatedUnion("visualization", [
|
|
229
|
-
MetricCardDataSchema,
|
|
230
|
-
AreaChartCardDataSchema,
|
|
231
|
-
BarChartCardDataSchema,
|
|
232
|
-
LineChartCardDataSchema,
|
|
233
|
-
PieChartCardDataSchema,
|
|
234
|
-
RadarChartCardDataSchema,
|
|
235
|
-
RadialChartCardDataSchema,
|
|
236
|
-
TableCardDataSchema,
|
|
237
|
-
]);
|
|
238
|
-
export type PanelCardPayload = z.infer<typeof PanelCardPayloadSchema>;
|
|
239
|
-
|
|
240
|
-
export const SourceDataTableSchema = z.object({
|
|
241
|
-
columns: z.array(TableColumnSchema),
|
|
242
|
-
rows: z.array(TableRowSchema),
|
|
243
|
-
});
|
|
244
|
-
export type SourceDataTable = z.infer<typeof SourceDataTableSchema>;
|
|
245
|
-
|
|
246
|
-
const panelCardDataSuccessSchema = z.object({
|
|
247
|
-
status: z.literal("success"),
|
|
248
|
-
data: PanelCardPayloadSchema,
|
|
249
|
-
sourceData: SourceDataTableSchema.optional(),
|
|
250
|
-
});
|
|
251
|
-
const panelCardDataEmptySchema = z.object({
|
|
252
|
-
status: z.literal("empty"),
|
|
253
|
-
message: z.string().optional(),
|
|
254
|
-
});
|
|
255
|
-
const panelCardDataErrorSchema = z.object({
|
|
256
|
-
status: z.literal("error"),
|
|
257
|
-
message: z.string(),
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
export const PanelCardDataResponseSchema = z.discriminatedUnion("status", [
|
|
261
|
-
panelCardDataSuccessSchema,
|
|
262
|
-
panelCardDataEmptySchema,
|
|
263
|
-
panelCardDataErrorSchema,
|
|
264
|
-
]);
|
|
265
|
-
export type PanelCardDataResponse = z.infer<typeof PanelCardDataResponseSchema>;
|
|
266
|
-
|
|
267
|
-
export const PanelCardDataWithSourceResponseSchema = z.discriminatedUnion(
|
|
268
|
-
"status",
|
|
269
|
-
[
|
|
270
|
-
panelCardDataSuccessSchema.extend({ sourceData: SourceDataTableSchema }),
|
|
271
|
-
panelCardDataEmptySchema,
|
|
272
|
-
panelCardDataErrorSchema,
|
|
273
|
-
],
|
|
274
|
-
);
|
|
275
|
-
export type PanelCardDataWithSourceResponse = z.infer<
|
|
276
|
-
typeof PanelCardDataWithSourceResponseSchema
|
|
277
|
-
>;
|
|
278
|
-
|
|
279
|
-
export const DashboardSummarySchema = z.object({
|
|
280
|
-
id: z.string(),
|
|
281
|
-
title: z.string(),
|
|
282
|
-
isDefault: z.boolean(),
|
|
283
|
-
});
|
|
284
|
-
export type DashboardSummary = z.infer<typeof DashboardSummarySchema>;
|
|
285
|
-
|
|
286
|
-
export const DashboardDocumentSchema = z.object({
|
|
287
|
-
id: z.string(),
|
|
288
|
-
revision: z.string(),
|
|
289
|
-
config: ApiPanelDashboardConfigSchema,
|
|
290
|
-
});
|
|
291
|
-
export type DashboardDocument = z.infer<typeof DashboardDocumentSchema>;
|
|
292
|
-
|
|
293
|
-
export const DashboardBootstrapRequestSchema = z.object({
|
|
294
|
-
dashboardId: z.string().optional(),
|
|
295
|
-
});
|
|
296
|
-
export type DashboardBootstrapRequest = z.infer<
|
|
297
|
-
typeof DashboardBootstrapRequestSchema
|
|
298
|
-
>;
|
|
299
|
-
|
|
300
|
-
export const DashboardBootstrapResponseSchema = z.object({
|
|
301
|
-
dashboards: z.array(DashboardSummarySchema),
|
|
302
|
-
dashboard: DashboardDocumentSchema,
|
|
303
|
-
});
|
|
304
|
-
export type DashboardBootstrapResponse = z.infer<
|
|
305
|
-
typeof DashboardBootstrapResponseSchema
|
|
306
|
-
>;
|
|
307
|
-
|
|
308
|
-
export const DashboardApiErrorCodeSchema = z.enum([
|
|
309
|
-
"INVALID_REQUEST",
|
|
310
|
-
"DASHBOARD_NOT_FOUND",
|
|
311
|
-
"DASHBOARD_LOAD_FAILED",
|
|
312
|
-
"DASHBOARD_CARD_NOT_FOUND",
|
|
313
|
-
"CARD_QUERY_FAILED",
|
|
314
|
-
"REVISION_CONFLICT",
|
|
315
|
-
"CARD_ALREADY_ADDED",
|
|
316
|
-
]);
|
|
317
|
-
export type DashboardApiErrorCode = z.infer<typeof DashboardApiErrorCodeSchema>;
|
|
318
|
-
|
|
319
|
-
export const DashboardApiErrorSchema = z.object({
|
|
320
|
-
error: z.object({
|
|
321
|
-
code: DashboardApiErrorCodeSchema,
|
|
322
|
-
message: z.string(),
|
|
323
|
-
}),
|
|
324
|
-
});
|
|
325
|
-
export type DashboardApiError = z.infer<typeof DashboardApiErrorSchema>;
|
|
326
|
-
|
|
327
|
-
export const UpdateDashboardLayoutRequestSchema = z.object({
|
|
328
|
-
revision: z.string(),
|
|
329
|
-
cards: z.array(
|
|
330
|
-
z.object({
|
|
331
|
-
id: z.string(),
|
|
332
|
-
...DashboardCardLayoutSchema.shape,
|
|
333
|
-
}),
|
|
334
|
-
),
|
|
335
|
-
});
|
|
336
|
-
export type UpdateDashboardLayoutRequest = z.infer<
|
|
337
|
-
typeof UpdateDashboardLayoutRequestSchema
|
|
338
|
-
>;
|
|
339
|
-
export type DashboardLayoutItem = UpdateDashboardLayoutRequest["cards"][number];
|
|
340
|
-
|
|
341
|
-
export const UpdateDashboardCardRequestSchema = z.object({
|
|
342
|
-
revision: z.string(),
|
|
343
|
-
name: z.string(),
|
|
344
|
-
});
|
|
345
|
-
export type UpdateDashboardCardRequest = z.infer<
|
|
346
|
-
typeof UpdateDashboardCardRequestSchema
|
|
347
|
-
>;
|
|
348
|
-
|
|
349
|
-
export const CardLibraryItemSchema = z.object({
|
|
350
|
-
key: z.string(),
|
|
351
|
-
name: z.string(),
|
|
352
|
-
description: z.string().optional(),
|
|
353
|
-
visualization: VisualizationTypeSchema,
|
|
354
|
-
defaultLayout: z.object({
|
|
355
|
-
width: z.number().int().positive(),
|
|
356
|
-
height: z.number().int().positive(),
|
|
357
|
-
}),
|
|
358
|
-
addedCardId: z.string().optional(),
|
|
359
|
-
});
|
|
360
|
-
export type CardLibraryItem = z.infer<typeof CardLibraryItemSchema>;
|
|
361
|
-
|
|
362
|
-
export const CardLibraryResponseSchema = z.object({
|
|
363
|
-
items: z.array(CardLibraryItemSchema),
|
|
364
|
-
});
|
|
365
|
-
export type CardLibraryResponse = z.infer<typeof CardLibraryResponseSchema>;
|
|
366
|
-
|
|
367
|
-
export const AddDashboardCardRequestSchema = z.object({
|
|
368
|
-
revision: z.string(),
|
|
369
|
-
libraryItemKey: z.string(),
|
|
370
|
-
});
|
|
371
|
-
export type AddDashboardCardRequest = z.infer<
|
|
372
|
-
typeof AddDashboardCardRequestSchema
|
|
373
|
-
>;
|
|
374
|
-
|
|
375
|
-
export const RemoveDashboardCardRequestSchema = z.object({
|
|
376
|
-
revision: z.string(),
|
|
377
|
-
});
|
|
378
|
-
export type RemoveDashboardCardRequest = z.infer<
|
|
379
|
-
typeof RemoveDashboardCardRequestSchema
|
|
380
|
-
>;
|
|
381
|
-
|
|
382
|
-
export const DashboardCardMutationResponseSchema = z.object({
|
|
383
|
-
dashboard: DashboardDocumentSchema,
|
|
384
|
-
cardLibrary: CardLibraryResponseSchema,
|
|
385
|
-
});
|
|
386
|
-
export type DashboardCardMutationResponse = z.infer<
|
|
387
|
-
typeof DashboardCardMutationResponseSchema
|
|
388
|
-
>;
|
|
389
|
-
|
|
390
|
-
export const DASHBOARD_GRID_COLUMNS = 4;
|
|
391
|
-
|
|
392
|
-
export type DashboardLayoutValidationResult =
|
|
393
|
-
| { valid: true }
|
|
394
|
-
| { valid: false; errors: string[] };
|
|
395
|
-
|
|
396
|
-
export function validateDashboardLayout(
|
|
397
|
-
cards: readonly DashboardLayoutItem[],
|
|
398
|
-
expectedCardIds: readonly string[],
|
|
399
|
-
): DashboardLayoutValidationResult {
|
|
400
|
-
const errors: string[] = [];
|
|
401
|
-
const cardIds = cards.map((card) => card.id);
|
|
402
|
-
const uniqueCardIds = new Set(cardIds);
|
|
403
|
-
|
|
404
|
-
if (uniqueCardIds.size !== cardIds.length) {
|
|
405
|
-
errors.push("Card IDs must be unique");
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
const expectedIds = new Set(expectedCardIds);
|
|
409
|
-
if (
|
|
410
|
-
cards.length !== expectedCardIds.length ||
|
|
411
|
-
[...uniqueCardIds].some((cardId) => !expectedIds.has(cardId)) ||
|
|
412
|
-
[...expectedIds].some((cardId) => !uniqueCardIds.has(cardId))
|
|
413
|
-
) {
|
|
414
|
-
errors.push("Layout must contain exactly the Dashboard's Cards");
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
for (const card of cards) {
|
|
418
|
-
if (card.x + card.width > DASHBOARD_GRID_COLUMNS) {
|
|
419
|
-
errors.push(
|
|
420
|
-
`Card ${card.id} extends beyond the ${DASHBOARD_GRID_COLUMNS}-column grid`,
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
for (let index = 0; index < cards.length; index += 1) {
|
|
426
|
-
const first = cards[index];
|
|
427
|
-
|
|
428
|
-
for (
|
|
429
|
-
let otherIndex = index + 1;
|
|
430
|
-
otherIndex < cards.length;
|
|
431
|
-
otherIndex += 1
|
|
432
|
-
) {
|
|
433
|
-
const second = cards[otherIndex];
|
|
434
|
-
|
|
435
|
-
if (first && second && rectanglesOverlap(first, second)) {
|
|
436
|
-
errors.push(`Cards ${first.id} and ${second.id} overlap`);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return errors.length ? { valid: false, errors } : { valid: true };
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
function rectanglesOverlap(
|
|
445
|
-
first: DashboardCardLayout,
|
|
446
|
-
second: DashboardCardLayout,
|
|
447
|
-
) {
|
|
448
|
-
return (
|
|
449
|
-
first.x < second.x + second.width &&
|
|
450
|
-
first.x + first.width > second.x &&
|
|
451
|
-
first.y < second.y + second.height &&
|
|
452
|
-
first.y + first.height > second.y
|
|
453
|
-
);
|
|
454
|
-
}
|