diff --git a/client/src/app/admin/admin-shared/components/webpage-form-content.component.html b/client/src/app/admin/admin-shared/components/webpage-form-content.component.html index 15c6c4d7ce6f213efa234c0f40e9e26f07891798..2c9f4ecdfc7b994562364eff2466a6304d0ddc45 100644 --- a/client/src/app/admin/admin-shared/components/webpage-form-content.component.html +++ b/client/src/app/admin/admin-shared/components/webpage-form-content.component.html @@ -4,7 +4,7 @@ <div class="code-container line-numbers"> <textarea #textArea - placeholder="Add your code (default html)" + placeholder="Add your code ({{ codeType }})" class="text-area-code-editor" id="{{ controlName }}" name="{{ controlName }}" diff --git a/client/src/app/admin/admin-shared/components/webpage-form-content.component.ts b/client/src/app/admin/admin-shared/components/webpage-form-content.component.ts index 77de9bf04795245a6e6880cf4098728ba1dc5bdf..909f8157347a3c7b4d77a7826e4f153ee88d1bdb 100644 --- a/client/src/app/admin/admin-shared/components/webpage-form-content.component.ts +++ b/client/src/app/admin/admin-shared/components/webpage-form-content.component.ts @@ -23,6 +23,7 @@ export class WebpageFormContentComponent implements OnInit, AfterViewChecked, Af @Input() form: UntypedFormGroup; @Input() controlName: string; @Input() controlLabel: string; + @Input() codeType: string; @ViewChild('textArea', { static: true }) textArea!: ElementRef; @@ -33,7 +34,6 @@ export class WebpageFormContentComponent implements OnInit, AfterViewChecked, Af sub!: Subscription; highlighted = false; - codeType = 'html'; constructor( private prismService: PrismService, diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html index d27924f7b1316cc8a0f8f705255f46c8a7d73f72..f553fd7cd347a737fa8426cdc826ff85e1d9c206 100644 --- a/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html +++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html @@ -3,7 +3,7 @@ <input class="custom-control-input" type="checkbox" id="enabled" name="enabled" formControlName="enabled"> <label class="custom-control-label" for="enabled">Enabled</label> </div> - <app-webpage-form-content [form]="form" [controlName]="'content'" [controlLabel]="'Content'"></app-webpage-form-content> + <app-webpage-form-content [form]="form" [controlName]="'content'" [controlLabel]="'Content'" [codeType]="'html'"></app-webpage-form-content> <div class="form-group mt-3"> <ng-content></ng-content> </div> diff --git a/client/src/app/admin/instance/webpage/components/webpage-family-card.component.spec.ts b/client/src/app/admin/instance/webpage/components/webpage-family-card.component.spec.ts index 69ca25a3bd1898f2b15811d5f973eefb695be3f7..f69092a0b0bff53a948b3ef74f650f52ccb937c5 100644 --- a/client/src/app/admin/instance/webpage/components/webpage-family-card.component.spec.ts +++ b/client/src/app/admin/instance/webpage/components/webpage-family-card.component.spec.ts @@ -65,9 +65,9 @@ describe('[admin][instance][webpage][components] WebpageFamilyCardComponent ', ( component = fixture.componentInstance; component.webpageFamily = { display: 10, icon: 'test', id: 0, label: 'webpageFamilly test label' }; component.webpageList = [ - { icon: 'test1', content: 'test1', display: 10, id: 0, id_webpage_family: 0, label: 'test1', title: 'test-title1' }, - { icon: 'test2', content: 'test2', display: 10, id: 0, id_webpage_family: 0, label: 'test2', title: 'test-title2' }, - { icon: 'test3', content: 'test3', display: 10, id: 0, id_webpage_family: 1, label: 'test3', title: 'test-title3' } + { icon: 'test1', content: 'test1', display: 10, id: 0, id_webpage_family: 0, label: 'test1', title: 'test-title1', name: 'test1', style_sheet: '' }, + { icon: 'test2', content: 'test2', display: 10, id: 0, id_webpage_family: 0, label: 'test2', title: 'test-title2', name: 'test2', style_sheet: '' }, + { icon: 'test3', content: 'test3', display: 10, id: 0, id_webpage_family: 1, label: 'test3', title: 'test-title3', name: 'test3', style_sheet: '' } ]; fixture.detectChanges(); }); diff --git a/client/src/app/admin/instance/webpage/components/webpage-form.component.html b/client/src/app/admin/instance/webpage/components/webpage-form.component.html index 90cd8c624e95f93e26c15169350da34191969eed..9f5670643ef30f9cb156f1fee5d928c1f5424c30 100644 --- a/client/src/app/admin/instance/webpage/components/webpage-form.component.html +++ b/client/src/app/admin/instance/webpage/components/webpage-form.component.html @@ -1,4 +1,8 @@ <form [formGroup]="form" (ngSubmit)="submit()" novalidate> + <div class="form-group"> + <label for="name">Name</label> + <input type="text" class="form-control" id="name" name="name" formControlName="name"> + </div> <div class="form-group"> <label for="label">Label</label> <input type="text" class="form-control" id="label" name="label" formControlName="label"> @@ -22,7 +26,8 @@ <option *ngFor="let family of webpageFamilyList" [ngValue]="family.id">{{ family.label }}</option> </select> </div> - <app-webpage-form-content [form]="form" [controlName]="'content'" [controlLabel]="'Content'"></app-webpage-form-content> + <app-webpage-form-content [form]="form" [controlName]="'content'" [controlLabel]="'Content'" [codeType]="'html'"></app-webpage-form-content> + <app-webpage-form-content [form]="form" [controlName]="'style_sheet'" [controlLabel]="'Style sheet css'" [codeType]="'css'"></app-webpage-form-content> <div class="form-group pt-4"> <ng-content></ng-content> </div> diff --git a/client/src/app/admin/instance/webpage/components/webpage-form.component.spec.ts b/client/src/app/admin/instance/webpage/components/webpage-form.component.spec.ts index f170e45aa20337fcd606d1c1ca6d17b92b72ad48..a37554bbe6791cf719bd3ecc3a27ce131ff5adab 100644 --- a/client/src/app/admin/instance/webpage/components/webpage-form.component.spec.ts +++ b/client/src/app/admin/instance/webpage/components/webpage-form.component.spec.ts @@ -23,14 +23,16 @@ describe('[admin][instance][webpage][components]WebpageFormComponent ', () => { let fixture: ComponentFixture<WebpageFormComponent>; let spy; let form = new UntypedFormGroup({ + name: new UntypedFormControl('', [Validators.required]), label: new UntypedFormControl('', [Validators.required]), icon: new UntypedFormControl(null), display: new UntypedFormControl('', [Validators.required]), title: new UntypedFormControl('', [Validators.required]), content: new UntypedFormControl('', [Validators.required]), + style_sheet: new UntypedFormControl(null), id_webpage_family: new UntypedFormControl('', [Validators.required]) }); - let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '' }; + let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '', name: '', style_sheet: '' }; beforeEach(() => { TestBed.configureTestingModule({ @@ -60,7 +62,6 @@ describe('[admin][instance][webpage][components]WebpageFormComponent ', () => { component.submit(); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith({ ...component.webpage, ...component.form.getRawValue() }); - }) it('should emit with webpage only', () => { diff --git a/client/src/app/admin/instance/webpage/components/webpage-form.component.ts b/client/src/app/admin/instance/webpage/components/webpage-form.component.ts index d549ba2e361bdd893f985b9e060749dfd2ee8e13..ba2b297a884ee4895284ff557399b51891a8146d 100644 --- a/client/src/app/admin/instance/webpage/components/webpage-form.component.ts +++ b/client/src/app/admin/instance/webpage/components/webpage-form.component.ts @@ -23,11 +23,13 @@ export class WebpageFormComponent implements OnInit { @Output() onSubmit: EventEmitter<Webpage> = new EventEmitter(); public form = new UntypedFormGroup({ + name: new UntypedFormControl('', [Validators.required]), label: new UntypedFormControl('', [Validators.required]), icon: new UntypedFormControl(null), display: new UntypedFormControl('', [Validators.required]), title: new UntypedFormControl('', [Validators.required]), content: new UntypedFormControl('', [Validators.required]), + style_sheet: new UntypedFormControl(null), id_webpage_family: new UntypedFormControl('', [Validators.required]) }); diff --git a/client/src/app/admin/instance/webpage/containers/edit-webpage.component.spec.ts b/client/src/app/admin/instance/webpage/containers/edit-webpage.component.spec.ts index 257f6a6ae024249300ec6d58c26751d8eee8262a..fe59080fb34c82f4918884ab457f4c48ef542ecc 100644 --- a/client/src/app/admin/instance/webpage/containers/edit-webpage.component.spec.ts +++ b/client/src/app/admin/instance/webpage/containers/edit-webpage.component.spec.ts @@ -48,7 +48,7 @@ describe('[admin][instance][webpage][containers] EditWebpageComponent ', () => { }); it('dispatch webpageActions.editWebPage with the new webpage values', () => { - let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '' }; + let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '', name: '', style_sheet: '' }; component.editWebpage(webpage); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(webpageActions.editWebpage({ webpage })); diff --git a/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts b/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts index 44278efd0621ed691ee1e631e8cb886715e4dc8e..3fd5c4d7ed98a9dc8e96c30d6869973929089d3c 100644 --- a/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts +++ b/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts @@ -56,7 +56,7 @@ describe('[admin][instance][webpage][containers] NewWebpageComponent ', () => { }); it('dispatch webpageActions.addWebPage with the new webpage values', () => { - let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '' }; + let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '', name: '', style_sheet: '' }; component.addNewWebpage(webpage); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(webpageActions.addWebpage({ webpage })); diff --git a/client/src/app/admin/instance/webpage/containers/webpage-list.component.spec.ts b/client/src/app/admin/instance/webpage/containers/webpage-list.component.spec.ts index 2fa3c696c419ea19ae29f087e4e1f028bf7710bb..4263e34d6fbf437b74e75a0e84a523c726e43d86 100644 --- a/client/src/app/admin/instance/webpage/containers/webpage-list.component.spec.ts +++ b/client/src/app/admin/instance/webpage/containers/webpage-list.component.spec.ts @@ -88,7 +88,7 @@ describe('[admin][instance][webpage][containers] WebpageListComponent ', () => { }); it('dispatch webpageFamilyActions.deleteWebpage', () => { - let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '' }; + let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: '', title: '', name: '', style_sheet: '' }; component.deleteWebpage(webpage); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(webpageActions.deleteWebpage({webpage})); diff --git a/client/src/app/admin/instance/webpage/edit-webpage-title.resolver.spec.ts b/client/src/app/admin/instance/webpage/edit-webpage-title.resolver.spec.ts index 7db89ec783db26513a64213810f0c671bcce48aa..5035294341c690a6de3482cbfed90af5ee447cdc 100644 --- a/client/src/app/admin/instance/webpage/edit-webpage-title.resolver.spec.ts +++ b/client/src/app/admin/instance/webpage/edit-webpage-title.resolver.spec.ts @@ -32,7 +32,7 @@ describe('[Webpage] EditWebpageTitleResolver', () => { provideMockStore({}), ] }) - let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: 'webpage_test_label', title: '' }; + let webpage: Webpage = { icon: '', content: '', display: 10, id: 0, id_webpage_family: 0, label: 'webpage_test_label', title: '', name: '', style_sheet: '' }; let instance: Instance; instance = { ...instance, label: 'instance_test_label' } diff --git a/client/src/app/instance/components/instance-navbar.component.ts b/client/src/app/instance/components/instance-navbar.component.ts index ec4cc6a4b3a1639d966971887c24779b76e5e3ed..06696f9f0926fd74394e3a27446ce389ffd6225c 100644 --- a/client/src/app/instance/components/instance-navbar.component.ts +++ b/client/src/app/instance/components/instance-navbar.component.ts @@ -57,21 +57,13 @@ export class InstanceNavbarComponent { getInstanceBaseHref() { if (this.firstWebpage) { - return `/instance/${this.instance.name}/webpage/${this.firstWebpage.id}`; + return `/instance/${this.instance.name}/webpage/${this.firstWebpage.name}`; } else { return `/instance/${this.instance.name}`; } } - getWebpageListByFamily(webpageFamily) { + getWebpageListByFamily(webpageFamily: WebpageFamily) { return this.webpageList.filter(webpage => webpage.id_webpage_family === webpageFamily.id); } - - // getNavbarStyle() { - // return { - // 'background-color': this.instance.navbar_background_color, - // 'border-bottom': `1px solid ${this.instance.navbar_border_bottom_color}`, - // 'color': this.instance.navbar_color - // }; - // } } diff --git a/client/src/app/instance/components/webpage-family-nav-mobile.component.html b/client/src/app/instance/components/webpage-family-nav-mobile.component.html index d95db1eee897dfe7a5e768753a30122be3fa683f..2530707afda33eae96cc227ef913f93d2adc0ba0 100644 --- a/client/src/app/instance/components/webpage-family-nav-mobile.component.html +++ b/client/src/app/instance/components/webpage-family-nav-mobile.component.html @@ -1,5 +1,5 @@ <li *ngIf="webpageList.length === 1" role="menuitem"> - <a class="dropdown-item" routerLink="webpage/{{ webpageList[0].id }}"> + <a class="dropdown-item" routerLink="webpage/{{ webpageList[0].name }}"> <span *ngIf="webpageList[0].icon" [ngClass]="webpageList[0].icon"></span> {{ webpageList[0].label }} </a> </li> @@ -9,7 +9,7 @@ <span *ngIf="webpageFamily.icon" [ngClass]="webpageFamily.icon"></span> {{ webpageFamily.label }} : </li> <li *ngFor="let webpage of webpageList" role="menuitem" class="ml-2"> - <a class="dropdown-item" routerLink="webpage/{{ webpage.id }}" fragment="nested-dropdowns"> + <a class="dropdown-item" routerLink="webpage/{{ webpage.name }}" fragment="nested-dropdowns"> <span *ngIf="webpage.icon" [ngClass]="webpage.icon"></span> {{ webpage.label }} </a> </li> diff --git a/client/src/app/instance/components/webpage-family-nav.component.html b/client/src/app/instance/components/webpage-family-nav.component.html index d01574033a559d254ce33721545abcd59cfafa77..be2f65ec992ca547d1ca3578149bf6204b2bd968 100644 --- a/client/src/app/instance/components/webpage-family-nav.component.html +++ b/client/src/app/instance/components/webpage-family-nav.component.html @@ -1,5 +1,5 @@ <li *ngIf="webpageList.length === 1" class="nav-item pr-3"> - <a class="nav-link" routerLink="webpage/{{ webpageList[0].id }}" routerLinkActive="active"> + <a class="nav-link" routerLink="webpage/{{ webpageList[0].name }}" routerLinkActive="active"> <span *ngIf="webpageList[0].icon" [ngClass]="webpageList[0].icon"></span> {{ webpageList[0].label }} </a> </li> @@ -9,7 +9,7 @@ <span *ngIf="webpageFamily.icon" [ngClass]="webpageFamily.icon"></span> {{ webpageFamily.label }} </a> <div *dropdownMenu class="dropdown-menu"> - <a *ngFor="let webpage of webpageList" class="dropdown-item" routerLink="webpage/{{ webpage.id }}" routerLinkActive="active"> + <a *ngFor="let webpage of webpageList" class="dropdown-item" routerLink="webpage/{{ webpage.name }}" routerLinkActive="active"> <span *ngIf="webpage.icon" [ngClass]="webpage.icon"></span> {{ webpage.label }} </a> </div> diff --git a/client/src/app/instance/instance.component.spec.ts b/client/src/app/instance/instance.component.spec.ts index 532d50d639f3f0f8fd0a542d46c6e848255c3053..df5f0ff3cc0f85b5b1e17675053ceafc6852466e 100644 --- a/client/src/app/instance/instance.component.spec.ts +++ b/client/src/app/instance/instance.component.spec.ts @@ -144,11 +144,13 @@ describe('[Instance] InstanceComponent', () => { const webpage: Webpage = { id: 1, + name: 'home', label: 'Home', title: 'Home', display: 10, icon: 'fas fa-home', content: '<p>Hello</p>', + style_sheet: '', id_webpage_family: 1 } diff --git a/client/src/app/instance/instance.component.ts b/client/src/app/instance/instance.component.ts index d2ed0b622683c10a6b579a76fd67086a9c9c968c..90b9a5f6d50eb5d7799ac63f1c6f98bc0d5ae583 100644 --- a/client/src/app/instance/instance.component.ts +++ b/client/src/app/instance/instance.component.ts @@ -158,7 +158,7 @@ export class InstanceComponent implements OnInit, OnDestroy { this.firstWebpageSubscription = this.firstWebpage.subscribe(webpage => { const iname = this.route.snapshot.paramMap.get('iname'); if (webpage && this.router.url === `/instance/${iname}`) { - this.router.navigate(['webpage', webpage.id], { relativeTo: this.route }); + this.router.navigate(['webpage', webpage.name], { relativeTo: this.route }); } }); } diff --git a/client/src/app/instance/webpage/components/webpage-content.component.html b/client/src/app/instance/webpage/components/webpage-content.component.html index 5fff195df3ec184143772fe509157449a25c0c0b..a7680459dfb4382a998d3284663beefc8e80adf4 100644 --- a/client/src/app/instance/webpage/components/webpage-content.component.html +++ b/client/src/app/instance/webpage/components/webpage-content.component.html @@ -1 +1 @@ -<ngx-dynamic-hooks [content]="webpage.content" [parsers]="getParsers()"></ngx-dynamic-hooks> \ No newline at end of file +<ngx-dynamic-hooks class="webpage-{{instance.name}}-{{webpage.name}}" [content]="webpage.content" [parsers]="getParsers()"></ngx-dynamic-hooks> \ No newline at end of file diff --git a/client/src/app/instance/webpage/components/webpage-content.component.ts b/client/src/app/instance/webpage/components/webpage-content.component.ts index 7559b9c51420858fc938a183b3b481c867ed4f29..1a078fdeb53a30533ea7b702875143c6a01b0fc9 100644 --- a/client/src/app/instance/webpage/components/webpage-content.component.ts +++ b/client/src/app/instance/webpage/components/webpage-content.component.ts @@ -7,11 +7,12 @@ * file that was distributed with this source code. */ -import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; +import { Component, OnChanges, SimpleChanges, Input, ChangeDetectionStrategy } from '@angular/core'; -import { Webpage } from 'src/app/metamodel/models'; +import { Instance, Webpage } from 'src/app/metamodel/models'; import { globalParsers } from 'src/app/shared/dynamic-content'; import { componentParsers } from '../dynamic-content'; +import { StyleService } from 'src/app/shared/services/style.service'; /** * @class @@ -22,8 +23,24 @@ import { componentParsers } from '../dynamic-content'; templateUrl: 'webpage-content.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -export class WebpageComponent { +export class WebpageComponent implements OnChanges { @Input() webpage: Webpage; + @Input() instance: Instance; + + constructor(private style: StyleService) { } + + ngOnChanges(changes: SimpleChanges) { + if (changes.webpage && changes.webpage.currentValue && changes.webpage.currentValue.style_sheet) { + const webpage = changes.webpage.currentValue; + this.style.addCSS( + webpage.style_sheet.replace( + /(.+{)/g, + (match, $1) => `.webpage-${this.instance.name}-${webpage.name} ${$1}` + ), + 'webpage' + ); + } + } getParsers() { return [ diff --git a/client/src/app/instance/webpage/containers/webpage.component.html b/client/src/app/instance/webpage/containers/webpage.component.html index e6c9db3b20bcefbf455c1f2194083840f3bcb3c1..0d970c0b1faba3f8152ae0a0e7dc566d66544a5c 100644 --- a/client/src/app/instance/webpage/containers/webpage.component.html +++ b/client/src/app/instance/webpage/containers/webpage.component.html @@ -1,6 +1,8 @@ <div class="container"> <app-spinner *ngIf="webpageListIsLoading | async"></app-spinner> - <app-webpage-content *ngIf="webpageListIsLoaded | async" [webpage]="webpage | async"> + <app-webpage-content *ngIf="webpageListIsLoaded | async" + [webpage]="webpage | async" + [instance]="instance | async"> </app-webpage-content> </div> diff --git a/client/src/app/instance/webpage/containers/webpage.component.ts b/client/src/app/instance/webpage/containers/webpage.component.ts index b1d9d4b11572b83a4f6dd85d9420f13a67f8590e..21d11a4ba153a13c9eb89c8220113e642e3f4db3 100644 --- a/client/src/app/instance/webpage/containers/webpage.component.ts +++ b/client/src/app/instance/webpage/containers/webpage.component.ts @@ -12,8 +12,9 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { Store } from '@ngrx/store'; -import { Webpage } from 'src/app/metamodel/models'; +import { Instance, Webpage } from 'src/app/metamodel/models'; import * as webpageSelector from 'src/app/metamodel/selectors/webpage.selector'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; /** * @class @@ -25,13 +26,15 @@ import * as webpageSelector from 'src/app/metamodel/selectors/webpage.selector'; }) export class WebpageComponent { public title: HTMLLinkElement = document.querySelector('#title'); + public instance: Observable<Instance>; public webpageListIsLoading: Observable<boolean>; public webpageListIsLoaded: Observable<boolean>; public webpage: Observable<Webpage>; constructor(private store: Store<{ }>) { + this.instance = store.select(instanceSelector.selectInstanceByRouteName); this.webpageListIsLoading = store.select(webpageSelector.selectWebpageListIsLoading); this.webpageListIsLoaded = store.select(webpageSelector.selectWebpageListIsLoaded); - this.webpage = this.store.select(webpageSelector.selectWebpageByRouteId); + this.webpage = this.store.select(webpageSelector.selectWebpageByRouteName); } } diff --git a/client/src/app/instance/webpage/webpage-routing.module.ts b/client/src/app/instance/webpage/webpage-routing.module.ts index c71f35d1922b7a861ceb261e62468d751b0ef991..0e8f66832f9c484d1229f18711aef11300e0e5bf 100644 --- a/client/src/app/instance/webpage/webpage-routing.module.ts +++ b/client/src/app/instance/webpage/webpage-routing.module.ts @@ -14,7 +14,7 @@ import { WebpageComponent } from './containers/webpage.component'; import { WebpageTitleResolver } from './webpage-title.resolver'; const routes: Routes = [ - { path: ':id', component: WebpageComponent, title: WebpageTitleResolver } + { path: ':name', component: WebpageComponent, title: WebpageTitleResolver } ]; /** diff --git a/client/src/app/instance/webpage/webpage-title.resolver.ts b/client/src/app/instance/webpage/webpage-title.resolver.ts index cebe5115333bc4744090d1919fdb4ed27fa02c7c..f47b1c846227a724e4f691ef73b9037d47d2c83f 100644 --- a/client/src/app/instance/webpage/webpage-title.resolver.ts +++ b/client/src/app/instance/webpage/webpage-title.resolver.ts @@ -26,7 +26,7 @@ export class WebpageTitleResolver implements Resolve<string> { switchMap(() => { return combineLatest([ this.store.pipe(select(instanceSelector.selectInstanceByRouteName)), - this.store.pipe(select(webpageSelector.selectWebpageByRouteId)) + this.store.pipe(select(webpageSelector.selectWebpageByRouteName)) ]).pipe( map(([instance, webpage]) => `${instance.label} - ${webpage.label}`) ); diff --git a/client/src/app/metamodel/models/webpage.model.ts b/client/src/app/metamodel/models/webpage.model.ts index 7f37e6d5ad87de24f8870fd6c1f10e08db729545..ccf37b79b2a54924829a62b8e64a5c2274f34fc0 100644 --- a/client/src/app/metamodel/models/webpage.model.ts +++ b/client/src/app/metamodel/models/webpage.model.ts @@ -14,10 +14,12 @@ */ export interface Webpage { id: number; + name: string; label: string; icon: string; display: number; title: string; content: string; + style_sheet: string; id_webpage_family: number; } diff --git a/client/src/app/metamodel/selectors/webpage.selector.ts b/client/src/app/metamodel/selectors/webpage.selector.ts index 618fa2a5a6cfe0dc2ced637fc15d39364e59a94e..00a23971ac778890c82e8f0c8093425b79cedb26 100644 --- a/client/src/app/metamodel/selectors/webpage.selector.ts +++ b/client/src/app/metamodel/selectors/webpage.selector.ts @@ -54,6 +54,12 @@ export const selectWebpageByRouteId = createSelector( (entities, router) => entities[router.state.params.id] ); +export const selectWebpageByRouteName = createSelector( + selectAllWebpages, + reducer.selectRouterState, + (webpages, router) => webpages.find(webpage => webpage.name === router.state.params.name) +); + export const selectFirstWebpage = createSelector( webpageFamilySelector.selectAllWebpageFamilies, webpageFamilySelector.selectWebpageFamilyListIsLoaded, diff --git a/client/src/app/shared/services/style.service.ts b/client/src/app/shared/services/style.service.ts index f04030050637699c2844a884d02f673ebfdce53a..b73c5e2b7ce22e2a0e5853fbc4f349c8db82cbb3 100644 --- a/client/src/app/shared/services/style.service.ts +++ b/client/src/app/shared/services/style.service.ts @@ -47,6 +47,19 @@ export class StyleService { }); } + public addCSS(styleSheet: string, id: string) { + const element = document.getElementById('webpage'); + if (element) { + element.innerHTML = styleSheet; + } else { + const styleSheetElement = document.createElement('style'); + styleSheetElement.setAttribute('id', id); + styleSheetElement.type = "text/css"; + styleSheetElement.innerHTML = styleSheet; + this.headElement.appendChild(styleSheetElement); + } + } + private createCssStyleSheet(): CSSStyleSheet { // Create the style sheet element. let styleSheetElement = document.createElement("style"); diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh index c89751cbabe50e559ce1c966c2f4b654df2cacf8..38e26bcce02944627c2b524a54f5613372270116 100644 --- a/conf-dev/create-db.sh +++ b/conf-dev/create-db.sh @@ -136,4 +136,4 @@ curl -d '{"id":3,"name":"observer","label":"observer","form_label":"observer","d # Add webpages curl -d '{"label":"Default","icon":null,"display":10}' --header 'Content-Type: application/json' -X POST http://localhost/instance/default/webpage-family -curl -d '{"label":"Home","icon":"fas fa-home","display":10,"title":"Home","content":"<div class=\"row align-items-center jumbotron\">\n <div class=\"col-6 col-md-4 order-md-2 mx-auto text-center\">\n <img class=\"img-fluid mb-3 mb-md-0\" src=\"http://localhost:8080/instance/default/file-explorer/home_component_logo.png\" alt=\"Instance logo\">\n </div>\n <div class=\"col-md-8 order-md-1 text-justify pr-md-5\">\n <h2 class=\"mb-3\">Welcome to the ANIS default instance</h2>\n <p class=\"lead\">\n This service provides several sub-services to interact with the database.<br>\n Here is a brief presentation of these sub-services:\n </p>\n <ul class=\"lead\">\n <li>\n <a href=\"https://drf-gitlab.cea.fr/svom/sdb/api-import/-/wikis/home\">\n /import/\n </a> => This sub-service allows you to import data L0, L1 or SR3/SR4\n </li>\n <li>\n /export-rest => => This sub-service allows you to request and export data \n from the database in json format with a specific URL. To build this URL you could \n <a class=\"btn btn-warning\" href=\"/instance/default/search/dataset\">\n Go to search form\n </a>\n </li>\n </ul>\n </div>\n</div>\n<app-dataset-sample\n [datasetName]=\"'\''observations'\''\"\n [sortingColumn]=\"1\"\n [sortingDirection]=\"'\''d'\''\"\n [nbItems]=\"5\">\n</app-dataset-sample>"}' --header 'Content-Type: application/json' -X POST http://localhost/webpage-family/1/webpage +curl -d '{"name":"home","label":"Home","icon":"fas fa-home","display":10,"title":"Home","content":"<div class=\"row align-items-center jumbotron\">\n <div class=\"col-6 col-md-4 order-md-2 mx-auto text-center\">\n <img class=\"img-fluid mb-3 mb-md-0\" src=\"http://localhost:8080/instance/default/file-explorer/home_component_logo.png\" alt=\"Instance logo\">\n </div>\n <div class=\"col-md-8 order-md-1 text-justify pr-md-5\">\n <h2 class=\"mb-3\">Welcome to the ANIS default instance</h2>\n <p class=\"lead\">\n This service provides several sub-services to interact with the database.<br>\n Here is a brief presentation of these sub-services:\n </p>\n <ul class=\"lead\">\n <li>\n <a href=\"https://drf-gitlab.cea.fr/svom/sdb/api-import/-/wikis/home\">\n /import/\n </a> => This sub-service allows you to import data L0, L1 or SR3/SR4\n </li>\n <li>\n /export-rest => => This sub-service allows you to request and export data \n from the database in json format with a specific URL. To build this URL you could \n <a class=\"btn btn-warning\" href=\"/instance/default/search/dataset\">\n Go to search form\n </a>\n </li>\n </ul>\n </div>\n</div>\n<app-dataset-sample\n [datasetName]=\"'\''observations'\''\"\n [sortingColumn]=\"1\"\n [sortingDirection]=\"'\''d'\''\"\n [nbItems]=\"5\">\n</app-dataset-sample>","style_sheet":".lead {\n color: #b60707;\n}"}' --header 'Content-Type: application/json' -X POST http://localhost/webpage-family/1/webpage diff --git a/server/doctrine-proxy/__CG__AppEntityWebpage.php b/server/doctrine-proxy/__CG__AppEntityWebpage.php index 45116fc175f6bdcf3675b96510f029606488d871..8450952cff50d1d427dd4d2b92d31ac1a2bcb335 100644 --- a/server/doctrine-proxy/__CG__AppEntityWebpage.php +++ b/server/doctrine-proxy/__CG__AppEntityWebpage.php @@ -67,10 +67,10 @@ class Webpage extends \App\Entity\Webpage implements \Doctrine\ORM\Proxy\Proxy public function __sleep() { if ($this->__isInitialized__) { - return ['__isInitialized__', 'id', 'label', 'icon', 'display', 'title', 'content', 'webpageFamily']; + return ['__isInitialized__', 'id', 'name', 'label', 'icon', 'display', 'title', 'content', 'styleSheet', 'webpageFamily']; } - return ['__isInitialized__', 'id', 'label', 'icon', 'display', 'title', 'content', 'webpageFamily']; + return ['__isInitialized__', 'id', 'name', 'label', 'icon', 'display', 'title', 'content', 'styleSheet', 'webpageFamily']; } /** @@ -192,6 +192,28 @@ class Webpage extends \App\Entity\Webpage implements \Doctrine\ORM\Proxy\Proxy return parent::getId(); } + /** + * {@inheritDoc} + */ + public function getName() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getName', []); + + return parent::getName(); + } + + /** + * {@inheritDoc} + */ + public function setName($name) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setName', [$name]); + + return parent::setName($name); + } + /** * {@inheritDoc} */ @@ -302,6 +324,28 @@ class Webpage extends \App\Entity\Webpage implements \Doctrine\ORM\Proxy\Proxy return parent::setContent($content); } + /** + * {@inheritDoc} + */ + public function getStyleSheet() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getStyleSheet', []); + + return parent::getStyleSheet(); + } + + /** + * {@inheritDoc} + */ + public function setStyleSheet($styleSheet) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setStyleSheet', [$styleSheet]); + + return parent::setStyleSheet($styleSheet); + } + /** * {@inheritDoc} */ diff --git a/server/src/Action/WebpageAction.php b/server/src/Action/WebpageAction.php index 9ecd704f93d720d030e44d1dc42c648aa9ecbf18..673762b51888a17ba28b973b4f1c53044488e279 100644 --- a/server/src/Action/WebpageAction.php +++ b/server/src/Action/WebpageAction.php @@ -62,7 +62,7 @@ final class WebpageAction extends AbstractAction if ($request->getMethod() === PUT) { $parsedBody = $request->getParsedBody(); - $fields = array('label', 'icon', 'display', 'title', 'content'); + $fields = array('name', 'label', 'icon', 'display', 'title', 'content', 'style_sheet'); foreach ($fields as $a) { if (!array_key_exists($a, $parsedBody)) { throw new HttpBadRequestException( @@ -97,11 +97,13 @@ final class WebpageAction extends AbstractAction */ private function editWebpage(Webpage $webpage, array $parsedBody): void { + $webpage->setName($parsedBody['name']); $webpage->setLabel($parsedBody['label']); $webpage->setIcon($parsedBody['icon']); $webpage->setDisplay($parsedBody['display']); $webpage->setTitle($parsedBody['title']); $webpage->setContent($parsedBody['content']); + $webpage->setStyleSheet($parsedBody['style_sheet']); $this->em->flush(); } } diff --git a/server/src/Action/WebpageListAction.php b/server/src/Action/WebpageListAction.php index 71d9d8600bb8609cd1fb49f97591e8c306a84b8d..580966fda3f0a264c7cf5d363a2505256118b355 100644 --- a/server/src/Action/WebpageListAction.php +++ b/server/src/Action/WebpageListAction.php @@ -65,7 +65,7 @@ final class WebpageListAction extends AbstractAction $parsedBody = $request->getParsedBody(); // To work this action needs information - foreach (array('label', 'icon', 'display', 'title', 'content') as $a) { + foreach (array('name', 'label', 'icon', 'display', 'title', 'content', 'style_sheet') as $a) { if (!array_key_exists($a, $parsedBody)) { throw new HttpBadRequestException( $request, @@ -94,11 +94,13 @@ final class WebpageListAction extends AbstractAction private function postWebpage(array $parsedBody, WebpageFamily $webpageFamily): Webpage { $webpage = new Webpage(); + $webpage->setName($parsedBody['name']); $webpage->setLabel($parsedBody['label']); $webpage->setIcon($parsedBody['icon']); $webpage->setDisplay($parsedBody['display']); $webpage->setTitle($parsedBody['title']); $webpage->setContent($parsedBody['content']); + $webpage->setStyleSheet($parsedBody['style_sheet']); $webpage->setWebpageFamily($webpageFamily); $this->em->persist($webpage); diff --git a/server/src/Entity/Webpage.php b/server/src/Entity/Webpage.php index f3881f4284b6ef08c260c5aab5accd5f0f3e3b8b..52b7371e1f94b8c14364c91c691f1062f9024fae 100644 --- a/server/src/Entity/Webpage.php +++ b/server/src/Entity/Webpage.php @@ -30,6 +30,13 @@ class Webpage implements \JsonSerializable */ protected $id; + /** + * @var string + * + * @Column(type="string", name="name", nullable=false) + */ + protected $name; + /** * @var string * @@ -65,6 +72,13 @@ class Webpage implements \JsonSerializable */ protected $content; + /** + * @var string + * + * @Column(type="text", name="style_sheet", nullable=true) + */ + protected $styleSheet; + /** * @var WebpageFamily * @@ -78,6 +92,16 @@ class Webpage implements \JsonSerializable return $this->id; } + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } + public function getLabel() { return $this->label; @@ -128,6 +152,16 @@ class Webpage implements \JsonSerializable $this->content = $content; } + public function getStyleSheet() + { + return $this->styleSheet; + } + + public function setStyleSheet($styleSheet) + { + $this->styleSheet = $styleSheet; + } + public function getWebpageFamily() { return $this->webpageFamily; @@ -142,11 +176,13 @@ class Webpage implements \JsonSerializable { return [ 'id' => $this->getId(), + 'name' => $this->getName(), 'label' => $this->getLabel(), 'icon' => $this->getIcon(), 'display' => $this->getDisplay(), 'title' => $this->getTitle(), 'content' => $this->getContent(), + 'style_sheet' => $this->getStyleSheet(), 'id_webpage_family' => $this->getWebpageFamily()->getId(), ]; }