Skip to content

Commit a8c201b

Browse files
committed
refactor: remove legacy view storage routes and implement new UI view endpoint
1 parent cb15428 commit a8c201b

File tree

2 files changed

+10
-197
lines changed

2 files changed

+10
-197
lines changed

packages/client/src/index.ts

Lines changed: 2 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,7 @@ import {
88
MetadataCacheRequest,
99
MetadataCacheResponse,
1010
StandardErrorCode,
11-
ErrorCategory,
12-
CreateViewRequest,
13-
UpdateViewRequest,
14-
ListViewsRequest,
15-
SavedView,
16-
ListViewsResponse,
17-
ViewResponse
11+
ErrorCategory
1812
} from '@objectstack/spec/api';
1913
import { Logger, createLogger } from '@objectstack/core';
2014

@@ -342,103 +336,7 @@ export class ObjectStackClient {
342336
}
343337
};
344338

345-
/**
346-
* View Storage Operations
347-
* Save, load, and manage UI view configurations
348-
*/
349-
views = {
350-
/**
351-
* Create a new saved view
352-
*/
353-
create: async (request: CreateViewRequest): Promise<ViewResponse> => {
354-
const route = this.getRoute('ui');
355-
const res = await this.fetch(`${this.baseUrl}${route}/views`, {
356-
method: 'POST',
357-
body: JSON.stringify(request)
358-
});
359-
return res.json();
360-
},
361-
362-
/**
363-
* Get a saved view by ID
364-
*/
365-
get: async (id: string): Promise<ViewResponse> => {
366-
const route = this.getRoute('ui');
367-
const res = await this.fetch(`${this.baseUrl}${route}/views/${id}`);
368-
return res.json();
369-
},
370-
371-
/**
372-
* List saved views with optional filters
373-
*/
374-
list: async (request?: ListViewsRequest): Promise<ListViewsResponse> => {
375-
const route = this.getRoute('ui');
376-
const queryParams = new URLSearchParams();
377-
378-
if (request?.object) queryParams.set('object', request.object);
379-
if (request?.type) queryParams.set('type', request.type);
380-
if (request?.visibility) queryParams.set('visibility', request.visibility);
381-
if (request?.createdBy) queryParams.set('createdBy', request.createdBy);
382-
if (request?.isDefault !== undefined) queryParams.set('isDefault', String(request.isDefault));
383-
if (request?.limit) queryParams.set('limit', String(request.limit));
384-
if (request?.offset) queryParams.set('offset', String(request.offset));
385-
386-
const url = queryParams.toString()
387-
? `${this.baseUrl}${route}/views?${queryParams.toString()}`
388-
: `${this.baseUrl}${route}/views`;
389-
390-
const res = await this.fetch(url);
391-
return res.json();
392-
},
393339

394-
/**
395-
* Update an existing view
396-
*/
397-
update: async (request: UpdateViewRequest): Promise<ViewResponse> => {
398-
const route = this.getRoute('ui');
399-
const { id, ...updateData } = request;
400-
const res = await this.fetch(`${this.baseUrl}${route}/views/${id}`, {
401-
method: 'PATCH',
402-
body: JSON.stringify(updateData)
403-
});
404-
return res.json();
405-
},
406-
407-
/**
408-
* Delete a saved view
409-
*/
410-
delete: async (id: string): Promise<{ success: boolean }> => {
411-
const route = this.getRoute('ui');
412-
const res = await this.fetch(`${this.baseUrl}${route}/views/${id}`, {
413-
method: 'DELETE'
414-
});
415-
return res.json();
416-
},
417-
418-
/**
419-
* Share a view with users/teams
420-
*/
421-
share: async (id: string, userIds: string[]): Promise<ViewResponse> => {
422-
const route = this.getRoute('ui');
423-
const res = await this.fetch(`${this.baseUrl}${route}/views/${id}/share`, {
424-
method: 'POST',
425-
body: JSON.stringify({ sharedWith: userIds })
426-
});
427-
return res.json();
428-
},
429-
430-
/**
431-
* Set a view as default for an object
432-
*/
433-
setDefault: async (id: string, object: string): Promise<ViewResponse> => {
434-
const route = this.getRoute('ui');
435-
const res = await this.fetch(`${this.baseUrl}${route}/views/${id}/set-default`, {
436-
method: 'POST',
437-
body: JSON.stringify({ object })
438-
});
439-
return res.json();
440-
}
441-
};
442340

