Skip to content

Commit d265b76

Browse files
authored
Merge pull request #57 from dont-code/fullprj
Supports for project definition as request param
2 parents 21f5d5d + eb0d874 commit d265b76

7 files changed

Lines changed: 211 additions & 42 deletions

File tree

apps/xt-host/projects/host/public/assets/projects/Simple.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,28 @@
66
"creation": {
77
"type": "Application",
88
"name": "Simple",
9-
"entities": {
10-
"a": {
9+
"entities": [
10+
{
1111
"from": "",
1212
"name": "SimpleNote",
13-
"fields": {
14-
"a": {
13+
"fields": [
14+
{
1515
"name": "Text",
1616
"type": "string"
1717
},
18-
"b": {
18+
{
1919
"name": "Amount",
2020
"type": "number"
2121
},
22-
"c": {
22+
{
2323
"name": "Check",
2424
"type": "boolean"
2525
}
26-
}
27-
},
28-
"sharing": {
29-
"with": "Dont-code users"
26+
]
3027
}
28+
],
29+
"sharing": {
30+
"with": "Dont-code users"
3131
}
3232
}
3333
}

apps/xt-host/projects/host/src/app/application-model-manager/application-model-manager.service.ts

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { inject, Injectable, signal } from '@angular/core';
2-
import { DcApplicationModel, DcFieldModel } from '../shared/models/dc-application-model';
2+
import {
3+
DcApplicationModel, DcEntityModel,
4+
DcFieldModel,
5+
isOldProjectModel,
6+
OldDcApplicationModel
7+
} from '../shared/models/dc-application-model';
38
import { XtTypeInfo } from 'xt-type';
49
import { Title } from '@angular/platform-browser';
510

@@ -23,17 +28,21 @@ export class ApplicationModelManagerService {
2328
return null;
2429
}
2530

26-
return Object.keys(entities).length>0?entities[Object.keys(entities)[0]].name:null;
31+
return entities.length>0?entities[0].name:null;
2732
}
2833

29-
setModel(value: DcApplicationModel) {
30-
this.model = value;
34+
setModel(value: DcApplicationModel|OldDcApplicationModel) {
35+
if (isOldProjectModel(value)) {
36+
this.model = this.toNewProjectModel (value);
37+
} else
38+
this.model = value;
39+
3140
if (this.model?.content?.creation?.entities!=null){
3241
this.entityNames.set (Object.values(this.model?.content?.creation?.entities).map((entity) => entity.name));
3342
}else {
3443
this.entityNames.set([]);
3544
}
36-
if (this.model.name!=null) {
45+
if (this.model?.name!=null) {
3746
this.projectTitle.set(this.model.name);
3847
this.titleMgr.setTitle(this.model.name);
3948
}
@@ -50,7 +59,7 @@ export class ApplicationModelManagerService {
5059
getApplicationTypes (): XtTypeInfo|null {
5160
if (this.model?.content.creation.entities!=null) {
5261
const ret={} as XtTypeInfo;
53-
for (const entity of Object.values(this.model!.content.creation.entities)) {
62+
for (const entity of this.model!.content.creation.entities) {
5463
if (entity.fields!=null) {
5564
ret[entity.name] = this.getEntityFields (entity.fields);
5665
}
@@ -61,9 +70,9 @@ export class ApplicationModelManagerService {
6170
}
6271
}
6372

64-
getEntityFields(fields: { [key:string]:DcFieldModel}): XtTypeInfo {
73+
getEntityFields(fields: Array<DcFieldModel>): XtTypeInfo {
6574
const ret = {} as XtTypeInfo;
66-
for (const field of Object.values(fields)) {
75+
for (const field of fields) {
6776
ret[field.name]= this.translate (field.type);
6877
}
6978
return ret;
@@ -85,4 +94,29 @@ export class ApplicationModelManagerService {
8594
return type.toLowerCase();
8695
}
8796
}
97+
98+
/**
99+
* Transform the old project model (that uses objects instead of arrays)
100+
* @param value
101+
* @protected
102+
*/
103+
protected toNewProjectModel(value: OldDcApplicationModel): DcApplicationModel {
104+
const ret ={ name:value.name,
105+
description: value.description,
106+
content: { creation: {
107+
type:value.content.creation.type,
108+
entities:new Array<DcEntityModel>(),
109+
sharing: value.content.creation.sharing
110+
}}
111+
} as DcApplicationModel;
112+
113+
for (const entity of Object.values(value.content.creation.entities??{})) {
114+
const newEntity = { name:entity.name, fields:new Array<DcFieldModel>} as DcEntityModel;
115+
for (const field of Object.values(entity.fields??{})) {
116+
newEntity.fields!.push(field);
117+
}
118+
ret.content!.creation!.entities!.push(newEntity);
119+
}
120+
return ret;
121+
}
88122
}

apps/xt-host/projects/host/src/app/project-load/project-load.component.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,40 @@ describe('ProjectLoadComponent', () => {
2828
it('should create', () => {
2929
expect(component).toBeTruthy();
3030
});
31+
3132
});
33+
34+
const PRJ_DEFINITION={
35+
"name": "Simple",
36+
"template": false,
37+
"description": "Simple project with no need for plugins",
38+
"content": {
39+
"creation": {
40+
"type": "Application",
41+
"name": "Simple",
42+
"entities": [
43+
{
44+
"from": "",
45+
"name": "SimpleNote",
46+
"fields": [
47+
{
48+
"name": "Text",
49+
"type": "string"
50+
},
51+
{
52+
"name": "Amount",
53+
"type": "number"
54+
},
55+
{
56+
"name": "Check",
57+
"type": "boolean"
58+
}
59+
]
60+
}
61+
],
62+
"sharing": {
63+
"with": "Dont-code users"
64+
}
65+
}
66+
}
67+
}

apps/xt-host/projects/host/src/app/project-load/project-load.component.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,23 @@ export class ProjectLoadComponent implements OnInit {
3737
private readonly injector = inject(Injector);
3838

3939
ngOnInit() {
40-
let projectName = this.route.snapshot.paramMap.get('projectName');
41-
if ((projectName==null) || (projectName.length==0)) {
42-
projectName = this.route.snapshot.queryParamMap.get('project')??'Coffee Beans Evaluation';
40+
// Either we get the complete project definition, or only the name to be read from project API
41+
let projectName:string = 'Coffee Beans Evaluation';
42+
let project = this.route.snapshot.queryParamMap.get('prjDef');
43+
if (project==null) {
44+
let givenPrjName = this.route.snapshot.paramMap.get('projectName');
45+
if ((givenPrjName==null) || (givenPrjName.length==0)) {
46+
projectName = this.route.snapshot.queryParamMap.get('project')??projectName;
47+
} else projectName=givenPrjName;
4348
}
49+
4450
const repoName = this.route.snapshot.paramMap.get('repoName') ?? this.route.snapshot.queryParamMap.get('repository')?? 'default';
4551
this.appConfig.updateConfigName(repoName); // Load the default config
46-
this.appConfig.updateProjectName(projectName);
52+
if (project!=null) {
53+
this.appConfig.updateProjectDefinition(project);
54+
}else {
55+
this.appConfig.updateProjectName(projectName);
56+
}
4757
}
4858

4959
combinedloadingStatus = linkedSignal( () => {
@@ -109,3 +119,17 @@ export class ProjectLoadComponent implements OnInit {
109119
}
110120

111121
}
122+
123+
function bufferToString(buffer: ArrayBuffer): string {
124+
return String.fromCharCode.apply(null, Array.from(new Uint16Array(buffer)));
125+
}
126+
127+
function stringToBuffer(value: string): ArrayBuffer {
128+
let buffer = new ArrayBuffer(value.length * 2); // 2 bytes per char
129+
let view = new Uint16Array(buffer);
130+
for (let i = 0, length = value.length; i < length; i++) {
131+
view[i] = value.charCodeAt(i);
132+
}
133+
return buffer;
134+
}
135+

apps/xt-host/projects/host/src/app/shared/app-config/app-config.service.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export class AppConfigService {
1111

1212
protected configResources = {
1313
configName: signal<string|undefined>(undefined),
14-
projectName: signal<string|undefined>(undefined)
14+
projectName: signal<string|undefined>(undefined),
15+
projectDefinition: signal<string|undefined>(undefined)
1516
}
1617

1718
protected resolverService = inject (XtResolverService);
@@ -96,25 +97,31 @@ export class AppConfigService {
9697
const ret= {
9798
pluginsLoaded: (this.plugins.status()=='resolved')||(this.plugins.status()=='local'),
9899
projectUrl:this.config.value()?.projectApiUrl,
99-
projectName: this.configResources.projectName()
100+
projectName: this.configResources.projectName(),
101+
projectDefinition: this.configResources.projectDefinition()
100102
}
101103
return ret;
102104
},
103105
loader: (options) => {
104-
if ((options.params.pluginsLoaded) && (options.params.projectName!=null)) {
105-
let projectUrl = options.params.projectUrl;
106-
if (projectUrl==null) {
107-
projectUrl='assets/projects/'+encodeURIComponent (options.params.projectName)+'.json';
108-
} else {
109-
projectUrl = new URL (options.params.projectName, projectUrl.endsWith('/')?projectUrl:projectUrl+'/').toString();
106+
if (options.params.pluginsLoaded) {
107+
if (options.params.projectDefinition!=null) {
108+
const jsonDef=JSON.parse(options.params.projectDefinition);
109+
return Promise.resolve(jsonDef);
110+
} else if (options.params.projectName!=null) {
111+
let projectUrl = options.params.projectUrl;
112+
if (projectUrl==null) {
113+
projectUrl='assets/projects/'+encodeURIComponent (options.params.projectName)+'.json';
114+
} else {
115+
projectUrl = new URL (options.params.projectName, projectUrl.endsWith('/')?projectUrl:projectUrl+'/').toString();
116+
}
117+
return fetch(projectUrl).then ((response) => {
118+
return response.json();
119+
});
120+
}else {
121+
return Promise.reject('No project name to load');
110122
}
111-
return fetch(projectUrl).then ((response) => {
112-
return response.json();
113-
});
114-
} else if (!options.params.pluginsLoaded) {
115-
return Promise.resolve();
116123
} else {
117-
return Promise.reject('No project name to load');
124+
return Promise.resolve();
118125
}
119126
}
120127
});
@@ -154,4 +161,9 @@ export class AppConfigService {
154161
this.configResources.projectName.set(newName);
155162
}
156163

164+
updateProjectDefinition (prjDef:string) {
165+
this.configResources.projectDefinition.set(prjDef);
166+
}
167+
168+
157169
}

apps/xt-host/projects/host/src/app/shared/models/dc-application-model.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ export type DcApplicationModel = {
66
content: {
77
creation: {
88
type?: string,
9-
entities?: {
10-
[key:string]:DcEntityModel
11-
},
9+
entities?: Array<DcEntityModel>,
1210
sharing?: {
1311
with: 'Dont-code users'|'No-one'|'Volatile'
1412
}
@@ -18,9 +16,7 @@ export type DcApplicationModel = {
1816

1917
export type DcEntityModel = {
2018
name: string,
21-
fields?: {
22-
[key:string]:DcFieldModel
23-
},
19+
fields?: Array<DcFieldModel>,
2420
compatibleWith?: string[]
2521
}
2622

@@ -29,3 +25,33 @@ export type DcFieldModel = {
2925
type: string,
3026
reference?: XtTypeReference
3127
}
28+
29+
export type OldDcApplicationModel = {
30+
name:string,
31+
description?: string,
32+
content: {
33+
creation: {
34+
type?: string,
35+
entities?: {
36+
[key:string]:OldDcEntityModel
37+
},
38+
sharing?: {
39+
with: 'Dont-code users'|'No-one'|'Volatile'
40+
}
41+
}
42+
}
43+
}
44+
45+
export type OldDcEntityModel = {
46+
name: string,
47+
fields?: {
48+
[key:string]:DcFieldModel
49+
},
50+
compatibleWith?: string[]
51+
}
52+
53+
export function isOldProjectModel(prj:DcApplicationModel|OldDcApplicationModel):prj is OldDcApplicationModel {
54+
if (prj.content.creation.entities != null) {
55+
return !Array.isArray(prj.content.creation.entities);
56+
} else return false;
57+
}

docs/test-project-definition.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Base 64:
2+
ewogICJuYW1lIjogIlNpbXBsZSIsCiAgInRlbXBsYXRlIjogZmFsc2UsCiAgImRlc2NyaXB0aW9uIjogIlNpbXBsZSBwcm9qZWN0IHdpdGggbm8gbmVlZCBmb3IgcGx1Z2lucyIsCiAgImNvbnRlbnQiOiB7CiAgICAiY3JlYXRpb24iOiB7CiAgICAgICJ0eXBlIjogIkFwcGxpY2F0aW9uIiwKICAgICAgIm5hbWUiOiAiU2ltcGxlIiwKICAgICAgImVudGl0aWVzIjogWwogICAgICAgIHsKICAgICAgICAgICJmcm9tIjogIiIsCiAgICAgICAgICAibmFtZSI6ICJTaW1wbGVOb3RlIiwKICAgICAgICAgICJmaWVsZHMiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAibmFtZSI6ICJUZXh0IiwKICAgICAgICAgICAgICAidHlwZSI6ICJzdHJpbmciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAibmFtZSI6ICJBbW91bnQiLAogICAgICAgICAgICAgICJ0eXBlIjogIm51bWJlciIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICJuYW1lIjogIkNoZWNrIiwKICAgICAgICAgICAgICAidHlwZSI6ICJib29sZWFuIgogICAgICAgICAgICB9CiAgICAgICAgICBdCiAgICAgICAgfQogICAgICBdLAogICAgICAic2hhcmluZyI6IHsKICAgICAgICAid2l0aCI6ICJEb250LWNvZGUgdXNlcnMiCiAgICAgIH0KICAgIH0KICB9Cn0K
3+
4+
{
5+
"name": "Simple",
6+
"template": false,
7+
"description": "Simple project with no need for plugins",
8+
"content": {
9+
"creation": {
10+
"type": "Application",
11+
"name": "Simple",
12+
"entities": [
13+
{
14+
"from": "",
15+
"name": "SimpleNote",
16+
"fields": [
17+
{
18+
"name": "Text",
19+
"type": "string"
20+
},
21+
{
22+
"name": "Amount",
23+
"type": "number"
24+
},
25+
{
26+
"name": "Check",
27+
"type": "boolean"
28+
}
29+
]
30+
}
31+
],
32+
"sharing": {
33+
"with": "Dont-code users"
34+
}
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)