Skip to content

Commit 3a1a8d2

Browse files
committed
Add @objectstack/spec and zod dependencies to Gantt, Map, and Timeline plugins; implement configuration validation
1 parent 687fbba commit 3a1a8d2

8 files changed

Lines changed: 158 additions & 39 deletions

File tree

apps/console/test-spec-import.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
import * as UI from '@objectstack/spec/ui';
3+
console.log('UI Exports:', Object.keys(UI).sort());
4+

packages/plugin-gantt/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@object-ui/fields": "workspace:*",
3737
"@object-ui/react": "workspace:*",
3838
"@object-ui/types": "workspace:*",
39+
"@objectstack/spec": "^0.9.2",
3940
"lucide-react": "^0.563.0"
4041
},
4142
"peerDependencies": {

packages/plugin-gantt/src/ObjectGantt.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import React, { useEffect, useState, useMemo } from 'react';
2626
import type { ObjectGridSchema, DataSource, ViewData, GanttConfig } from '@object-ui/types';
27+
import { GanttConfigSchema } from '@objectstack/spec/ui';
2728
import { GanttView, type GanttTask } from './GanttView';
2829

2930
export interface ObjectGanttProps {
@@ -91,14 +92,23 @@ function convertSortToQueryParams(sort: string | any[] | undefined): Record<stri
9192
* Helper to get gantt configuration from schema
9293
*/
9394
function getGanttConfig(schema: ObjectGridSchema): GanttConfig | null {
95+
let config: GanttConfig | null = null;
9496
// Check if schema has gantt configuration
9597
if (schema.filter && typeof schema.filter === 'object' && 'gantt' in schema.filter) {
96-
return (schema.filter as any).gantt as GanttConfig;
98+
config = (schema.filter as any).gantt as GanttConfig;
9799
}
98100

99101
// For backward compatibility, check if schema has gantt config at root
100-
if ((schema as any).gantt) {
101-
return (schema as any).gantt as GanttConfig;
102+
else if ((schema as any).gantt) {
103+
config = (schema as any).gantt as GanttConfig;
104+
}
105+
106+
if (config) {
107+
const result = GanttConfigSchema.safeParse(config);
108+
if (!result.success) {
109+
console.warn(`[ObjectGantt] Invalid gantt configuration:`, result.error.format());
110+
}
111+
return config;
102112
}
103113

104114
return null;

packages/plugin-map/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
"@object-ui/core": "workspace:*",
3636
"@object-ui/react": "workspace:*",
3737
"@object-ui/types": "workspace:*",
38-
"lucide-react": "^0.563.0"
38+
"@objectstack/spec": "^0.9.2",
39+
"lucide-react": "^0.563.0",
40+
"zod": "^4.3.6"
3941
},
4042
"peerDependencies": {
4143
"react": "^18.0.0 || ^19.0.0",

packages/plugin-map/src/ObjectMap.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@
2626

2727
import React, { useEffect, useState, useMemo } from 'react';
2828
import type { ObjectGridSchema, DataSource, ViewData } from '@object-ui/types';
29+
import { z } from 'zod';
30+
31+
const MapConfigSchema = z.object({
32+
latitudeField: z.string().optional(),
33+
longitudeField: z.string().optional(),
34+
locationField: z.string().optional(),
35+
titleField: z.string().optional(),
36+
descriptionField: z.string().optional(),
37+
zoom: z.number().optional(),
38+
center: z.tuple([z.number(), z.number()]).optional(),
39+
});
2940

3041
export interface ObjectMapProps {
3142
schema: ObjectGridSchema;
@@ -109,14 +120,23 @@ function convertSortToQueryParams(sort: string | any[] | undefined): Record<stri
109120
* Helper to get map configuration from schema
110121
*/
111122
function getMapConfig(schema: ObjectGridSchema): MapConfig {
123+
let config: MapConfig | null = null;
112124
// Check if schema has map configuration
113125
if (schema.filter && typeof schema.filter === 'object' && 'map' in schema.filter) {
114-
return (schema.filter as any).map as MapConfig;
126+
config = (schema.filter as any).map as MapConfig;
115127
}
116128

117129
// For backward compatibility, check if schema has map config at root
118-
if ((schema as any).map) {
119-
return (schema as any).map as MapConfig;
130+
else if ((schema as any).map) {
131+
config = (schema as any).map as MapConfig;
132+
}
133+
134+
if (config) {
135+
const result = MapConfigSchema.safeParse(config);
136+
if (!result.success) {
137+
console.warn(`[ObjectMap] Invalid map configuration:`, result.error.format());
138+
}
139+
return config;
120140
}
121141

122142
// Default configuration

packages/plugin-timeline/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@
3434
"@object-ui/components": "workspace:*",
3535
"@object-ui/core": "workspace:*",
3636
"@object-ui/react": "workspace:*",
37-
"@object-ui/types": "workspace:*"
37+
"@object-ui/types": "workspace:*",
38+
"@objectstack/spec": "^0.9.2",
39+
"zod": "^4.3.6"
3840
},
3941
"peerDependencies": {
4042
"react": "^18.0.0 || ^19.0.0",
4143
"react-dom": "^18.0.0 || ^19.0.0"
4244
},
4345
"devDependencies": {
46+
"@object-ui/data-objectstack": "workspace:*",
4447
"@types/react": "^19.2.10",
4548
"@types/react-dom": "^19.2.3",
4649
"@vitejs/plugin-react": "^5.1.3",
47-
"@object-ui/data-objectstack": "workspace:*",
4850
"typescript": "^5.9.3",
4951
"vite": "^7.3.1",
5052
"vite-plugin-dts": "^4.5.4"

packages/plugin-timeline/src/ObjectTimeline.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,24 @@
99
import React, { useEffect, useState } from 'react';
1010
import type { DataSource, TimelineSchema } from '@object-ui/types';
1111
import { useDataScope } from '@object-ui/react';
12+
import { z } from 'zod';
1213
import { TimelineRenderer } from './renderer';
1314

15+
const TimelineMappingSchema = z.object({
16+
title: z.string().optional(),
17+
date: z.string().optional(),
18+
description: z.string().optional(),
19+
variant: z.string().optional(),
20+
});
21+
22+
const TimelineExtensionSchema = z.object({
23+
mapping: TimelineMappingSchema.optional(),
24+
objectName: z.string().optional(),
25+
titleField: z.string().optional(),
26+
dateField: z.string().optional(),
27+
descriptionField: z.string().optional(),
28+
});
29+
1430
export interface ObjectTimelineProps {
1531
schema: TimelineSchema & {
1632
objectName?: string;
@@ -38,6 +54,13 @@ export const ObjectTimeline: React.FC<ObjectTimelineProps> = ({
3854
const [loading, setLoading] = useState(false);
3955
const [error, setError] = useState<Error | null>(null);
4056

57+
useEffect(() => {
58+
const result = TimelineExtensionSchema.safeParse(schema);
59+
if (!result.success) {
60+
console.warn(`[ObjectTimeline] Invalid timeline configuration:`, result.error.format());
61+
}
62+
}, [schema]);
63+
4164
const boundData = useDataScope(schema.bind);
4265

4366
useEffect(() => {

0 commit comments

Comments
 (0)