Skip to content

Commit 9698576

Browse files
committed
feat(CalendarView): add locale prop to support localization in date rendering
feat(ObjectGrid): add .well-known endpoint to MSW handlers for API discovery feat(ObjectForm): remove redundant 'form' type registration from ComponentRegistry fix(Kanban): update ComponentRegistry references to use 'kanban-ui' for consistency
1 parent 1c94f96 commit 9698576

6 files changed

Lines changed: 73 additions & 33 deletions

File tree

packages/plugin-calendar/src/CalendarView.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ describe('CalendarView', () => {
5050
const defaultDate = new Date(2024, 0, 15); // Jan 15, 2024
5151

5252
it('renders the header correctly', () => {
53-
render(<CalendarView currentDate={defaultDate} />);
53+
render(<CalendarView currentDate={defaultDate} locale="en-US" />);
5454

5555
// Check for month label
5656
expect(screen.getByText('January 2024')).toBeInTheDocument();
5757
});
5858

5959
it('renders navigation buttons', () => {
60-
render(<CalendarView currentDate={defaultDate} />);
60+
render(<CalendarView currentDate={defaultDate} locale="en-US" />);
6161

6262
expect(screen.getByText('Today')).toBeInTheDocument();
6363

@@ -77,7 +77,7 @@ describe('CalendarView', () => {
7777
});
7878

7979
it('renders the view switcher dropdown trigger', () => {
80-
render(<CalendarView currentDate={defaultDate} view="month" />);
80+
render(<CalendarView currentDate={defaultDate} view="month" locale="en-US" />);
8181
// The SelectValue should display "Month"
8282
const selectTrigger = screen.getByText('Month');
8383
expect(selectTrigger).toBeInTheDocument();
@@ -88,7 +88,7 @@ describe('CalendarView', () => {
8888
});
8989

9090
it('renders the date picker trigger', () => {
91-
render(<CalendarView currentDate={defaultDate} />);
91+
render(<CalendarView currentDate={defaultDate} locale="en-US" />);
9292
// The date label (e.g. "January 2024") is now inside a PopoverTrigger button
9393
const dateLabel = screen.getByText('January 2024');
9494
expect(dateLabel).toBeInTheDocument();
@@ -100,7 +100,7 @@ describe('CalendarView', () => {
100100

101101
it('opens date picker on click', () => {
102102
// We need to mock pointer interactions for Popover usually, but let's try basic click
103-
render(<CalendarView currentDate={defaultDate} />);
103+
render(<CalendarView currentDate={defaultDate} locale="en-US" />);
104104
const dateTrigger = screen.getByText('January 2024');
105105

106106
fireEvent.click(dateTrigger);
@@ -112,7 +112,7 @@ describe('CalendarView', () => {
112112
});
113113

114114
it('renders events in month view', () => {
115-
render(<CalendarView currentDate={defaultDate} events={mockEvents} />);
115+
render(<CalendarView currentDate={defaultDate} events={mockEvents} locale="en-US" />);
116116
expect(screen.getByText('Test Event 1')).toBeInTheDocument();
117117
});
118118
});

packages/plugin-calendar/src/CalendarView.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export interface CalendarViewProps {
4040
events?: CalendarEvent[]
4141
view?: "month" | "week" | "day"
4242
currentDate?: Date
43+
locale?: string
4344
onEventClick?: (event: CalendarEvent) => void
4445
onDateClick?: (date: Date) => void
4546
onViewChange?: (view: "month" | "week" | "day") => void
@@ -52,6 +53,7 @@ function CalendarView({
5253
events = [],
5354
view = "month",
5455
currentDate = new Date(),
56+
locale = "default",
5557
onEventClick,
5658
onDateClick,
5759
onViewChange,
@@ -110,24 +112,24 @@ function CalendarView({
110112

111113
const getDateLabel = () => {
112114
if (selectedView === "month") {
113-
return selectedDate.toLocaleDateString("default", {
115+
return selectedDate.toLocaleDateString(locale, {
114116
month: "long",
115117
year: "numeric",
116118
})
117119
} else if (selectedView === "week") {
118120
const weekStart = getWeekStart(selectedDate)
119121
const weekEnd = new Date(weekStart)
120122
weekEnd.setDate(weekEnd.getDate() + 6)
121-
return `${weekStart.toLocaleDateString("default", {
123+
return `${weekStart.toLocaleDateString(locale, {
122124
month: "short",
123125
day: "numeric",
124-
})} - ${weekEnd.toLocaleDateString("default", {
126+
})} - ${weekEnd.toLocaleDateString(locale, {
125127
month: "short",
126128
day: "numeric",
127129
year: "numeric",
128130
})}`
129131
} else {
130-
return selectedDate.toLocaleDateString("default", {
132+
return selectedDate.toLocaleDateString(locale, {
131133
weekday: "long",
132134
month: "long",
133135
day: "numeric",
@@ -429,7 +431,7 @@ function WeekView({ date, events, onEventClick, onDateClick }: WeekViewProps) {
429431
className="p-3 text-center border-r last:border-r-0"
430432
>
431433
<div className="text-sm font-medium text-muted-foreground">
432-
{day.toLocaleDateString("default", { weekday: "short" })}
434+
{day.toLocaleDateString(locale, { weekday: "short" })}
433435
</div>
434436
<div
435437
className={cn(

packages/plugin-form/src/ObjectForm.msw.test.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ const mockRecord = {
2828
// --- MSW Setup ---
2929

3030
const handlers = [
31+
// .well-known discovery endpoint (used by client.connect())
32+
http.get(`${BASE_URL}/.well-known/objectstack`, () => {
33+
return HttpResponse.json({
34+
name: 'ObjectStack API',
35+
version: '1.0',
36+
endpoints: {
37+
data: '/api/v1/data',
38+
metadata: '/api/v1/meta'
39+
},
40+
capabilities: {
41+
graphql: false,
42+
search: false,
43+
websockets: false,
44+
files: true,
45+
analytics: false,
46+
hub: false
47+
}
48+
});
49+
}),
50+
3151
// OPTIONS handler for CORS preflight
3252
http.options(`${BASE_URL}/*`, () => {
3353
return new HttpResponse(null, {
@@ -45,14 +65,21 @@ const handlers = [
4565
return HttpResponse.json({ status: 'ok', version: '1.0.0' });
4666
}),
4767

48-
// Mock Schema Fetch: GET /api/v1/metadata/object/:name
68+
// Mock Schema Fetch: GET /api/v1/metadata/object/:name and /api/v1/meta/object/:name (client uses /meta)
4969
http.get(`${BASE_URL}/api/v1/metadata/object/:name`, ({ params }) => {
5070
const { name } = params;
5171
if (name === 'contact') {
5272
return HttpResponse.json(mockSchema);
5373
}
5474
return new HttpResponse(null, { status: 404 });
5575
}),
76+
http.get(`${BASE_URL}/api/v1/meta/object/:name`, ({ params }) => {
77+
const { name } = params;
78+
if (name === 'contact') {
79+
return HttpResponse.json(mockSchema);
80+
}
81+
return new HttpResponse(null, { status: 404 });
82+
}),
5683

5784
// Mock Record Fetch: GET /api/v1/data/:object/:id
5885
http.get(`${BASE_URL}/api/v1/data/:object/:id`, ({ params }) => {

packages/plugin-form/src/index.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,5 @@ ComponentRegistry.register('object-form', ObjectFormRenderer, {
2222
namespace: 'plugin-form'
2323
});
2424

25-
// Alias for generic view
26-
ComponentRegistry.register('form', ObjectFormRenderer, {
27-
namespace: 'view',
28-
category: 'view',
29-
label: 'Form',
30-
inputs: [
31-
{ name: 'objectName', type: 'string', label: 'Object Name', required: true },
32-
{ name: 'recordId', type: 'string', label: 'Record ID' },
33-
{ name: 'layout', type: 'string', label: 'Layout' },
34-
]
35-
});
36-
3725
// Note: 'form' type is handled by @object-ui/components Form component
3826
// This plugin only handles 'object-form' which integrates with ObjectQL/ObjectStack

packages/plugin-grid/src/ObjectGrid.msw.test.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,26 @@ const mockData = {
3030
// --- MSW Setup ---
3131

3232
const handlers = [
33+
// .well-known discovery endpoint (used by client.connect())
34+
http.get(`${BASE_URL}/.well-known/objectstack`, () => {
35+
return HttpResponse.json({
36+
name: 'ObjectStack API',
37+
version: '1.0',
38+
endpoints: {
39+
data: '/api/v1/data',
40+
metadata: '/api/v1/meta'
41+
},
42+
capabilities: {
43+
graphql: false,
44+
search: false,
45+
websockets: false,
46+
files: true,
47+
analytics: false,
48+
hub: false
49+
}
50+
});
51+
}),
52+
3353
// OPTIONS handler for CORS preflight
3454
http.options(`${BASE_URL}/*`, () => {
3555
return new HttpResponse(null, {
@@ -47,10 +67,13 @@ const handlers = [
4767
return HttpResponse.json({ status: 'ok', version: '1.0.0' });
4868
}),
4969

50-
// Schema: /api/v1/metadata/object/:name
70+
// Schema: /api/v1/metadata/object/:name and /api/v1/meta/object/:name (client uses /meta)
5171
http.get(`${BASE_URL}/api/v1/metadata/object/contact`, () => {
5272
return HttpResponse.json(mockSchema);
5373
}),
74+
http.get(`${BASE_URL}/api/v1/meta/object/contact`, () => {
75+
return HttpResponse.json(mockSchema);
76+
}),
5477

5578
// Data Query: /api/v1/data/contact
5679
http.get(`${BASE_URL}/api/v1/data/contact`, () => {

packages/plugin-kanban/src/index.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ describe('Plugin Kanban', () => {
1717

1818
describe('kanban component', () => {
1919
it('should be registered in ComponentRegistry', () => {
20-
const kanbanRenderer = ComponentRegistry.get('kanban');
20+
const kanbanRenderer = ComponentRegistry.get('kanban-ui');
2121
expect(kanbanRenderer).toBeDefined();
2222
});
2323

2424
it('should have proper metadata', () => {
25-
const config = ComponentRegistry.getConfig('kanban');
25+
const config = ComponentRegistry.getConfig('kanban-ui');
2626
expect(config).toBeDefined();
2727
expect(config?.label).toBe('Kanban Board');
2828
expect(config?.icon).toBe('LayoutDashboard');
@@ -32,7 +32,7 @@ describe('Plugin Kanban', () => {
3232
});
3333

3434
it('should have expected inputs', () => {
35-
const config = ComponentRegistry.getConfig('kanban');
35+
const config = ComponentRegistry.getConfig('kanban-ui');
3636
const inputNames = config?.inputs?.map((input: any) => input.name) || [];
3737

3838
expect(inputNames).toContain('columns');
@@ -41,7 +41,7 @@ describe('Plugin Kanban', () => {
4141
});
4242

4343
it('should have columns as required input', () => {
44-
const config = ComponentRegistry.getConfig('kanban');
44+
const config = ComponentRegistry.getConfig('kanban-ui');
4545
const columnsInput = config?.inputs?.find((input: any) => input.name === 'columns');
4646

4747
expect(columnsInput).toBeDefined();
@@ -51,7 +51,7 @@ describe('Plugin Kanban', () => {
5151
});
5252

5353
it('should have onCardMove as code input', () => {
54-
const config = ComponentRegistry.getConfig('kanban');
54+
const config = ComponentRegistry.getConfig('kanban-ui');
5555
const onCardMoveInput = config?.inputs?.find((input: any) => input.name === 'onCardMove');
5656

5757
expect(onCardMoveInput).toBeDefined();
@@ -61,7 +61,7 @@ describe('Plugin Kanban', () => {
6161
});
6262

6363
it('should have sensible default props', () => {
64-
const config = ComponentRegistry.getConfig('kanban');
64+
const config = ComponentRegistry.getConfig('kanban-ui');
6565
const defaults = config?.defaultProps;
6666

6767
expect(defaults).toBeDefined();
@@ -72,7 +72,7 @@ describe('Plugin Kanban', () => {
7272
});
7373

7474
it('should have default columns with proper structure', () => {
75-
const config = ComponentRegistry.getConfig('kanban');
75+
const config = ComponentRegistry.getConfig('kanban-ui');
7676
const defaults = config?.defaultProps;
7777
const columns = defaults?.columns || [];
7878

@@ -93,7 +93,7 @@ describe('Plugin Kanban', () => {
9393
});
9494

9595
it('should have cards with proper structure', () => {
96-
const config = ComponentRegistry.getConfig('kanban');
96+
const config = ComponentRegistry.getConfig('kanban-ui');
9797
const defaults = config?.defaultProps;
9898
const columns = defaults?.columns || [];
9999

0 commit comments

Comments
 (0)