@objectql/platform-node 1.6.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.
@@ -0,0 +1,42 @@
1
+ # Test Dashboard Page
2
+ name: test_dashboard
3
+ label: Test Dashboard
4
+ description: Dashboard layout test
5
+ icon: dashboard
6
+ layout: dashboard
7
+
8
+ components:
9
+ # Metric with grid positioning
10
+ - id: metric_1
11
+ type: metric
12
+ label: Total Count
13
+ data_source:
14
+ object: projects
15
+ query:
16
+ op: count
17
+ config:
18
+ format: number
19
+ color: blue
20
+ grid:
21
+ x: 0
22
+ y: 0
23
+ w: 3
24
+ h: 2
25
+
26
+ # Chart with grid positioning
27
+ - id: chart_1
28
+ type: chart
29
+ label: Projects by Status
30
+ data_source:
31
+ object: projects
32
+ fields: ['status']
33
+ config:
34
+ chart_type: bar
35
+ grid:
36
+ x: 3
37
+ y: 0
38
+ w: 6
39
+ h: 4
40
+
41
+ permissions:
42
+ view: ['admin', 'manager']
@@ -0,0 +1,54 @@
1
+ # Test Page - Simple Single Column Layout
2
+ name: test_page
3
+ label: Test Page
4
+ description: A test page for unit tests
5
+ icon: test-tube
6
+ layout: single_column
7
+
8
+ # Permissions
9
+ permissions:
10
+ view: ['admin', 'user']
11
+ edit: ['admin']
12
+
13
+ # Simple components
14
+ components:
15
+ - id: header_text
16
+ type: text
17
+ label: Welcome
18
+ config:
19
+ content: Welcome to the test page
20
+ format: text
21
+
22
+ - id: test_grid
23
+ type: data_grid
24
+ label: Test Data
25
+ data_source:
26
+ object: projects
27
+ fields: ['name', 'status']
28
+ sort: [['created_at', 'desc']]
29
+ limit: 10
30
+ config:
31
+ columns:
32
+ - field: name
33
+ label: Project Name
34
+ - field: status
35
+ label: Status
36
+ actions:
37
+ on_click:
38
+ type: navigate
39
+ path: /projects/{{id}}
40
+
41
+ - id: action_button
42
+ type: button
43
+ label: Click Me
44
+ actions:
45
+ on_click:
46
+ type: run_action
47
+ object: projects
48
+ action: custom_action
49
+ success_message: Action completed
50
+
51
+ # AI context
52
+ ai_context:
53
+ intent: Test page for unit testing
54
+ persona: Test users
@@ -0,0 +1,39 @@
1
+ # Test Responsive Page
2
+ name: test_responsive
3
+ label: Test Responsive
4
+ description: Page with responsive configuration
5
+ icon: mobile
6
+ layout: single_column
7
+
8
+ # Responsive breakpoints
9
+ responsive:
10
+ mobile:
11
+ columns: 1
12
+ visible: true
13
+ tablet:
14
+ columns: 2
15
+ visible: true
16
+ desktop:
17
+ columns: 3
18
+ visible: true
19
+
20
+ components:
21
+ - id: responsive_grid
22
+ type: data_grid
23
+ label: Responsive Grid
24
+ data_source:
25
+ object: projects
26
+ fields: ['name']
27
+ responsive:
28
+ mobile:
29
+ visible: true
30
+ columns: 1
31
+ tablet:
32
+ visible: true
33
+ columns: 2
34
+ desktop:
35
+ visible: true
36
+ columns: 3
37
+
38
+ permissions:
39
+ view: ['*']
@@ -0,0 +1,45 @@
1
+ # Test Sections Page
2
+ name: test_sections
3
+ label: Test Sections
4
+ description: Two-column layout with sections
5
+ icon: layout
6
+ layout: two_column
7
+
8
+ sections:
9
+ # Main content section
10
+ - id: main_section
11
+ type: content
12
+ label: Main Content
13
+ style:
14
+ width: 70%
15
+ components:
16
+ - id: content_form
17
+ type: form
18
+ label: Edit Form
19
+ data_source:
20
+ object: projects
21
+ config:
22
+ mode: edit
23
+ fields:
24
+ - name: name
25
+ label: Name
26
+ type: text
27
+ - name: description
28
+ label: Description
29
+ type: textarea
30
+
31
+ # Sidebar section
32
+ - id: sidebar_section
33
+ type: sidebar
34
+ label: Sidebar
35
+ style:
36
+ width: 30%
37
+ components:
38
+ - id: stats
39
+ type: metric
40
+ label: Statistics
41
+ config:
42
+ format: number
43
+
44
+ permissions:
45
+ view: ['admin']
@@ -0,0 +1,15 @@
1
+ import { loadObjectConfigs } from '../src/loader';
2
+ import * as path from 'path';
3
+
4
+ describe('Loader', () => {
5
+ it('should load object configs from directory', () => {
6
+ const fixturesDir = path.join(__dirname, 'fixtures');
7
+ const configs = loadObjectConfigs(fixturesDir);
8
+ expect(configs).toBeDefined();
9
+ expect(configs['project']).toBeDefined();
10
+ expect(configs['project'].name).toBe('project');
11
+ expect(configs['project'].fields).toBeDefined();
12
+ expect(configs['project'].fields.name).toBeDefined();
13
+ });
14
+ });
15
+
@@ -0,0 +1,49 @@
1
+ import { ObjectQL } from '@objectql/core';
2
+ import { ObjectConfig } from '@objectql/types';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import * as yaml from 'js-yaml';
6
+
7
+ describe('Metadata Loading', () => {
8
+
9
+ it('should load definitions from .object.yml file', () => {
10
+ // 1. Read YAML file
11
+ const yamlPath = path.join(__dirname, 'fixtures', 'project.object.yml');
12
+ const fileContents = fs.readFileSync(yamlPath, 'utf8');
13
+
14
+ // 2. Parse YAML
15
+ const objectDef = yaml.load(fileContents) as ObjectConfig;
16
+
17
+ // 3. Verify Structure
18
+ expect(objectDef.name).toBe('project');
19
+ expect(objectDef.fields.name.type).toBe('text');
20
+ expect(objectDef.fields.status.options).toHaveLength(3);
21
+ expect(objectDef.fields.budget.type).toBe('currency');
22
+ expect(objectDef.fields.owner.reference_to).toBe('users');
23
+
24
+ // 4. Register with ObjectQL
25
+ const app = new ObjectQL({
26
+ datasources: {}
27
+ });
28
+
29
+ app.registerObject(objectDef);
30
+
31
+ // 5. Verify Registration
32
+ const retrieved = app.getObject('project');
33
+ expect(retrieved).toBeDefined();
34
+ expect(retrieved?.label).toBe('Project');
35
+ });
36
+
37
+ it('should validate required properties (manual validation simulation)', () => {
38
+ const yamlPath = path.join(__dirname, 'fixtures', 'project.object.yml');
39
+ const fileContents = fs.readFileSync(yamlPath, 'utf8');
40
+ const objectDef = yaml.load(fileContents) as ObjectConfig;
41
+
42
+ function validateObject(obj: ObjectConfig) {
43
+ if (!obj.name) throw new Error('Object name is required');
44
+ if (!obj.fields) throw new Error('Object fields are required');
45
+ }
46
+
47
+ expect(() => validateObject(objectDef)).not.toThrow();
48
+ });
49
+ });
@@ -0,0 +1,137 @@
1
+ import { ObjectLoader } from '../src/loader';
2
+ import { MetadataRegistry } from '@objectql/types';
3
+ import * as path from 'path';
4
+ import * as fs from 'fs';
5
+
6
+ describe('Page Metadata Loader', () => {
7
+ let registry: MetadataRegistry;
8
+ let loader: ObjectLoader;
9
+
10
+ beforeEach(() => {
11
+ registry = new MetadataRegistry();
12
+ loader = new ObjectLoader(registry);
13
+ });
14
+
15
+ it('should load page from .page.yml file', () => {
16
+ const fixturesDir = path.join(__dirname, 'fixtures');
17
+ loader.load(fixturesDir);
18
+
19
+ const pages = registry.list('page');
20
+ expect(pages.length).toBeGreaterThan(0);
21
+ });
22
+
23
+ it('should parse page metadata correctly', () => {
24
+ const fixturesDir = path.join(__dirname, 'fixtures');
25
+ loader.load(fixturesDir);
26
+
27
+ const page = registry.get('page', 'test_page');
28
+ expect(page).toBeDefined();
29
+ expect(page.label).toBe('Test Page');
30
+ expect(page.layout).toBe('single_column');
31
+ expect(page.components).toBeDefined();
32
+ expect(Array.isArray(page.components)).toBe(true);
33
+ });
34
+
35
+ it('should load page with dashboard layout', () => {
36
+ const fixturesDir = path.join(__dirname, 'fixtures');
37
+ loader.load(fixturesDir);
38
+
39
+ const page = registry.get('page', 'test_dashboard');
40
+ expect(page).toBeDefined();
41
+ expect(page.layout).toBe('dashboard');
42
+ expect(page.components).toBeDefined();
43
+
44
+ // Check if components have grid positions
45
+ const componentWithGrid = page.components?.find((c: any) => c.grid);
46
+ expect(componentWithGrid).toBeDefined();
47
+ if (componentWithGrid && componentWithGrid.grid) {
48
+ expect(componentWithGrid.grid.x).toBeDefined();
49
+ expect(componentWithGrid.grid.y).toBeDefined();
50
+ expect(componentWithGrid.grid.w).toBeDefined();
51
+ expect(componentWithGrid.grid.h).toBeDefined();
52
+ }
53
+ });
54
+
55
+ it('should load page with sections', () => {
56
+ const fixturesDir = path.join(__dirname, 'fixtures');
57
+ loader.load(fixturesDir);
58
+
59
+ const page = registry.get('page', 'test_sections');
60
+ expect(page).toBeDefined();
61
+ expect(page.sections).toBeDefined();
62
+ expect(Array.isArray(page.sections)).toBe(true);
63
+
64
+ if (page.sections && page.sections.length > 0) {
65
+ const section = page.sections[0];
66
+ expect(section.id).toBeDefined();
67
+ expect(section.components).toBeDefined();
68
+ }
69
+ });
70
+
71
+ it('should support page permissions', () => {
72
+ const fixturesDir = path.join(__dirname, 'fixtures');
73
+ loader.load(fixturesDir);
74
+
75
+ const page = registry.get('page', 'test_page');
76
+ expect(page).toBeDefined();
77
+ expect(page.permissions).toBeDefined();
78
+ expect(page.permissions.view).toBeDefined();
79
+ expect(Array.isArray(page.permissions.view)).toBe(true);
80
+ });
81
+
82
+ it('should support component actions', () => {
83
+ const fixturesDir = path.join(__dirname, 'fixtures');
84
+ loader.load(fixturesDir);
85
+
86
+ const page = registry.get('page', 'test_page');
87
+ expect(page).toBeDefined();
88
+
89
+ const componentWithAction = page.components?.find((c: any) => c.actions);
90
+ expect(componentWithAction).toBeDefined();
91
+ if (componentWithAction && componentWithAction.actions) {
92
+ expect(componentWithAction.actions.on_click).toBeDefined();
93
+ }
94
+ });
95
+
96
+ it('should support data source configuration', () => {
97
+ const fixturesDir = path.join(__dirname, 'fixtures');
98
+ loader.load(fixturesDir);
99
+
100
+ const page = registry.get('page', 'test_page');
101
+ expect(page).toBeDefined();
102
+
103
+ const componentWithDataSource = page.components?.find((c: any) => c.data_source);
104
+ expect(componentWithDataSource).toBeDefined();
105
+ if (componentWithDataSource && componentWithDataSource.data_source) {
106
+ expect(componentWithDataSource.data_source.object).toBeDefined();
107
+ }
108
+ });
109
+
110
+ it('should support responsive configuration', () => {
111
+ const fixturesDir = path.join(__dirname, 'fixtures');
112
+ loader.load(fixturesDir);
113
+
114
+ const page = registry.get('page', 'test_responsive');
115
+ expect(page).toBeDefined();
116
+ expect(page.responsive).toBeDefined();
117
+
118
+ if (page.responsive) {
119
+ expect(page.responsive.mobile).toBeDefined();
120
+ expect(page.responsive.tablet).toBeDefined();
121
+ expect(page.responsive.desktop).toBeDefined();
122
+ }
123
+ });
124
+
125
+ it('should support AI context', () => {
126
+ const fixturesDir = path.join(__dirname, 'fixtures');
127
+ loader.load(fixturesDir);
128
+
129
+ const page = registry.get('page', 'test_page');
130
+ expect(page).toBeDefined();
131
+ expect(page.ai_context).toBeDefined();
132
+
133
+ if (page.ai_context) {
134
+ expect(page.ai_context.intent).toBeDefined();
135
+ }
136
+ });
137
+ });