diff --git a/storefront/package-lock.json b/storefront/package-lock.json
index 993c52f..4db1971 100644
--- a/storefront/package-lock.json
+++ b/storefront/package-lock.json
@@ -5063,6 +5063,11 @@
"schema-utils": "^2.6.5"
}
},
+ "file-saver": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz",
+ "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw=="
+ },
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -6788,6 +6793,11 @@
"verror": "1.10.0"
}
},
+ "jstoxml": {
+ "version": "1.6.10",
+ "resolved": "https://registry.npmjs.org/jstoxml/-/jstoxml-1.6.10.tgz",
+ "integrity": "sha512-Y610p1VGKBGpPGF8QB67JMnEK66J4maFDovguPyJIw7e3Aj3jsmvC1lCl3YckIkgUjFOg4J3q4j+aRaevG0J4g=="
+ },
"jszip": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz",
diff --git a/storefront/package.json b/storefront/package.json
index ba4fc76..43cafd8 100644
--- a/storefront/package.json
+++ b/storefront/package.json
@@ -23,7 +23,9 @@
"@angular/platform-browser-dynamic": "~10.0.5",
"@angular/router": "~10.0.5",
"ang-jsoneditor": "^1.9.4",
+ "file-saver": "^2.0.2",
"jsoneditor": "^9.0.3",
+ "jstoxml": "^1.6.10",
"rxjs": "~6.5.5",
"tslib": "^2.0.0",
"zone.js": "~0.10.3"
diff --git a/storefront/src/app/app.module.ts b/storefront/src/app/app.module.ts
index 31f375c..bdb9482 100644
--- a/storefront/src/app/app.module.ts
+++ b/storefront/src/app/app.module.ts
@@ -1,6 +1,6 @@
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
-import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';
+import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {FlexLayoutModule} from '@angular/flex-layout';
import {AppRoutingModule} from './app-routing.module';
@@ -12,6 +12,7 @@ import {AppComponent} from './app.component';
import {StoreRoomService} from './service/storeroom/store-room.service';
import {DefaultModule} from './layout/default/default.module';
import {HttpErrorInterceptor} from './interceptors/http-error.interceptor';
+import {JsonConverterService} from './service/json-converter/json-converter.service';
@NgModule({
declarations: [
@@ -33,7 +34,8 @@ import {HttpErrorInterceptor} from './interceptors/http-error.interceptor';
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true
- }
+ },
+ JsonConverterService
],
bootstrap: [AppComponent]
})
diff --git a/storefront/src/app/modules/editor/editor.component.html b/storefront/src/app/modules/editor/editor.component.html
index 3f8a463..8383010 100644
--- a/storefront/src/app/modules/editor/editor.component.html
+++ b/storefront/src/app/modules/editor/editor.component.html
@@ -3,9 +3,9 @@
-
-
-
+
+
+
diff --git a/storefront/src/app/modules/editor/editor.component.ts b/storefront/src/app/modules/editor/editor.component.ts
index 563c418..21b7da7 100644
--- a/storefront/src/app/modules/editor/editor.component.ts
+++ b/storefront/src/app/modules/editor/editor.component.ts
@@ -4,6 +4,7 @@ import {StoreRoomService} from '../../service/storeroom/store-room.service';
import {ActivatedRoute, Router} from '@angular/router';
import {IError} from 'ang-jsoneditor/jsoneditor/jsoneditoroptions';
import {MatSnackBar} from '@angular/material/snack-bar';
+import {JsonConverterService} from '../../service/json-converter/json-converter.service';
@Component({
selector: 'app-editor',
@@ -22,7 +23,7 @@ export class EditorComponent implements OnInit, OnDestroy {
private metaSchema: any;
constructor(private storeroomClient: StoreRoomService, private route: ActivatedRoute, private snackBar: MatSnackBar,
- private router: Router) {
+ private router: Router, private jsonConverterService: JsonConverterService) {
this.editorOptions = new JsonEditorOptions();
this.editorOptions2 = new JsonEditorOptions();
this.editorOptions.modes = ['code', 'text', 'tree', 'view'];
@@ -31,7 +32,7 @@ export class EditorComponent implements OnInit, OnDestroy {
// this.editorOptions.onValidate = () => this.validateSchema();
this.editorOptions.navigationBar = true;
// tslint:disable-next-line:max-line-length
- this.editorOptions.schema = { $schema: 'http://json-schema.org/draft-07/schema#', $ref: '#/definitions/Welcome', definitions: { Welcome: { type: 'object', additionalProperties: false, properties: { $schema: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'http' ] }, $id: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.0' ] }, title: { type: 'string' }, description: { type: 'string' }, type: { type: 'string' }, meta: { $ref: '#/definitions/Meta' }, properties: { $ref: '#/definitions/Properties' }, required: { type: 'array', items: { type: 'string' } }, oneof: { type: 'array', items: { $ref: '#/definitions/Oneof' } }, additionalProperties: { type: 'boolean' }, examples: { type: 'array', items: { $ref: '#/definitions/WelcomeExample' } } }, required: [ '$id', '$schema', 'additionalProperties', 'description', 'examples', 'meta', 'oneof', 'properties', 'required', 'title', 'type' ], title: 'Welcome' }, WelcomeExample: { type: 'object', additionalProperties: false, properties: { term: { $ref: '#/definitions/ClassOfOnset' }, classOfOnset: { $ref: '#/definitions/ClassOfOnset' } }, required: [ 'classOfOnset', 'term' ], title: 'WelcomeExample' }, Meta: { type: 'object', additionalProperties: false, properties: { contributors: { type: 'array', items: { $ref: '#/definitions/Contributor' } }, provenance: { type: 'array', items: { $ref: '#/definitions/Contributor' } }, used_by: { type: 'array', items: { $ref: '#/definitions/Contributor' } }, sb_status: { type: 'string' } }, required: [ 'contributors', 'provenance', 'sb_status', 'used_by' ], title: 'Meta' }, Contributor: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, id: { type: 'string', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.rst' ] } }, required: [ 'description' ], title: 'Contributor' }, Oneof: { type: 'object', additionalProperties: false, properties: { properties: { type: 'array', items: { type: 'string' } } }, required: [ 'properties' ], title: 'Oneof' }, Properties: { type: 'object', additionalProperties: false, properties: { term: { $ref: '#/definitions/Term' }, ageOfOnset: { $ref: '#/definitions/AgeOfOnset' }, ageRangeOfOnset: { $ref: '#/definitions/AgeRangeOfOnset' }, classOfOnset: { $ref: '#/definitions/PropertiesClassOfOnset' }, diseaseStage: { $ref: '#/definitions/DiseaseStage' }, tnmFinding: { $ref: '#/definitions/DiseaseStage' } }, required: [ 'ageOfOnset', 'ageRangeOfOnset', 'classOfOnset', 'diseaseStage', 'term', 'tnmFinding' ], title: 'Properties' }, AgeOfOnset: { type: 'object', additionalProperties: false, properties: { allof: { type: 'array', items: { $ref: '#/definitions/AgeOfOnsetAllof' } } }, required: [ 'allof' ], title: 'AgeOfOnset' }, AgeOfOnsetAllof: { type: 'object', additionalProperties: false, properties: { $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, description: { type: 'string' }, examples: { type: 'array', items: { $ref: '#/definitions/Start' } } }, required: [], title: 'AgeOfOnsetAllof' }, Start: { type: 'object', additionalProperties: false, properties: { age: { type: 'string' } }, required: [ 'age' ], title: 'Start' }, AgeRangeOfOnset: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, examples: { type: 'array', items: { $ref: '#/definitions/AgeRangeOfOnsetExample' } } }, required: [ '$ref', 'description', 'examples' ], title: 'AgeRangeOfOnset' }, AgeRangeOfOnsetExample: { type: 'object', additionalProperties: false, properties: { start: { $ref: '#/definitions/Start' } }, required: [ 'start' ], title: 'AgeRangeOfOnsetExample' }, PropertiesClassOfOnset: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, examples: { type: 'array', items: { $ref: '#/definitions/ClassOfOnset' } } }, required: [ '$ref', 'description', 'examples' ], title: 'PropertiesClassOfOnset' }, DiseaseStage: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, type: { type: 'string' }, items: { $ref: '#/definitions/Items' }, examples: { type: 'array', items: { type: 'array', items: { $ref: '#/definitions/ClassOfOnset' } } } }, required: [ 'description', 'examples', 'items', 'type' ], title: 'DiseaseStage' }, ClassOfOnset: { type: 'object', additionalProperties: false, properties: { id: { type: 'string' }, label: { type: 'string' } }, required: [ 'id', 'label' ], title: 'ClassOfOnset' }, Items: { type: 'object', additionalProperties: false, properties: { $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] } }, required: [ '$ref' ], title: 'Items' }, Term: { type: 'object', additionalProperties: false, properties: { allof: { type: 'array', items: { $ref: '#/definitions/TermAllof' } } }, required: [ 'allof' ], title: 'Term' }, TermAllof: { type: 'object', additionalProperties: false, properties: { $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, description: { type: 'string' }, examples: { type: 'array', items: { $ref: '#/definitions/AllofExample' } } }, required: [], title: 'TermAllof' }, AllofExample: { type: 'object', additionalProperties: false, properties: { id: { type: 'string' } }, required: [ 'id' ], title: 'AllofExample' } } };
+ this.editorOptions.schema = { $schema: 'http://json-schema.org/draft-07/schema#', $ref: '#/definitions/MetaSchema', definitions: { MetaSchema: { type: 'object', additionalProperties: false, properties: { $schema: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'http' ] }, $id: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https', 'http' ], 'qt-uri-extensions': [ '.0' ] }, title: { type: 'string' }, description: { type: 'string' }, type: { type: 'string' }, meta: { $ref: '#/definitions/Meta' }, properties: { $ref: '#/definitions/Properties' }, required: { type: 'array', items: { type: 'string' } }, oneof: { type: 'array', items: { $ref: '#/definitions/Oneof' } }, additionalProperties: { type: 'boolean' }, examples: { type: 'array', items: { $ref: '#/definitions/SchemaExample' } } }, required: [ '$id', '$schema', 'additionalProperties', 'description', 'examples', 'meta', 'oneof', 'properties', 'required', 'title', 'type' ], title: 'MetaSchema' }, SchemaExample: { type: 'object', additionalProperties: false, properties: { term: { $ref: '#/definitions/ClassOfOnset' }, classOfOnset: { $ref: '#/definitions/ClassOfOnset' } }, required: [ 'classOfOnset', 'term' ], title: 'SchemaExample' }, Meta: { type: 'object', additionalProperties: false, properties: { contributors: { type: 'array', items: { $ref: '#/definitions/Contributor' } }, provenance: { type: 'array', items: { $ref: '#/definitions/Contributor' } }, used_by: { type: 'array', items: { $ref: '#/definitions/Contributor' } }, sb_status: { type: 'string' } }, required: [ 'contributors', 'provenance', 'sb_status', 'used_by' ], title: 'Meta' }, Contributor: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, id: { type: 'string', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.rst' ] } }, required: [ 'description' ], title: 'Contributor' }, Oneof: { type: 'object', additionalProperties: false, properties: { properties: { type: 'array', items: { type: 'string' } } }, required: [ 'properties' ], title: 'Oneof' }, Properties: { type: 'object', additionalProperties: false, properties: { term: { $ref: '#/definitions/Term' }, ageOfOnset: { $ref: '#/definitions/AgeOfOnset' }, ageRangeOfOnset: { $ref: '#/definitions/AgeRangeOfOnset' }, classOfOnset: { $ref: '#/definitions/PropertiesClassOfOnset' }, diseaseStage: { $ref: '#/definitions/DiseaseStage' }, tnmFinding: { $ref: '#/definitions/DiseaseStage' } }, required: [ 'ageOfOnset', 'ageRangeOfOnset', 'classOfOnset', 'diseaseStage', 'term', 'tnmFinding' ], title: 'Properties' }, AgeOfOnset: { type: 'object', additionalProperties: false, properties: { allof: { type: 'array', items: { $ref: '#/definitions/AgeOfOnsetAllof' } } }, required: [ 'allof' ], title: 'AgeOfOnset' }, AgeOfOnsetAllof: { type: 'object', additionalProperties: false, properties: { $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, description: { type: 'string' }, examples: { type: 'array', items: { $ref: '#/definitions/Start' } } }, required: [], title: 'AgeOfOnsetAllof' }, Start: { type: 'object', additionalProperties: false, properties: { age: { type: 'string' } }, required: [ 'age' ], title: 'Start' }, AgeRangeOfOnset: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, examples: { type: 'array', items: { $ref: '#/definitions/AgeRangeOfOnsetExample' } } }, required: [ '$ref', 'description', 'examples' ], title: 'AgeRangeOfOnset' }, AgeRangeOfOnsetExample: { type: 'object', additionalProperties: false, properties: { start: { $ref: '#/definitions/Start' } }, required: [ 'start' ], title: 'AgeRangeOfOnsetExample' }, PropertiesClassOfOnset: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, examples: { type: 'array', items: { $ref: '#/definitions/ClassOfOnset' } } }, required: [ '$ref', 'description', 'examples' ], title: 'PropertiesClassOfOnset' }, DiseaseStage: { type: 'object', additionalProperties: false, properties: { description: { type: 'string' }, type: { type: 'string' }, items: { $ref: '#/definitions/Items' }, examples: { type: 'array', items: { type: 'array', items: { $ref: '#/definitions/ClassOfOnset' } } } }, required: [ 'description', 'examples', 'items', 'type' ], title: 'DiseaseStage' }, ClassOfOnset: { type: 'object', additionalProperties: false, properties: { id: { type: 'string' }, label: { type: 'string' } }, required: [ 'id', 'label' ], title: 'ClassOfOnset' }, Items: { type: 'object', additionalProperties: false, properties: { $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] } }, required: [ '$ref' ], title: 'Items' }, Term: { type: 'object', additionalProperties: false, properties: { allof: { type: 'array', items: { $ref: '#/definitions/TermAllof' } } }, required: [ 'allof' ], title: 'Term' }, TermAllof: { type: 'object', additionalProperties: false, properties: { $ref: { type: 'string', format: 'uri', 'qt-uri-protocols': [ 'https' ], 'qt-uri-extensions': [ '.json' ] }, description: { type: 'string' }, examples: { type: 'array', items: { $ref: '#/definitions/AllofExample' } } }, required: [], title: 'TermAllof' }, AllofExample: { type: 'object', additionalProperties: false, properties: { id: { type: 'string' } }, required: [ 'id' ], title: 'AllofExample' } } };
// tslint:disable-next-line:max-line-length
this.data = { $schema: 'http://json-schema.org/draft-07/schema#', $id: 'https://schemablocks.org/schemas/xxxxx', title: 'title', description: 'description', type: 'object', meta: { contributors: [ { description: 'GA4GH Data Working Group' }, { description: 'Jules Jacobsen', id: 'orcid:0000-0002-3265-15918' } ], provenance: [ { description: 'description', id: 'https://github.com/phenopackets/phenopacket-schema/xxxxxx' } ], used_by: [ { description: 'Phenopackets', id: 'https://github.com/phenopackets/phenopacket-schema/xxxx' } ], sb_status: 'implemented' }, properties: { term: { allof: [ { $ref: 'https://schemablocks.org/schemas/sb-phenopackets/v1.0.0/OntologyClass.json' }, { description: 'The identifier of this disease\ne.g. MONDO:0007043, OMIM:101600, Orphanet:710, DOID:14705 (note these are all equivalent)\n', examples: [ { id: 'MONDO:0007043' } ] } ] } }, required: [ 'term' ], additionalProperties: false, examples: [ { term: { id: 'MONDO:0007043', label: 'Pfeiffer syndrome' } } ] };
}
@@ -102,6 +103,14 @@ export class EditorComponent implements OnInit, OnDestroy {
this.isMetaSchemaViewerDisable = !this.isMetaSchemaViewerDisable;
}
+ public downloadAs(format: string): void {
+ if (format === 'JSON') {
+ this.jsonConverterService.jsonToJSONAndDownload(this.editor.get());
+ } else if (format === 'XML') {
+ this.jsonConverterService.jsonToXMLAndDownload(this.editor.get());
+ }
+ }
+
private validateSchema(): IError[] {
console.log('start validating scehma!');
console.log(this.jsonSchema);
diff --git a/storefront/src/app/service/json-converter/json-converter.service.spec.ts b/storefront/src/app/service/json-converter/json-converter.service.spec.ts
new file mode 100644
index 0000000..0f9c295
--- /dev/null
+++ b/storefront/src/app/service/json-converter/json-converter.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { JsonConverterService } from './json-converter.service';
+
+describe('JsonConverterService', () => {
+ let service: JsonConverterService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(JsonConverterService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/storefront/src/app/service/json-converter/json-converter.service.ts b/storefront/src/app/service/json-converter/json-converter.service.ts
new file mode 100644
index 0000000..3e0de01
--- /dev/null
+++ b/storefront/src/app/service/json-converter/json-converter.service.ts
@@ -0,0 +1,33 @@
+import {Injectable} from '@angular/core';
+import * as fileSaver from 'file-saver';
+import {toXML} from 'jstoxml';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class JsonConverterService {
+
+ constructor() {
+ }
+
+ public jsonToJSONAndDownload(jsonObject: any, fileName?: string): void {
+ if (!fileName) {
+ fileName = jsonObject.title + '-' + jsonObject.$id.substring(jsonObject.$id.lastIndexOf('/')) + '.json';
+ }
+ JSON.stringify(jsonObject);
+ const file = new Blob([JSON.stringify(jsonObject, null, 2)], {type: 'text/javascript'});
+ fileSaver.saveAs(file, fileName);
+ }
+
+ public jsonToXMLAndDownload(jsonObject: any, fileName?: string): void {
+ if (!fileName) {
+ fileName = jsonObject.title + '-' + jsonObject.$id.substring(jsonObject.$id.lastIndexOf('/')) + '.xml';
+ }
+ const xmlOptions = {
+ header: false,
+ indent: ' '
+ };
+ const file = new Blob([toXML(jsonObject, xmlOptions)], {type: 'text/xml'});
+ fileSaver.saveAs(file, fileName);
+ }
+}
diff --git a/storeroom/src/main/resources/test/metaschema.json b/storeroom/src/main/resources/test/metaschema.json
index f54e572..3e7e10e 100644
--- a/storeroom/src/main/resources/test/metaschema.json
+++ b/storeroom/src/main/resources/test/metaschema.json
@@ -1,8 +1,8 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
- "$ref": "#/definitions/Welcome",
+ "$ref": "#/definitions/MetaSchema",
"definitions": {
- "Welcome": {
+ "MetaSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
@@ -17,7 +17,8 @@
"type": "string",
"format": "uri",
"qt-uri-protocols": [
- "https"
+ "https",
+ "http"
],
"qt-uri-extensions": [
".4"
@@ -56,7 +57,7 @@
"examples": {
"type": "array",
"items": {
- "$ref": "#/definitions/WelcomeExample"
+ "$ref": "#/definitions/SchemaExample"
}
}
},
@@ -73,9 +74,9 @@
"title",
"type"
],
- "title": "Welcome"
+ "title": "MetaSchema"
},
- "WelcomeExample": {
+ "SchemaExample": {
"type": "object",
"additionalProperties": false,
"properties": {
@@ -90,7 +91,7 @@
"classOfOnset",
"term"
],
- "title": "WelcomeExample"
+ "title": "SchemaExample"
},
"Meta": {
"type": "object",
@@ -453,4 +454,4 @@
"title": "AllofExample"
}
}
-}
+}
\ No newline at end of file