443341
/**
444342
* Private Helpers
@@ -537,15 +435,5 @@ export type {
537435
MetadataCacheRequest,
538436
MetadataCacheResponse,
539437
StandardErrorCode,
540-
ErrorCategory,
541-
CreateViewRequest,
542-
UpdateViewRequest,
543-
ListViewsRequest,
544-
SavedView,
545-
ViewResponse,
546-
ListViewsResponse,
547-
ViewType,
548-
ViewVisibility,
549-
ViewColumn,
550-
ViewLayout
438+
ErrorCategory
551439
} from '@objectstack/spec/api';

packages/plugins/plugin-hono-server/src/hono-plugin.ts

Lines changed: 8 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -276,95 +276,20 @@ export class HonoServerPlugin implements Plugin {
276276
}
277277
});
278278

279-
// View Storage Routes
280-
this.server.post('/api/v1/ui/views', async (req, res) => {
281-
ctx.logger.debug('Create view request', { name: req.body?.name, object: req.body?.object });
282-
try {
283-
const result = await p.createView(req.body);
284-
if (result.success) {
285-
ctx.logger.info('View created', { id: result.data?.id, name: result.data?.name });
286-
res.status(201).json(result);
287-
} else {
288-
ctx.logger.warn('View creation failed', { error: result.error });
289-
res.status(400).json(result);
290-
}
291-
} catch (e: any) {
292-
ctx.logger.error('View creation error', e);
293-
res.status(500).json({ success: false, error: { code: 'internal_error', message: e.message } });
294-
}
295-
});
296-
297-
this.server.get('/api/v1/ui/views/:id', async (req, res) => {
298-
ctx.logger.debug('Get view request', { id: req.params.id });
299-
try {
300-
const result = await p.getView({ id: req.params.id });
301-
if (result.success) {
302-
ctx.logger.debug('View retrieved', { id: req.params.id });
303-
res.json(result);
304-
} else {
305-
ctx.logger.warn('View not found', { id: req.params.id });
306-
res.status(404).json(result);
307-
}
308-
} catch (e: any) {
309-
ctx.logger.error('Get view error', e, { id: req.params.id });
310-
res.status(500).json({ success: false, error: { code: 'internal_error', message: e.message } });
311-
}
312-
});
313-
314-
this.server.get('/api/v1/ui/views', async (req, res) => {
315-
ctx.logger.debug('List views request', { query: req.query });
279+
// UI Protocol endpoint
280+
this.server.get('/api/v1/ui/view/:object', async (req, res) => {
281+
ctx.logger.debug('Get UI view request', { object: req.params.object, type: req.query.type });
316282
try {
317-
const request: any = {};
318-
if (req.query.object) request.object = req.query.object as string;
319-
if (req.query.type) request.type = req.query.type;
320-
if (req.query.visibility) request.visibility = req.query.visibility;
321-
if (req.query.createdBy) request.createdBy = req.query.createdBy as string;
322-
if (req.query.isDefault !== undefined) request.isDefault = req.query.isDefault === 'true';
323-
if (req.query.limit) request.limit = parseInt(req.query.limit as string);
324-
if (req.query.offset) request.offset = parseInt(req.query.offset as string);
325-
326-
const result = await p.listViews(request);
327-
ctx.logger.debug('Views listed', { count: result.data?.length, total: result.pagination?.total });
328-
res.json(result);
283+
const viewType = (req.query.type as 'list' | 'form') || 'list';
284+
const view = await p.getUiView({ object: req.params.object, type: viewType });
285+
res.json(view);
329286
} catch (e: any) {
330-
ctx.logger.error('List views error', e);
331-
res.status(500).json({ success: false, error: { code: 'internal_error', message: e.message } });
287+
ctx.logger.warn('UI view not found', { object: req.params.object, error: e.message });
288+
res.status(404).json({ error: e.message });
332289
}
333290
});
334291

335-
this.server.patch('/api/v1/ui/views/:id', async (req, res) => {
336-
ctx.logger.debug('Update view request', { id: req.params.id });
337-
try {
338-
const result = await p.updateView({ ...req.body, id: req.params.id });
339-
if (result.success) {
340-
ctx.logger.info('View updated', { id: req.params.id });
341-
res.json(result);
342-
} else {
343-
ctx.logger.warn('View update failed', { id: req.params.id, error: result.error });
344-
res.status(result.error?.code === 'resource_not_found' ? 404 : 400).json(result);
345-
}
346-
} catch (e: any) {
347-
ctx.logger.error('Update view error', e, { id: req.params.id });
348-
res.status(500).json({ success: false, error: { code: 'internal_error', message: e.message } });
349-
}
350-
});
351292

352-
this.server.delete('/api/v1/ui/views/:id', async (req, res) => {
353-
ctx.logger.debug('Delete view request', { id: req.params.id });
354-
try {
355-
const result = await p.deleteView({ id: req.params.id });
356-
if (result.success) {
357-
ctx.logger.info('View deleted', { id: req.params.id });
358-
res.json(result);
359-
} else {
360-
ctx.logger.warn('View deletion failed', { id: req.params.id });
361-
res.status(404).json(result);
362-
}
363-
} catch (e: any) {
364-
ctx.logger.error('Delete view error', e, { id: req.params.id });
365-
res.status(500).json({ success: false, error: { code: 'internal_error', message: e.message } });
366-
}
367-
});
368293

369294
ctx.logger.info('All API routes registered');
370295
}

0 commit comments

Comments
 (0)