Commit dab5996e authored by PECQUOT's avatar PECQUOT

Link with sumaris-lib

parent fa6c9ee1
......@@ -4,7 +4,7 @@
"extensions": {
"endpoints": {
"Default GraphQL Endpoint": {
"url": "http://desktop-enpp3sv:8080/graphql",
"url": "http://localhost:8080/graphql",
"headers": {
"user-agent": "JS GraphQL"
},
......
......@@ -101,7 +101,8 @@
"includePaths": [
"src/theme"
]
}
},
"preserveSymlinks": true
},
"configurations": {
"production": {
......
{
"name": "quadrige3-app",
"description": "Quadrige3Admin app",
"version": "1.5.3",
"version": "0.0.1",
"author": "contact@e-is.pro",
"license": "AGPL-3.0",
"readmeFilename": "README.md",
......@@ -21,21 +21,18 @@
},
"dependencies": {
"@angular/animations": "^11.0.2",
"@angular/cdk": "^11.0.0",
"@angular/cdk": "^11.0.1",
"@angular/common": "^11.0.2",
"@angular/core": "^11.0.2",
"@angular/forms": "^11.0.2",
"@angular/material": "^11.0.0",
"@angular/material-moment-adapter": "^11.0.0",
"@angular/material": "^11.0.1",
"@angular/material-moment-adapter": "^11.0.1",
"@angular/platform-browser": "^11.0.2",
"@angular/platform-browser-dynamic": "^11.0.2",
"@angular/router": "^11.0.2",
"@apollo/client": "^3.2.7",
"@apollo/link-error": "^2.0.0-beta.3",
"@apollo/link-retry": "^2.0.0-beta.3",
"@apollo/link-ws": "^2.0.0-beta.3",
"@asymmetrik/ngx-leaflet": "^7.0.1",
"@e-is/ngx-material-table": "0.10.2",
"@apollo/client": "^3.3.2",
"@asymmetrik/ngx-leaflet": "^8.1.0",
"@e-is/ngx-material-table": "0.11.1",
"@ionic-native/audio-management": "^5.29.0",
"@ionic-native/camera": "^5.29.0",
"@ionic-native/core": "^5.29.0",
......@@ -57,12 +54,11 @@
"@ngx-translate/http-loader": "^6.0.0",
"angular2-text-mask": "^9.0.0",
"apollo-angular": "^2.1.0",
"apollo-angular-link-http": "^1.11.0",
"apollo-cache-inmemory": "^1.6.6",
"apollo3-cache-persist": "^0.9.1",
"apollo-angular-link-http": "^2.0.0-alpha.6",
"apollo-link-logger": "^2.0.0",
"apollo-link-queue": "^3.0.0",
"apollo-link-serialize": "^3.1.1",
"apollo3-cache-persist": "^0.9.1",
"chart.js": "^2.9.4",
"clovelced-plugin-audiomanagement": "^1.0.2",
"core-js": "^3.6.5",
......@@ -71,10 +67,10 @@
"geojson": "^0.5.0",
"graphql": "^15.4.0",
"graphql-tag": "^2.11.0",
"hammerjs": "^2.0.8",
"hammer-timejs": "^1.1.0",
"hammerjs": "^2.0.8",
"ionic-cache": "^5.2.0",
"ionicons": "^5.1.2",
"ionicons": "^5.2.3",
"leaflet": "^1.6.0",
"localforage": "1.7.1",
"lodash.clonedeep": "^4.5.0",
......@@ -84,47 +80,40 @@
"ng2-charts": "^2.4.2",
"ng2-charts-schematics": "^0.1.7",
"ngx-color-picker": "^10.1.0",
"ngx-markdown": "^10.1.1",
"ngx-markdown": "^11.0.0",
"ngx-material-timepicker": "5.5.3",
"ngx-quicklink": "^0.2.4",
"roboto-fontface": "^0.10.0",
"rxjs": "^6.6.3",
"scrypt-async": "^2.0.1",
"seedrandom": "^3.0.5",
"subscriptions-transport-ws": "^0.9.16",
"sw-toolbox": "3.6.0",
"tslib": "^2.0.0",
"tslib": "^2.0.3",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1",
"uuid": "^3.3.3",
"zone.js": "~0.11.3"
},
"peerDependencies": {
"tar": "^5.0.5",
"rxjs": "^6.6.3"
"zone.js": "~0.10.3"
},
"devDependencies": {
"sumaris-lib": "file:/home/ludovic/dev/sumaris/sumaris-app/dist",
"@angular-devkit/build-angular": "~0.1100.2",
"@angular-devkit/build-webpack": "~0.1100.2",
"@angular/cli": "^11.0.2",
"@angular/compiler": "^11.0.2",
"@angular/compiler-cli": "^11.0.2",
"@angular/language-service": "^11.0.2",
"@ionic/angular-toolkit": "^3.0.0",
"@ionic/cli": "^6.12.2",
"@types/async": "^3.2.4",
"@types/jasmine": "^3.6.2",
"@types/jasminewd2": "^2.0.8",
"@types/jasmine": "~3.5.14",
"@types/jasminewd2": "~2.0.8",
"@types/leaflet": "^1.5.19",
"@types/node": "^12.19.6",
"@types/node": "^12.19.1",
"@types/uuid": "^3.4.9",
"acorn": "^7.3.1",
"codelyzer": "^6.0.0",
"rxjs": "^6.6.3",
"eslint": "^7.4.0",
"codelyzer": "^6.0.1",
"react": "^17.0.1",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.2",
"karma": "~5.2.1",
"karma": "~5.2.3",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1",
......@@ -135,7 +124,8 @@
"tar": "^5.0.5",
"ts-node": "^8.10.2",
"typescript": "~4.0.5",
"webpack": "^4.0.1"
"webpack": "^4.6.0",
"tslint": "^6.1.3"
},
"repository": {
"type": "git",
......
import {RouterModule, Routes} from "@angular/router";
import {UsersPage} from "./users/list/users";
import {AuthGuardService} from "../core/services/auth-guard.service";
import {NgModule} from "@angular/core";
import {ConfigurationPage} from "./config/configuration.page";
import {SharedRoutingModule} from "../shared/shared-routing.module";
import {AdminModule} from "./admin.module";
const routes: Routes = [
{
path: 'users',
pathMatch: 'full',
component: UsersPage,
canActivate: [AuthGuardService],
data: {
profile: 'ADMIN'
}
},
{
path: 'config',
pathMatch: 'full',
component: ConfigurationPage,
canActivate: [AuthGuardService],
data: {
profile: 'ADMIN'
}
}
];
@NgModule({
imports: [
SharedRoutingModule,
AdminModule,
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class AdminRoutingModule { }
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {CoreModule} from '../core/core.module';
import {PersonValidatorService} from './services/validator/person.validator';
import {UsersPage} from './users/list/users';
import {AdminRoutingModule} from "./admin-routing.module";
import {ReferentialModule} from "../referential/referential.module";
import {ConfigurationPage} from "./config/configuration.page";
import {SocialModule} from "../social/social.module";
@NgModule({
imports: [
CommonModule,
CoreModule,
SocialModule,
ReferentialModule
],
declarations: [
UsersPage,
ConfigurationPage
],
exports: [
UsersPage,
ConfigurationPage
]
})
export class AdminModule {
constructor() {
console.debug('[admin] Creating module');
}
}
<app-toolbar [title]="title$ | async" color="primary" [hasValidate]="!loading" (onValidate)="save($event)"
[canGoBack]="false">
<ion-spinner slot="end" *ngIf="loading"></ion-spinner>
</app-toolbar>
<ion-content>
<mat-tab-group #tabGroup
[(selectedIndex)]="selectedTabIndex"
(selectedTabChange)="onTabChange($event)"
[animationDuration]="tabGroupAnimationDuration"
dynamicHeight>
<!-- TAB: general -->
<mat-tab label="{{'CONFIGURATION.TAB_GENERAL'|translate}}">
<ng-template mat-tab-label>
<mat-icon>information-circle</mat-icon>
<ion-label translate>CONFIGURATION.TAB_GENERAL</ion-label>
<ion-icon slot="end" name="alert-circle" color="danger" *ngIf="submitted && referentialForm.invalid"></ion-icon>
</ng-template>
<div class="ion-padding">
<!-- error -->
<ion-item *ngIf="referentialForm.error || error" visible-xs visible-sm visible-mobile lines="none">
<ion-icon color="danger" slot="start" name="alert-circle"></ion-icon>
<ion-label color="danger" class="error"
[innerHTML]="(referentialForm.error || error) | translate"></ion-label>
</ion-item>
<ion-grid class="ion-no-padding">
<ion-row class="ion-no-padding">
<ion-col class="ion-no-padding ion-padding-top">
<!-- base form-->
<app-referential-form #referentialForm
[form]="form"
[showError]="false"
[debug]="debug"
(onSubmit)="save($event)">
<!-- properties divider-->
<h3>
<ion-text translate>CONFIGURATION.PROPERTIES_DIVIDER</ion-text>
</h3>
<!-- Properties -->
<form [formGroup]="form" class="form-container">
<ion-grid *ngIf="!loading || saving; else propertiesSkeleton"
formArrayName="properties" class="ion-no-padding">
<ion-row class="ion-no-padding">
<ion-col class="ion-no-padding ion-align-self-end" size="12">
<span class="toolbar-spacer"></span>
<!-- Show more options -->
<ion-button color="light" *ngIf="propertiesForm?.length === 0"
[title]="'CONFIGURATION.BTN_SHOW_MORE_HELP'|translate"
(click)="propertiesFormHelper.add()">
<ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>
<mat-icon slot="end">arrow_drop_down</mat-icon>
</ion-button>
</ion-col>
</ion-row>
<ng-container *ngFor="let propertyForm of propertiesForm?.controls; let i=index">
<ion-row class="ion-no-padding" [formGroupName]="i">
<!-- property key -->
<ion-col size="6" class="ion-no-padding">
<mat-form-field floatLabel="never">
<mat-select formControlName="key"
[placeholder]="'CONFIGURATION.PROPERTY_KEY'|translate"
(selectionChange)="updatePropertyDefinition(i)"
[tabindex]="20+i*2"
required>
<mat-option *ngFor="let item of propertyDefinitions"
[value]="item.key">{{ item.label | translate }}
</mat-option>
</mat-select>
<mat-error
*ngIf="propertyForm.controls.key.hasError('required') && !propertiesFormHelper.isLast(i)"
translate>ERROR.FIELD_REQUIRED
</mat-error>
</mat-form-field>
</ion-col>
<!-- property value -->
<ion-col class="ion-no-padding" padding-left>
<app-form-field *ngIf="getPropertyDefinition(i); let definition"
floatLabel="never"
[definition]="definition"
[formControl]="propertyForm.controls.value"
[placeholder]="'CONFIGURATION.PROPERTY_VALUE' | translate"
[required]="true"
[tabindex]="20+i*2 + 1">
</app-form-field>
</ion-col>
<ion-col size="auto" class="ion-no-padding">
<button type="button" mat-icon-button color="light"
[disabled]="loading"
[title]="'COMMON.BTN_DELETE'|translate"
(click)="removePropertyAt(i)">
<mat-icon>close</mat-icon>
</button>
<button [hidden]="!propertiesFormHelper.isLast(i)"
type="button"
mat-icon-button
color="light"
[disabled]="loading"
[title]="'CONFIGURATION.BTN_ADD_PROPERTY'|translate"
(click)="propertiesFormHelper.add()">
<mat-icon>add</mat-icon>
</button>
</ion-col>
</ion-row>
</ng-container>
</ion-grid>
</form>
<h3>
<ion-text translate>CONFIGURATION.PREVIEW_DIVIDER</ion-text>
</h3>
<!-- Home logos -->
<ng-container *ngIf="config?.smallLogo || config?.largeLogo">
<h4>
<ion-text translate>CONFIGURATION.LOGOS</ion-text>
</h4>
<ion-grid>
<ion-row>
<ion-col>
<img *ngIf="config?.smallLogo"
src="{{ config?.smallLogo }}" [title]="'CONFIGURATION.OPTIONS.LOGO'|translate"
width="110"/>
</ion-col>
<ion-col>
<img *ngIf="config?.largeLogo"
src="{{ config?.largeLogo }}" [title]="'CONFIGURATION.OPTIONS.HOME.LOGO_LARGE'|translate"
width="250"/>
</ion-col>
</ion-row>
</ion-grid>
</ng-container>
<h4>
<ion-text translate>CONFIGURATION.LOGO_PARTNERS</ion-text>
</h4>
<div class="bottom-banner">
<div class="partner-logo" *ngFor="let item of partners | async; let i = index ">
<img class="logo" src="{{ item.logo }}" alt="{{item.label}}" [title]="item.name" width="50"/>
<mat-icon class="button-close" (click)="removePartnerAt(i)">close</mat-icon>
</div>
</div>
</app-referential-form>
</ion-col>
<!-- entity metadata-->
<ion-col class="ion-no-padding" size="12" size-xl="3">
<app-entity-metadata [value]="data"></app-entity-metadata>
</ion-col>
</ion-row>
</ion-grid>
</div>
</mat-tab>
<!-- TAB: notifications -->
<mat-tab label="{{'CONFIGURATION.TAB_NOTIFICATIONS'|translate}}">
<ng-template mat-tab-label>
<mat-icon>
<ion-icon matPrefix slot="start" name="notifications"></ion-icon>
</mat-icon>
<ion-label translate>CONFIGURATION.TAB_NOTIFICATIONS</ion-label>
</ng-template>
<app-user-events-table recipient="SYSTEM"
withContent="true">
</app-user-events-table>
</mat-tab>
<!-- TAB: cache -->
<mat-tab label="{{'CONFIGURATION.TAB_CACHE'|translate}}">
<ng-template mat-tab-label>
<mat-icon>
<ion-icon matPrefix slot="start" name="stats-chart"></ion-icon>
</mat-icon>
<ion-label translate>CONFIGURATION.TAB_CACHE</ion-label>
</ng-template>
<mat-toolbar class="ion-no-padding">
<button mat-icon-button color="light" *ngIf="network.online" [title]="'COMMON.BTN_REFRESH'|translate"
(click)="loadCacheStat()">
<mat-icon>refresh</mat-icon>
</button>
<!-- title -->
<ion-text class="toolbar-spacer ion-text-center" >
<h3 translate>CONFIGURATION.CACHE_TITLE</h3>
</ion-text>
<button mat-icon-button *ngIf="enabled"
[matMenuTriggerFor]="optionsMenu"
[title]=" 'COMMON.BTN_OPTIONS'|translate">
<mat-icon>more_vert</mat-icon>
</button>
</mat-toolbar>
<!-- Type = options menu -->
<mat-menu #optionsMenu="matMenu" xPosition="after">
<button mat-menu-item *ngIf="network.online" (click)="clearCache($event)">
<ion-label translate>CONFIGURATION.BTN_CLEAR_CACHE</ion-label>
</button>
</mat-menu>
<div class="">
<ion-grid class="ion-no-padding cache">
<!-- header -->
<ion-row class="mat-header-row">
<ion-col size="12" size-lg="6" class="mat-header-cell">
<ion-label translate>CONFIGURATION.CACHE.NAME</ion-label>
</ion-col>
<ion-col class="mat-header-cell">
<ion-label translate>CONFIGURATION.CACHE.SIZE</ion-label>
</ion-col>
<ion-col class="mat-header-cell">
<ion-label translate>CONFIGURATION.CACHE.HEAP_SIZE</ion-label>
</ion-col>
<ion-col class="mat-header-cell">
<ion-label translate>CONFIGURATION.CACHE.OFF_HEAP_SIZE</ion-label>
</ion-col>
<ion-col class="mat-header-cell">
<ion-label translate>CONFIGURATION.CACHE.DISK_SIZE</ion-label>
</ion-col>
<ion-col size="1">
</ion-col>
</ion-row>
<!-- total -->
<ion-row *ngIf="cacheStatisticTotal | async as total" class="computed mat-row odd">
<ion-col size="12" size-lg="6">
<ion-label class="ion-text-wrap" translate>CONFIGURATION.CACHE.TOTAL</ion-label>
</ion-col>
<ion-col>
<ion-label>{{total.size}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{total.heapSize | fileSize}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{total.offHeapSize | fileSize}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{total.diskSize | fileSize}}</ion-label>
</ion-col>
<ion-col size="1">
</ion-col>
</ion-row>
<!-- details -->
<ion-row *ngFor="let stat of cacheStatistics | async; odd as odd"
class="mat-row"
[class.odd]="odd">
<ion-col size="12" size-lg="6">
<ion-label class="ion-text-wrap">{{stat.name}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{stat.size}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{stat.heapSize | fileSize}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{stat.offHeapSize | fileSize}}</ion-label>
</ion-col>
<ion-col>
<ion-label>{{stat.diskSize | fileSize}}</ion-label>
</ion-col>
<ion-col size="1">
<ion-button [title]="'COMMON.BTN_CLEAR'|translate"
fill="clear" color="medium"
(click)="clearCache($event, stat.name)">
<ion-icon slot="icon-only" name="trash"></ion-icon>
</ion-button>
</ion-col>
</ion-row>
</ion-grid>
</div>
</mat-tab>
</mat-tab-group>
</ion-content>
<ion-footer hidden-xs hidden-sm hidden-mobile>
<form-buttons-bar (onCancel)="cancel()" (onSave)="save($event)" [disabled]="!dirty || loading"
[disabledCancel]="!dirty || loading">
<!-- error -->
<ion-item *ngIf="error" lines="none">
<ion-icon color="danger" slot="start" name="alert-circle"></ion-icon>
<ion-label color="danger" [innerHTML]="error|translate"></ion-label>
</ion-item>
</form-buttons-bar>
</ion-footer>
<ng-template #propertiesSkeleton>
<ion-grid class="ion-no-padding">
<ng-container *ngTemplateOutlet="propertyRowSkeleton"></ng-container>
<ng-container *ngTemplateOutlet="propertyRowSkeleton"></ng-container>
<ng-container *ngTemplateOutlet="propertyRowSkeleton"></ng-container>
</ion-grid>
</ng-template>
<ng-template #propertyRowSkeleton>
<ion-row>
<!-- property key -->
<ion-col>
<mat-form-field>
<input matInput hidden>
<ion-skeleton-text animated style="width: 60%"></ion-skeleton-text>
<ion-icon name="arrow-dropdown" matSuffix></ion-icon>
</mat-form-field>
</ion-col>
<!-- value -->
<ion-col>
<mat-form-field>
<input matInput hidden>
<ion-skeleton-text animated style="width: 60%"></ion-skeleton-text>
</mat-form-field>
</ion-col>
<!-- buttons -->
<ion-col size="2">
<button type="button" mat-icon-button color="light"
[disabled]="true">
<mat-icon>close</mat-icon>