diff --git a/angular.json b/angular.json index 329e6e9b75b2147adfaceaf01cb6a9b4f58a57be..4036b3bce35e7201d2604667614a400a9901e70e 100644 --- a/angular.json +++ b/angular.json @@ -30,9 +30,12 @@ "node_modules/material-design-icons/iconfont/material-icons.css", "node_modules/roboto-fontface/css/roboto/roboto-fontface.css", "node_modules/primeng/resources/primeng.min.css", - "node_modules/primeng/resources/themes/nova-light/theme.css" + "node_modules/primeng/resources/themes/nova-light/theme.css", + "node_modules/katex/dist/katex.min.css" ], "scripts": [ + "node_modules/marked/lib/marked.js", + "node_modules/katex/dist/katex.min.js" ], "showCircularDependencies": false }, diff --git a/package-lock.json b/package-lock.json index 60d4cba85c634fd581fe67d5ba0c7efcee2913a3..ccc9d5b1ebc81c016039d9eab74a8d2fdad893b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2565,6 +2565,11 @@ "@types/jasmine": "*" } }, + "@types/marked": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.6.5.tgz", + "integrity": "sha512-6kBKf64aVfx93UJrcyEZ+OBM5nGv4RLsI6sR1Ar34bpgvGVRoyTgpxn4ZmtxOM5aDTAaaznYuYUH8bUX3Nk3YA==" + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -10994,6 +10999,14 @@ "source-map-support": "^0.5.5" } }, + "katex": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz", + "integrity": "sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww==", + "requires": { + "commander": "^2.19.0" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -11576,9 +11589,9 @@ "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==" }, "marked": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.3.tgz", - "integrity": "sha512-Fqa7eq+UaxfMriqzYLayfqAE40WN03jf+zHjT18/uXNuzjq3TY0XTbrAoPeqSJrAmPz11VuUA+kBPYOhHt9oOQ==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==" }, "material-design-icons": { "version": "3.0.1", @@ -12195,21 +12208,23 @@ "resolved": "https://registry.npmjs.org/ngx-konami/-/ngx-konami-1.6.0.tgz", "integrity": "sha512-no/NocDjFnGw5XlNlj6LavP2YA3NxEg3eIHylU9dblkl5JgcfIEw3YntRs9/3OUSnVZGhZSNZkO35sY2AGtkoA==" }, - "ngx-material-file-input": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ngx-material-file-input/-/ngx-material-file-input-1.1.1.tgz", - "integrity": "sha512-rYhBPAr7EZca6RoFWKcceV4Y4V2xH8SPAgrA/bCXgKbS/tJ+h/e9UW3jIPMWVOR/u/rbNhzuXVTuTMfSgS3klw==", + "ngx-markdown": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-8.2.0.tgz", + "integrity": "sha512-4sWz08Hjqvz35OGtSUcfnO9grkkC7+agRlsVZxi2xpYbkmFiRk7cMKGVfRFe+tqzjOxKi1j3BwUG+x2tAGpVlA==", "requires": { + "@types/marked": "^0.6.5", + "katex": "^0.11.1", + "marked": "^0.7.0", + "prismjs": "^1.16.0", "tslib": "^1.9.0" } }, - "ngx-md": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/ngx-md/-/ngx-md-8.0.0.tgz", - "integrity": "sha512-VLbdKnrHblK7UKDJpsKjiwZFujU075x/TLCzsiAuXtLWtj5IKG8XU5a6BZxHi71ScJtPs1qgjpwWown6okjjOg==", + "ngx-material-file-input": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ngx-material-file-input/-/ngx-material-file-input-1.1.1.tgz", + "integrity": "sha512-rYhBPAr7EZca6RoFWKcceV4Y4V2xH8SPAgrA/bCXgKbS/tJ+h/e9UW3jIPMWVOR/u/rbNhzuXVTuTMfSgS3klw==", "requires": { - "marked": "^0.6.2", - "prismjs": "^1.15.0", "tslib": "^1.9.0" } }, @@ -13452,9 +13467,9 @@ "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" }, "prismjs": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.16.0.tgz", - "integrity": "sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz", + "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==", "requires": { "clipboard": "^2.0.0" } diff --git a/package.json b/package.json index 5ca90635c48ba640ba4b5bc2feb701f59de9fa15..3aac7e14545135f92609643f2fa9adf675f9acd6 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,8 @@ "mathjax": "^2.7.5", "mermaid": "^8.2.5", "ngx-konami": "^1.6.0", + "ngx-markdown": "^8.2.0", "ngx-material-file-input": "^1.1.1", - "ngx-md": "^8.0.0", "ngx-webstorage-service": "^4.1.0", "pako": "^1.0.10", "primeng": "^8.0.2", @@ -107,4 +107,4 @@ "android" ] } -} \ No newline at end of file +} diff --git a/src/app/app.component.html b/src/app/app.component.html index 29888b584b0c42354eafcf361d10c0ff1efb6e0c..ada2c37dd155fbdc80add28251d9583a6a4332d6 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -79,49 +79,65 @@ <!-- side panel --> <mat-sidenav class="sidenav" #sidenav fxLayout="column" > - <div fxLayout="column"> - <a id="close-side-nav" class="closebtn" (click)="sidenav.close()">×</a> - - <a id="side-nav-list" routerLink="/list" (click)="sidenav.close()"> - <mat-icon>add</mat-icon> - {{ uitextSidenavNewCalc }} - </a> - <a *ngIf="enableEmptySessionMenu" id="side-nav-empty-session" (click)="sidenav.close(); emptySession()"> - <mat-icon>insert_drive_file</mat-icon> - {{ uitextSidenavEmptySession }} - </a> - <a *ngIf="! enableEmptySessionMenu" id="side-nav-empty-session" class="disabled-link"> - <mat-icon>insert_drive_file</mat-icon> - {{ uitextSidenavEmptySession }} - </a> - <a id="side-nav-load-session" (click)="loadSession(); sidenav.close()"> - <mat-icon>folder_open</mat-icon> - {{ uitextSidenavLoadSession }} - </a> - <a id="side-nav-save-session" (click)="saveForm(); sidenav.close()"> + + <a id="close-side-nav" class="closebtn" (click)="sidenav.close()">×</a> + + <div fxLayout="column" class="full-height-column"> + + <div class="links-container"> + <a id="side-nav-list" routerLink="/list" (click)="sidenav.close()"> + <mat-icon>add</mat-icon> + {{ uitextSidenavNewCalc }} + </a> + <a *ngIf="enableEmptySessionMenu" id="side-nav-empty-session" (click)="sidenav.close(); emptySession()"> + <mat-icon>insert_drive_file</mat-icon> + {{ uitextSidenavEmptySession }} + </a> + <a *ngIf="! enableEmptySessionMenu" id="side-nav-empty-session" class="disabled-link"> + <mat-icon>insert_drive_file</mat-icon> + {{ uitextSidenavEmptySession }} + </a> + <a id="side-nav-load-session" (click)="loadSession(); sidenav.close()"> + <mat-icon>folder_open</mat-icon> + {{ uitextSidenavLoadSession }} + </a> + <a *ngIf="enableSaveSessionMenu" id="side-nav-save-session" (click)="saveForm(); sidenav.close()"> + <mat-icon>file_download</mat-icon> + {{ uitextSidenavSaveSession }} + </a> + <a *ngIf="! enableSaveSessionMenu" id="side-nav-save-session" class="disabled-link"> <mat-icon>file_download</mat-icon> - {{ uitextSidenavSaveSession }} - </a> - <a *ngIf="enableModulesDiagramMenu" id="side-nav-diagram" routerLink="/diagram" (click)="sidenav.close()"> - <mat-icon>insert_chart</mat-icon> - {{ uitextSidenavDiagram }} - </a> - <a *ngIf="! enableModulesDiagramMenu" id="side-nav-diagram" class="disabled-link"> - <mat-icon>insert_chart</mat-icon> - {{ uitextSidenavDiagram }} - </a> - <a id="side-nav-setup" routerLink="/setup" (click)="sidenav.close()"> - <mat-icon>settings</mat-icon> - {{ uitextSidenavParams }} - </a> - <a id="side-nav-bug-report" (click)="reportBug(); sidenav.close()"> - <mat-icon>report_problem</mat-icon> - {{ uitextSidenavReportBug }} - </a> - <a id="side-nav-help" target="_blank" href="assets/docs-fr/index.html" (click)="sidenav.close()"> - <mat-icon>help</mat-icon> - {{ uitextSidenavHelp }} - </a> + {{ uitextSidenavSaveSession }} + </a> + <a *ngIf="enableSessionPropertiesMenu" id="side-nav-session-props" routerLink="/properties" (click)="sidenav.close()"> + <mat-icon>edit</mat-icon> + {{ uitextSidenavSessionProps }} + </a> + <a *ngIf="! enableSessionPropertiesMenu" id="side-nav-session-props" class="disabled-link"> + <mat-icon>edit</mat-icon> + {{ uitextSidenavSessionProps }} + </a> + <a *ngIf="enableModulesDiagramMenu" id="side-nav-diagram" routerLink="/diagram" (click)="sidenav.close()"> + <mat-icon>insert_chart</mat-icon> + {{ uitextSidenavDiagram }} + </a> + <a *ngIf="! enableModulesDiagramMenu" id="side-nav-diagram" class="disabled-link"> + <mat-icon>insert_chart</mat-icon> + {{ uitextSidenavDiagram }} + </a> + <a id="side-nav-setup" routerLink="/setup" (click)="sidenav.close()"> + <mat-icon>settings</mat-icon> + {{ uitextSidenavParams }} + </a> + <a id="side-nav-bug-report" (click)="reportBug(); sidenav.close()"> + <mat-icon>report_problem</mat-icon> + {{ uitextSidenavReportBug }} + </a> + <a id="side-nav-help" target="_blank" href="assets/docs-fr/index.html" (click)="sidenav.close()"> + <mat-icon>help</mat-icon> + {{ uitextSidenavHelp }} + </a> + </div> <div class="hyd_version"> <div class="jalhyd-version"> @@ -137,6 +153,7 @@ <span class="date">updated {{ revisionInfo.nghyd.date }}</span> </div> </div> + </div> </mat-sidenav> diff --git a/src/app/app.component.scss b/src/app/app.component.scss index c90160e4f3b3b8f75168f91b9cc50d6b575fb8c1..5573c4aea42eacc0f66178d50c0cd99ba48a0a7a 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -201,7 +201,6 @@ button:focus { background-color: #111; overflow-x: hidden; padding-top: 60px + $navbar_height; - padding-right: 4em; z-index: 100; a, .div.hyd_version { @@ -234,7 +233,20 @@ button:focus { } } + div.full-height-column { + position: relative; + height: auto; + min-height: 100%; + overflow: hidden; + } + + div.links-container { + margin-bottom: 100px; + padding-right: 4em; + } + div.hyd_version { + display: block; position: absolute; bottom: 0; right: 0; @@ -242,6 +254,7 @@ button:focus { color: #888888; padding: 0 2em 1em 0; text-align: right; + height: 80px; .jalhyd-version { margin-bottom: 0.6em; @@ -263,7 +276,7 @@ button:focus { .closebtn { position: absolute; top: 54px; - right: 25px; + right: 15px; font-size: 36px; margin-left: 50px; } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 2770e60dfb71aa7cfa16a07973393d7041138f6d..4b42b4214800e935458c5f7e47be1c40d0fd206e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -193,6 +193,10 @@ export class AppComponent implements OnInit, OnDestroy, Observer { return this.intlService.localizeText("INFO_MENU_DIAGRAM_TITLE"); } + public get uitextSidenavSessionProps() { + return this.intlService.localizeText("INFO_MENU_SESSION_PROPS"); + } + public get uitextSidenavReportBug() { return this.intlService.localizeText("INFO_MENU_REPORT_BUG"); } @@ -301,10 +305,18 @@ export class AppComponent implements OnInit, OnDestroy, Observer { return this.currentRoute === "/list" && this._calculators.length === 0; } + public get enableSaveSessionMenu(): boolean { + return this._calculators.length > 0; + } + public get enableModulesDiagramMenu(): boolean { return this._calculators.length > 0; } + public get enableSessionPropertiesMenu(): boolean { + return this._calculators.length > 0; + } + public get enableEmptySessionMenu(): boolean { return this._calculators.length > 0; } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e21223513b58c9e5fc04ea10d3cbdc3ef9e3395a..460d1f592ce1410fc5f0125bcaa9bb74f895ba04 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -31,6 +31,7 @@ import { DragDropModule } from "@angular/cdk/drag-drop"; import { TableModule } from "primeng/components/table/table"; import { KonamiModule } from "ngx-konami"; +import { MarkdownModule } from "ngx-markdown"; import { FlexLayoutModule } from "@angular/flex-layout"; import { @@ -44,7 +45,6 @@ import { HttpClientModule } from "@angular/common/http"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; // <-- NgModel lives here import { ChartModule } from "angular2-chartjs"; import { RouterModule, Routes } from "@angular/router"; -import { NgxMdModule } from "ngx-md"; import { StorageServiceModule } from "ngx-webstorage-service"; import { HotkeyModule } from "angular2-hotkeys"; @@ -92,6 +92,7 @@ import { MacrorugoCompoundResultsTableComponent } from "./components/macrorugo-c import { MacrorugoCompoundResultsComponent } from "./components/macrorugo-compound-results/macrorugo-compound-results.component"; import { JetResultsComponent } from "./components/jet-results/jet-results.component"; import { JetTrajectoryChartComponent } from "./components/jet-trajectory-chart/jet-trajectory-chart.component"; +import { SessionPropertiesComponent } from "./components/session-properties/session-properties.component"; import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component"; import { DialogConfirmCloseCalcComponent } from "./components/dialog-confirm-close-calc/dialog-confirm-close-calc.component"; @@ -117,6 +118,7 @@ const appRoutes: Routes = [ { path: "calculator/:uid", component: GenericCalculatorComponent }, { path: "setup", component: ApplicationSetupComponent }, { path: "diagram", component: ModulesDiagramComponent }, + { path: "properties", component: SessionPropertiesComponent }, { path: "**", redirectTo: "list", pathMatch: "full" } ]; @@ -131,6 +133,7 @@ const appRoutes: Routes = [ FlexLayoutModule, HotkeyModule.forRoot(), HttpClientModule, + MarkdownModule.forRoot(), MatBadgeModule, MatButtonModule, MatButtonToggleModule, @@ -152,7 +155,6 @@ const appRoutes: Routes = [ MatTabsModule, MatToolbarModule, MatTooltipModule, - NgxMdModule.forRoot(), RouterModule.forRoot( appRoutes, { @@ -219,6 +221,7 @@ const appRoutes: Routes = [ SectionResultsComponent, SelectFieldLineComponent, SelectModelFieldLineComponent, + SessionPropertiesComponent, VarResultsComponent ], entryComponents: [ diff --git a/src/app/components/session-properties/session-properties.component.html b/src/app/components/session-properties/session-properties.component.html new file mode 100644 index 0000000000000000000000000000000000000000..82095cb78145fc32aeb72361b6e64659c81f44dd --- /dev/null +++ b/src/app/components/session-properties/session-properties.component.html @@ -0,0 +1,25 @@ +<mat-card id="session-properties"> + + <mat-card-header> + <mat-card-title> + <h1>{{ uitextTitle }}</h1> + </mat-card-title> + </mat-card-header> + + <mat-card-content> + + <mat-tab-group> + <mat-tab [label]="uitextPreview"> + <markdown [data]="content" katex [katexOptions]="options"></markdown> + </mat-tab> + <mat-tab [label]="uitextEdit"> + <mat-form-field> + <textarea matInput id="md-editor" [(ngModel)]="content" + cdkTextareaAutosize cdkAutosizeMinRows="15" #autosize="cdkTextareaAutosize"></textarea> + </mat-form-field> + </mat-tab> + </mat-tab-group> + + </mat-card-content> + +</mat-card> diff --git a/src/app/components/session-properties/session-properties.component.scss b/src/app/components/session-properties/session-properties.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..48efb11ece3e94bd33425d210e276092ef116335 --- /dev/null +++ b/src/app/components/session-properties/session-properties.component.scss @@ -0,0 +1,8 @@ +mat-form-field { + width: 100%; + + textarea { + resize: none; + overflow: hidden; + } +} \ No newline at end of file diff --git a/src/app/components/session-properties/session-properties.component.ts b/src/app/components/session-properties/session-properties.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..e44fcc49baf6f942c2a1a76c1ccac6901b775875 --- /dev/null +++ b/src/app/components/session-properties/session-properties.component.ts @@ -0,0 +1,106 @@ +import { + Component, + ViewChild, + AfterContentInit, + OnInit, + AfterViewChecked, + AfterViewInit +} from "@angular/core"; +import { Router } from "@angular/router"; + +import { Session } from "jalhyd"; + +import { I18nService } from "../../services/internationalisation.service"; + +import { KatexOptions } from "ngx-markdown/src/katex-options"; + +@Component({ + selector: "session-properties", + templateUrl: "./session-properties.component.html", + styleUrls: ["./session-properties.component.scss"] +}) +export class SessionPropertiesComponent implements /* AfterContentInit, AfterViewChecked, AfterViewInit, */ OnInit { + + public options: KatexOptions; + + constructor( + private intlService: I18nService, + private router: Router + ) { + this.options = { + displayMode: false, // true centers equations + throwOnError: false, + errorColor: "#cc0000" + }; + } + + public get content(): string { + return Session.getInstance().documentation; + } + + public set content(c: string) { + Session.getInstance().documentation = c; + } + + public get uitextTitle(): string { + return this.intlService.localizeText("INFO_SESSION_PROPERTIES_TITLE"); + } + + public get uitextPreview(): string { + return this.intlService.localizeText("INFO_SESSION_PROPERTIES_PREVIEW"); + } + + public get uitextEdit(): string { + return this.intlService.localizeText("INFO_SESSION_PROPERTIES_EDIT"); + } + + public ngOnInit() { + // if app is started on this page but session is empty, redirect to home page + if (! this.hasModules) { + this.router.navigate([ "/list" ]); + } + } + + /* public ngAfterViewInit(): void { + // add click listener on every calculator node in the graph, that + // corresponds to an open module + this.nativeElement.querySelectorAll("g.node").forEach(item => { + if (item.id && this.formIsOpen(item.id)) { + item.style.cursor = "pointer"; + item.addEventListener("click", () => { + this.openCalc(item.id); + }); + } + }); + } + + public ngAfterContentInit(): void { + this.error = false; + mermaid.initialize({ + // theme: "forest", // @TODO thème Irstea ! + flowchart: { + curve: "basis" + } + }); + this.nativeElement = this.diagram.nativeElement; + + if (this.hasModules) { + // generate graph description + const graphDefinition = this.graphDefinition(); + // draw + try { + mermaid.render("graphDiv", graphDefinition, (svgCode, bindFunctions) => { + this.nativeElement.innerHTML = svgCode; + }); + } catch (e) { + console.error(e); + this.error = true; + } + } + } */ + + public get hasModules(): boolean { + return Session.getInstance().getNumberOfNubs() > 0; + } + +} diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index d46b196a0e158bd6e1f2c10f8734e5533b04baa7..12a293a5d09a361f36b4750a2f1fa78bdac0fac2 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -312,6 +312,7 @@ "INFO_MENU_SAVE_SESSION_TITLE": "Save session", "INFO_MENU_SAVE_SETTINGS": "Save settings", "INFO_MENU_SELECT_CALC": "Select calculator module", + "INFO_MENU_SESSION_PROPS": "Session properties", "INFO_OPTION_ALL_F": "All", "INFO_OPTION_ALL": "All", "INFO_OPTION_CANCEL": "Cancel", @@ -423,6 +424,9 @@ "INFO_SETUP_RESTORE_DEFAULT_VALUES": "Restore default values", "INFO_SETUP_STORE_PREFERENCES": "Save preferences", "INFO_SETUP_TITLE": "Application setup", + "INFO_SESSION_PROPERTIES_EDIT": "Edit", + "INFO_SESSION_PROPERTIES_PREVIEW": "Documentation", + "INFO_SESSION_PROPERTIES_TITLE": "Session properties", "INFO_SNACKBAR_DEFAULT_SETTINGS_RESTORED": "Default settings restored", "INFO_SNACKBAR_RESULTS_CALCULATED": "Results calculated for", "INFO_SNACKBAR_RESULTS_INVALIDATED": "Results invalidated for", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index 92a77bf9c5055217b2bc34703262cae2ab5fab84..4b3184c188d21ae2e20ddd6841b675d9a7b7c0e9 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -311,6 +311,7 @@ "INFO_MENU_SAVE_SESSION_TITLE": "Enregistrer la session", "INFO_MENU_SAVE_SETTINGS": "Enregistrer les paramètres", "INFO_MENU_SELECT_CALC": "Choisir un module de calcul", + "INFO_MENU_SESSION_PROPS": "Propriétés de la session", "INFO_OPTION_ALL_F": "Toutes", "INFO_OPTION_ALL": "Tous", "INFO_OPTION_CANCEL": "Annuler", @@ -422,6 +423,9 @@ "INFO_SETUP_RESTORE_DEFAULT_VALUES": "Restaurer les valeurs par défaut", "INFO_SETUP_STORE_PREFERENCES": "Enregistrer les préférences", "INFO_SETUP_TITLE": "Paramètres de l'application", + "INFO_SESSION_PROPERTIES_EDIT": "Modifier", + "INFO_SESSION_PROPERTIES_PREVIEW": "Documentation", + "INFO_SESSION_PROPERTIES_TITLE": "Propriétés de la session", "INFO_SNACKBAR_DEFAULT_SETTINGS_RESTORED": "Paramètres par défaut restaurés", "INFO_SNACKBAR_RESULTS_CALCULATED": "Résultats calculés pour", "INFO_SNACKBAR_RESULTS_INVALIDATED": "Résultats invalidés pour",