Compare commits
25 Commits
Author | SHA1 | Date |
---|---|---|
VANNEAU | a33f1ab1e2 | 1 year ago |
floxx2112 | 3d3b9a7a45 | 1 year ago |
floxx2112 | 10736d718a | 1 year ago |
floxx2112 | 0654581c2b | 1 year ago |
floxx2112 | 99791e3b2e | 1 year ago |
floxx2112 | cc47e34572 | 1 year ago |
floxx2112 | dc25dc6da9 | 2 years ago |
floxx2112 | be8f6fee51 | 2 years ago |
floxx2112 | 45c5f85a62 | 2 years ago |
floxx2112 | 5d2a682744 | 2 years ago |
floxx2112 | 2f4718886b | 2 years ago |
floxx2112 | c4de57ab5c | 2 years ago |
floxx2112 | fbee9b6857 | 2 years ago |
floxx2112 | 1eb347b5f8 | 2 years ago |
floxx2112 | 9571e2f4ff | 2 years ago |
fhibert | be40370cb2 | 2 years ago |
fhibert | d2939b5b57 | 2 years ago |
fhibert | 60f4b7cce6 | 2 years ago |
floxx2112 | 9952610b88 | 2 years ago |
floxx2112 | 2646b80461 | 2 years ago |
floxx2112 | b78d4dc5a4 | 2 years ago |
floxx2112 | 3a8c52ae76 | 2 years ago |
floxx2112 | b4ae128b86 | 2 years ago |
floxx2112 | 83ec591545 | 2 years ago |
floxx2112 | 489e3fa34c | 2 years ago |
@ -0,0 +1,16 @@ |
||||
# Editor configuration, see https://editorconfig.org |
||||
root = true |
||||
|
||||
[*] |
||||
charset = utf-8 |
||||
indent_style = space |
||||
indent_size = 2 |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
|
||||
[*.ts] |
||||
quote_type = single |
||||
|
||||
[*.md] |
||||
max_line_length = off |
||||
trim_trailing_whitespace = false |
@ -0,0 +1,42 @@ |
||||
# See http://help.github.com/ignore-files/ for more about ignoring files. |
||||
|
||||
# Compiled output |
||||
/dist |
||||
/tmp |
||||
/out-tsc |
||||
/bazel-out |
||||
|
||||
# Node |
||||
/node_modules |
||||
npm-debug.log |
||||
yarn-error.log |
||||
|
||||
# IDEs and editors |
||||
.idea/ |
||||
.project |
||||
.classpath |
||||
.c9/ |
||||
*.launch |
||||
.settings/ |
||||
*.sublime-workspace |
||||
|
||||
# Visual Studio Code |
||||
.vscode/* |
||||
!.vscode/settings.json |
||||
!.vscode/tasks.json |
||||
!.vscode/launch.json |
||||
!.vscode/extensions.json |
||||
.history/* |
||||
|
||||
# Miscellaneous |
||||
/.angular/cache |
||||
.sass-cache/ |
||||
/connect.lock |
||||
/coverage |
||||
/libpeerconnection.log |
||||
testem.log |
||||
/typings |
||||
|
||||
# System files |
||||
.DS_Store |
||||
Thumbs.db |
@ -0,0 +1,4 @@ |
||||
{ |
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 |
||||
"recommendations": ["angular.ng-template"] |
||||
} |
@ -0,0 +1,20 @@ |
||||
{ |
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
||||
"version": "0.2.0", |
||||
"configurations": [ |
||||
{ |
||||
"name": "ng serve", |
||||
"type": "pwa-chrome", |
||||
"request": "launch", |
||||
"preLaunchTask": "npm: start", |
||||
"url": "http://localhost:4200/" |
||||
}, |
||||
{ |
||||
"name": "ng test", |
||||
"type": "chrome", |
||||
"request": "launch", |
||||
"preLaunchTask": "npm: test", |
||||
"url": "http://localhost:9876/debug.html" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,42 @@ |
||||
{ |
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 |
||||
"version": "2.0.0", |
||||
"tasks": [ |
||||
{ |
||||
"type": "npm", |
||||
"script": "start", |
||||
"isBackground": true, |
||||
"problemMatcher": { |
||||
"owner": "typescript", |
||||
"pattern": "$tsc", |
||||
"background": { |
||||
"activeOnStart": true, |
||||
"beginsPattern": { |
||||
"regexp": "(.*?)" |
||||
}, |
||||
"endsPattern": { |
||||
"regexp": "bundle generation complete" |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
"type": "npm", |
||||
"script": "test", |
||||
"isBackground": true, |
||||
"problemMatcher": { |
||||
"owner": "typescript", |
||||
"pattern": "$tsc", |
||||
"background": { |
||||
"activeOnStart": true, |
||||
"beginsPattern": { |
||||
"regexp": "(.*?)" |
||||
}, |
||||
"endsPattern": { |
||||
"regexp": "bundle generation complete" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,27 @@ |
||||
## STEP 1 BUILD ## |
||||
FROM node:18-alpine AS build |
||||
|
||||
RUN mkdir -p /app |
||||
|
||||
WORKDIR /app |
||||
|
||||
RUN npm cache clean --force |
||||
|
||||
COPY package*.json /app |
||||
|
||||
RUN npm install |
||||
|
||||
COPY . /app |
||||
|
||||
RUN npm run build --prod |
||||
|
||||
## STEP 2 DEPLOY ## |
||||
FROM nginx:1.21.3 AS ngi |
||||
|
||||
COPY --from=build /app/dist/* /usr/share/nginx/html |
||||
COPY /nginx.conf /etc/nginx/conf.d/default.conf |
||||
# COPY /nginx.conf /etc/nginx/nginx.conf |
||||
|
||||
# EXPOSE 9002 |
||||
|
||||
CMD ["nginx", "-g", "daemon off;"] |
@ -0,0 +1,27 @@ |
||||
# AngularTest |
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.1.4. |
||||
|
||||
## Development server |
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. |
||||
|
||||
## Code scaffolding |
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. |
||||
|
||||
## Build |
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. |
||||
|
||||
## Running unit tests |
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). |
||||
|
||||
## Running end-to-end tests |
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. |
||||
|
||||
## Further help |
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. |
@ -0,0 +1,139 @@ |
||||
{ |
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", |
||||
"version": 1, |
||||
"newProjectRoot": "projects", |
||||
"projects": { |
||||
"angularTest": { |
||||
"projectType": "application", |
||||
"schematics": { |
||||
"@schematics/angular:component": { |
||||
"style": "scss", |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:class": { |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:directive": { |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:guard": { |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:interceptor": { |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:pipe": { |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:resolver": { |
||||
"skipTests": true |
||||
}, |
||||
"@schematics/angular:service": { |
||||
"skipTests": true |
||||
} |
||||
}, |
||||
"root": "", |
||||
"sourceRoot": "src", |
||||
"prefix": "app", |
||||
"architect": { |
||||
"build": { |
||||
"builder": "@angular-devkit/build-angular:browser", |
||||
"options": { |
||||
"outputPath": "dist/angular-test", |
||||
"index": "src/index.html", |
||||
"main": "src/main.ts", |
||||
"polyfills": [ |
||||
"zone.js" |
||||
], |
||||
"tsConfig": "tsconfig.app.json", |
||||
"inlineStyleLanguage": "scss", |
||||
"assets": [ |
||||
"src/favicon.ico", |
||||
"src/assets" |
||||
], |
||||
"styles": [ |
||||
"@angular/material/prebuilt-themes/deeppurple-amber.css", |
||||
"src/styles.scss" |
||||
], |
||||
"scripts": [] |
||||
}, |
||||
"configurations": { |
||||
"production": { |
||||
"budgets": [ |
||||
{ |
||||
"type": "initial", |
||||
"maximumWarning": "500kb", |
||||
"maximumError": "1mb" |
||||
}, |
||||
{ |
||||
"type": "anyComponentStyle", |
||||
"maximumWarning": "2kb", |
||||
"maximumError": "4kb" |
||||
} |
||||
], |
||||
"outputHashing": "all" |
||||
}, |
||||
"development": { |
||||
"buildOptimizer": false, |
||||
"optimization": false, |
||||
"vendorChunk": true, |
||||
"extractLicenses": false, |
||||
"sourceMap": true, |
||||
"namedChunks": true, |
||||
"fileReplacements": [ |
||||
{ |
||||
"replace": "src/environments/environment.ts", |
||||
"with": "src/environments/environment.development.ts" |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
"defaultConfiguration": "production" |
||||
}, |
||||
"serve": { |
||||
"builder": "@angular-devkit/build-angular:dev-server", |
||||
"configurations": { |
||||
"production": { |
||||
"browserTarget": "angularTest:build:production" |
||||
}, |
||||
"development": { |
||||
"browserTarget": "angularTest:build:development" |
||||
} |
||||
}, |
||||
"defaultConfiguration": "development", |
||||
"options": { |
||||
"port": 9002 |
||||
} |
||||
|
||||
|
||||
}, |
||||
"extract-i18n": { |
||||
"builder": "@angular-devkit/build-angular:extract-i18n", |
||||
"options": { |
||||
"browserTarget": "angularTest:build" |
||||
} |
||||
}, |
||||
"test": { |
||||
"builder": "@angular-devkit/build-angular:karma", |
||||
"options": { |
||||
"polyfills": [ |
||||
"zone.js", |
||||
"zone.js/testing" |
||||
], |
||||
"tsConfig": "tsconfig.spec.json", |
||||
"inlineStyleLanguage": "scss", |
||||
"assets": [ |
||||
"src/favicon.ico", |
||||
"src/assets" |
||||
], |
||||
"styles": [ |
||||
"@angular/material/prebuilt-themes/deeppurple-amber.css", |
||||
"src/styles.scss" |
||||
], |
||||
"scripts": [] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
upstream docker-web { |
||||
server 178.18.0.5:9001; |
||||
} |
||||
|
||||
server { |
||||
include /etc/nginx/extra-conf.d/*.conf; |
||||
|
||||
listen 80; |
||||
|
||||
include /etc/nginx/mime.types; |
||||
|
||||
location / { |
||||
root /usr/share/nginx/html; |
||||
try_files $uri $uri/ /index.html; |
||||
} |
||||
|
||||
|
||||
location /api/ { |
||||
proxy_pass http://docker-web; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,46 @@ |
||||
{ |
||||
"name": "angular-test", |
||||
"version": "0.0.0", |
||||
"scripts": { |
||||
"ng": "ng", |
||||
"start": "ng serve", |
||||
"build": "ng build", |
||||
"watch": "ng build --watch --configuration development", |
||||
"test": "ng test" |
||||
}, |
||||
"private": true, |
||||
"dependencies": { |
||||
"@angular/animations": "^15.1.0", |
||||
"@angular/cdk": "^15.1.4", |
||||
"@angular/common": "^15.1.0", |
||||
"@angular/compiler": "^15.1.0", |
||||
"@angular/core": "^15.1.0", |
||||
"@angular/forms": "^15.1.0", |
||||
"@angular/material": "^15.1.4", |
||||
"@angular/platform-browser": "^15.1.0", |
||||
"@angular/platform-browser-dynamic": "^15.1.0", |
||||
"@angular/router": "^15.1.0", |
||||
"@tailwindcss/forms": "^0.5.3", |
||||
"@tailwindcss/typography": "^0.5.9", |
||||
"ng-multiselect-dropdown": "^0.3.9", |
||||
"ng2-search-filter": "^0.5.1", |
||||
"ngx-dropzone": "^3.1.0", |
||||
"rxjs": "~7.8.0", |
||||
"tslib": "^2.3.0", |
||||
"zone.js": "~0.12.0" |
||||
}, |
||||
"devDependencies": { |
||||
"@angular-devkit/build-angular": "^15.1.4", |
||||
"@angular/cli": "~15.1.4", |
||||
"@angular/compiler-cli": "^15.1.0", |
||||
"@types/jasmine": "~4.3.0", |
||||
"jasmine-core": "~4.5.0", |
||||
"karma": "~6.4.0", |
||||
"karma-chrome-launcher": "~3.1.0", |
||||
"karma-coverage": "~2.2.0", |
||||
"karma-jasmine": "~5.1.0", |
||||
"karma-jasmine-html-reporter": "~2.0.0", |
||||
"tailwindcss": "^3.2.4", |
||||
"typescript": "~4.9.4" |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
{ |
||||
"/api/*": { |
||||
"target": "http://localhost:9002", |
||||
"secure": false, |
||||
"timeout": 600000 |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { RouterModule, Routes } from '@angular/router'; |
||||
import { LandingPageComponent } from './landing-page/landing-page.component'; |
||||
import { RequestPageComponent } from './search/request-page/request-page.component'; |
||||
import { JoinsPageComponent } from './joins/joins-page/joins-page.component'; |
||||
import { CreateJoinsPageComponent } from './creation/create-joins-page/create-joins-page.component'; |
||||
import { ScriptManagementComponent } from './manager/script-management/script-management.component'; |
||||
import { AddScriptComponent } from './manager/add-script/add-script.component'; |
||||
import { EditScriptComponent } from './manager/edit-script/edit-script.component'; |
||||
import { TagsManagementComponent } from './manager/tags-management/tags-management.component'; |
||||
|
||||
const routes: Routes = [ |
||||
{ path: '', component: LandingPageComponent }, |
||||
{ path: 'request', component: RequestPageComponent }, |
||||
{ path: 'joins', component: JoinsPageComponent }, |
||||
{ path: 'createjoins', component: CreateJoinsPageComponent }, |
||||
{ path: 'scriptmanagement', component: ScriptManagementComponent }, |
||||
{ path: 'addscript', component: AddScriptComponent}, |
||||
{ path: 'editscript', component: EditScriptComponent}, |
||||
{ path: 'tagsmanagement', component: TagsManagementComponent}, |
||||
{ path: '**', redirectTo: '', pathMatch: 'full'} |
||||
]; |
||||
|
||||
@NgModule({ |
||||
imports: [ |
||||
RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' }) |
||||
], |
||||
exports: [ |
||||
RouterModule |
||||
] |
||||
}) |
||||
export class AppRoutingModule {} |
@ -0,0 +1,6 @@ |
||||
<div> |
||||
<app-navbar></app-navbar> |
||||
<div class="mt-4 px-12"> |
||||
<router-outlet></router-outlet> |
||||
</div> |
||||
</div> |
@ -0,0 +1,10 @@ |
||||
import { Component } from '@angular/core'; |
||||
|
||||
@Component({ |
||||
selector: 'app-root', |
||||
templateUrl: './app.component.html', |
||||
styleUrls: ['./app.component.scss'] |
||||
}) |
||||
export class AppComponent { |
||||
|
||||
} |
@ -0,0 +1,79 @@ |
||||
|
||||
import { NgModule } from '@angular/core'; |
||||
import { BrowserModule } from '@angular/platform-browser'; |
||||
|
||||
import { AppComponent } from './app.component'; |
||||
import { AppRoutingModule } from './app-routing.module'; |
||||
import { LandingPageComponent } from './landing-page/landing-page.component'; |
||||
import { NavbarComponent } from './menu/navbar/navbar.component'; |
||||
import { RequestPageComponent } from './search/request-page/request-page.component'; |
||||
import { HttpClientModule } from '@angular/common/http'; |
||||
import { EmployeeService } from './service/employee.service'; |
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; |
||||
import { MatStepperModule } from '@angular/material/stepper'; |
||||
import { MatToolbarModule } from '@angular/material/toolbar'; |
||||
import {MatDialogModule} from '@angular/material/dialog'; |
||||
import { MatIconModule } from "@angular/material/icon"; |
||||
import { Custom_Ng2SearchPipe } from './custom-pipe/Custom_Ng2SearchPipe'; |
||||
import { FormsModule } from '@angular/forms'; |
||||
import { JoinsPageComponent } from './joins/joins-page/joins-page.component'; |
||||
import { CreateJoinsPageComponent } from './creation/create-joins-page/create-joins-page.component'; |
||||
import { JoinsTableComponent } from './creation/joins-table/joins-table.component'; |
||||
import { WhereCardComponent } from './creation/where-card/where-card.component'; |
||||
import { ColumnsCardComponent } from './creation/columns-card/columns-card.component'; |
||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; |
||||
import { ScriptManagementComponent } from './manager/script-management/script-management.component'; |
||||
import { AddScriptComponent } from './manager/add-script/add-script.component'; |
||||
import { DndDirective } from './directives/dnd.directive' |
||||
import { CustomFilterScript } from 'src/app/custom-pipe/CustomFilterScript'; |
||||
import { CustomFilterTable } from 'src/app/custom-pipe/CustomInfoTableSearchPipe'; |
||||
import { EditScriptComponent } from './manager/edit-script/edit-script.component'; |
||||
import { TagsManagementComponent } from './manager/tags-management/tags-management.component'; |
||||
import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown'; |
||||
import { CdkAccordionModule } from '@angular/cdk/accordion'; |
||||
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'; |
||||
import {MatTooltipModule} from '@angular/material/tooltip'; |
||||
|
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [ |
||||
AppComponent, |
||||
LandingPageComponent, |
||||
NavbarComponent, |
||||
RequestPageComponent, |
||||
Custom_Ng2SearchPipe, |
||||
CustomFilterScript, |
||||
CustomFilterTable, |
||||
JoinsPageComponent, |
||||
CreateJoinsPageComponent, |
||||
JoinsTableComponent, |
||||
WhereCardComponent, |
||||
ColumnsCardComponent, |
||||
ScriptManagementComponent, |
||||
AddScriptComponent, |
||||
DndDirective, |
||||
EditScriptComponent, |
||||
TagsManagementComponent, |
||||
], |
||||
imports: [ |
||||
BrowserModule, |
||||
AppRoutingModule, |
||||
HttpClientModule, |
||||
BrowserAnimationsModule, |
||||
MatStepperModule, |
||||
MatToolbarModule, |
||||
MatIconModule, |
||||
FormsModule, |
||||
MatDialogModule, |
||||
MatProgressSpinnerModule, |
||||
NgMultiSelectDropDownModule, |
||||
CdkAccordionModule, |
||||
ClipboardModule, |
||||
MatTooltipModule |
||||
|
||||
], |
||||
providers: [EmployeeService], |
||||
bootstrap: [AppComponent] |
||||
}) |
||||
export class AppModule { } |
@ -0,0 +1,19 @@ |
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 rounded-lg overflow-hidden shadow-lg bg-slate-300 border-solid border-orange-400 border-2 p-2"> |
||||
<div> |
||||
<label class="text-black text-left">Colonnes(Base) : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterBaseColumn" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="baseColumnData" (change)="sendColumnsData()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let col of baseColumns | filter : filterBaseColumn" id="{{ col.id }}" [ngValue]="col">{{ col.nameColumn }} ({{col.columnText}})</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Colonnes : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterSpecificColumn" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="specificColumnData" (change)="sendColumnsData()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let col of specificColumns | filter : filterSpecificColumn" id="{{ col.id }}" [ngValue]="col">{{ col.nameColumn }} ({{col.columnText}})</option> |
||||
</select> |
||||
</div> |
||||
</div> |
@ -0,0 +1,37 @@ |
||||
import { Component, EventEmitter, Input, Output } from '@angular/core'; |
||||
import { InfoColumn } from '../../model/info-column'; |
||||
import { ColumnData } from '../../model/column-data'; |
||||
|
||||
@Component({ |
||||
selector: 'app-columns-card', |
||||
templateUrl: './columns-card.component.html', |
||||
styleUrls: ['./columns-card.component.scss'] |
||||
}) |
||||
export class ColumnsCardComponent { |
||||
@Input() baseColumns: InfoColumn[] | undefined |
||||
@Input() specificColumns: InfoColumn[] | undefined |
||||
@Input() childIndex: number | undefined; |
||||
@Output() selectedColumn = new EventEmitter<ColumnData>(); |
||||
specificColumnData: InfoColumn | undefined; |
||||
baseColumnData: InfoColumn | undefined; |
||||
filterBaseColumn: string = ""; |
||||
filterSpecificColumn: string = ""; |
||||
|
||||
constructor(){} |
||||
|
||||
public sendColumnsData(){ |
||||
if(this.baseColumnData && this.specificColumnData){ |
||||
let tempsOpe = "AND"; |
||||
if(this.childIndex === 0){ |
||||
tempsOpe = "ON"; |
||||
} |
||||
const tempColumnData: ColumnData = { |
||||
operator: tempsOpe, |
||||
aliasColumn: this.baseColumnData.nameColumn, |
||||
specColumn: this.specificColumnData.nameColumn, |
||||
} |
||||
this.selectedColumn.emit(tempColumnData); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,74 @@ |
||||
|
||||
<!--Card--> |
||||
|
||||
<div class="flex sm:flex-nowrap flex-wrap sm:space-x-4 my-4"> |
||||
<div class="w-full sm:w-2/3 h-full text-center rounded-lg overflow-hidden shadow-lg bg-white p-4 "> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-slate-100 border-solid border-orange-400 border-2 p-4"> |
||||
|
||||
<div class="font-bold text-xl text-left">Selectionner un Schéma et une Table (Base) :</div> |
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> |
||||
<div class="mt-2"> |
||||
<label class="text-black text-left">Schémas : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterBaseSchema" placeholder="Rechercher..."> |
||||
|
||||
<select (change)="useTablesWithBaseSchema($event)" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let schema of allSchema | filter : filterBaseSchema" value="{{ schema }}">{{ schema }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div *ngIf="tablesByBaseSchema" class="mt-2"> |
||||
<label *ngIf="!isChecked" class="text-black text-left">Tables : </label> |
||||
<label *ngIf="isChecked" class="text-black text-left">Tables et Vues : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterBaseTables" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="baseTableData" (change)="getNameBaseTable()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let table of tablesByBaseSchema | filter : filterBaseTables" id="{{ table.id }}" [ngValue]="table">{{ table.nameTable }}</option> |
||||
</select> |
||||
</div> |
||||
</div> |
||||
|
||||
<div *ngIf="tablesByBaseSchema"> |
||||
<input type="checkbox" [(ngModel)]="isChecked" (change)="checkValue(isChecked?'true':'false')" class="w-4 h-4 text-orange-400 bg-slate-400 border-slate-200 rounded focus:ring-orange-400 focus:ring-2"/> |
||||
<label class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300">Afficher aussi les Vues</label> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<div *ngIf="baseTableName"> |
||||
<div *ngFor="let hop of requestInfoJoin; index as i" > |
||||
<app-joins-table [allAlias]="aliasData" [passJoinData]="allData[i]" (data)="retrieveData($event, i)" id="{{hop}}"></app-joins-table> |
||||
<div class="sm:inline-flex sm:space-x-4"> |
||||
<button (click)="addTable()" type="button" class="btn-grad-pink-orange mr-2 mb-2">Ajouter une Jointure</button> |
||||
|
||||
<button *ngIf="!oneJoinRemaining" (click)="removeTable(i)" type="button" class="btn-grad-red-yellow mr-2 mb-2">Supprimer cette jointure</button> |
||||
|
||||
<button (click)="addCondition()" type="button" class="btn-grad-green-blue mr-2 mb-2">Ajouter une Condition</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div *ngIf="whereCardList.length != 0"> |
||||
<div *ngFor="let whereCards of whereCardList; index as i" > |
||||
<app-where-card [allAlias]="aliasData" [childIndex]="i" id="{{whereCards}}" (conditionData)="getConditionData($event, i)"></app-where-card> |
||||
<div class="sm:inline-flex sm:space-x-4"> |
||||
<button (click)="addCondition()" type="button" class="btn-grad-green-blue mr-2 mb-2">Ajouter une Condition</button> |
||||
|
||||
<button (click)="removeWhereCard(i)" type="button" class="btn-grad-cyon-blue mr-2 mb-2">Supprimer cette Condition</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="sticky top-20 w-full mt-2 sm:mt-0 sm:w-1/3 h-full text-center rounded-lg overflow-hidden shadow-lg bg-white p-4 "> |
||||
<div class="flex justify-between mb-2"> |
||||
<div class="text-xl font-bold">Résultat de la requête :</div> |
||||
<mat-icon matTooltip="Copier la requête" [cdkCopyToClipboard]="newRequestData" class="text-green-400 ml-2 hover:cursor-pointer" svgIcon="copy"></mat-icon> |
||||
</div> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-slate-900 text-white text-left pl-2">{{newRequestData}} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
|
@ -0,0 +1,452 @@ |
||||
|
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { AfterViewInit, Component, OnInit, QueryList, ViewChildren } from '@angular/core'; |
||||
import { InfoTable } from '../../model/info-table'; |
||||
import { InfoColumnService } from '../../service/info-column.service'; |
||||
import { InfoTableService } from '../../service/info-table.service'; |
||||
import { JoinsTableComponent } from '../joins-table/joins-table.component'; |
||||
import { Join } from '../../model/join'; |
||||
import { Alias } from '../../model/alias'; |
||||
import { WhereCardComponent } from '../where-card/where-card.component'; |
||||
import { Condition } from '../../model/condition'; |
||||
import { ClipboardModule } from '@angular/cdk/clipboard'; |
||||
import { MatIconRegistry } from '@angular/material/icon'; |
||||
import { DomSanitizer } from '@angular/platform-browser'; |
||||
|
||||
@Component({ |
||||
selector: 'app-create-joins-page', |
||||
templateUrl: './create-joins-page.component.html', |
||||
styleUrls: ['./create-joins-page.component.scss'] |
||||
}) |
||||
export class CreateJoinsPageComponent implements OnInit, AfterViewInit{ |
||||
@ViewChildren(JoinsTableComponent)joinsTableComponent!: QueryList<JoinsTableComponent>; |
||||
@ViewChildren(WhereCardComponent)whereCardComponent!: QueryList<WhereCardComponent>; |
||||
|
||||
public allSchema: String[] | undefined; |
||||
filterBaseSchema: string = ""; |
||||
filterBaseTables: string = ""; |
||||
tablesByBaseSchema: InfoTable[] | undefined; |
||||
tablesByBaseSchemaAll: InfoTable[] | undefined; |
||||
tablesByBaseSchemaNoViews: InfoTable[] | undefined; |
||||
baseTableData: InfoTable | undefined; |
||||
isChecked: boolean = false; |
||||
requestInfoJoin: Array<JoinsTableComponent> = []; |
||||
whereCardList: Array<WhereCardComponent> = []; |
||||
baseTableName: string = ""; |
||||
baseTableNameLowerCase: String = ""; |
||||
oneJoinRemaining : boolean = true; |
||||
baseSchema: string | undefined; |
||||
displayJoins: boolean = false; |
||||
allData: Join[] = []; |
||||
aliasData: Alias[] = []; |
||||
selectedAlias: string = ""; |
||||
passSchema: string = ""; |
||||
passTable: string = ""; |
||||
baseAlias: Alias | undefined; |
||||
memoAlias: Alias | undefined; |
||||
conditionData: Condition[] = []; |
||||
newRequestData: string = "SELECT * FROM"; |
||||
|
||||
constructor( |
||||
private infoColumnService: InfoColumnService, |
||||
private infoTableService: InfoTableService, |
||||
private clipboard: ClipboardModule, |
||||
private matIconRegistry: MatIconRegistry, |
||||
private domSanitizer: DomSanitizer |
||||
){ |
||||
this.matIconRegistry.addSvgIcon('copy', this.domSanitizer.bypassSecurityTrustResourceUrl('../../assets/svg/copy.svg')) |
||||
|
||||
} |
||||
|
||||
ngAfterViewInit(): void { |
||||
} |
||||
|
||||
ngOnInit(): void { |
||||
this.getSchemas(); |
||||
this.requestInfoJoin.push(new JoinsTableComponent(this.infoColumnService, this.infoTableService)); |
||||
} |
||||
|
||||
public refreshRequestData(){ |
||||
this.newRequestData = "SELECT * FROM"; |
||||
this.newRequestData += ` ${this.baseSchema}.${this.baseTableName} AS ${this.baseTableNameLowerCase}`; |
||||
|
||||
for (let i = 0; i < this.allData.length; i++) { |
||||
const join: Join = this.allData[i]; |
||||
this.newRequestData += ` |
||||
${join.joinSpec} ${join.specificSchema}.${join.specificTable} AS ${join.aliasSpecificTable}`;
|
||||
|
||||
for (let j = 0; j < join.columns.length; j++) { |
||||
const allCol = join.columns[j]; |
||||
this.newRequestData += ` |
||||
${allCol.operator} ${join.baseAlias}.${allCol.aliasColumn}=${join.aliasSpecificTable}.${allCol.specColumn}`;
|
||||
} |
||||
} |
||||
|
||||
for (let i = 0; i < this.conditionData.length; i++) { |
||||
const cond: Condition = this.conditionData[i]; |
||||
this.newRequestData += ` |
||||
${cond.operator} ${cond.alias}.${cond.column} ${cond.condition} ${cond.value}`;
|
||||
} |
||||
} |
||||
|
||||
public getSchemas():void { |
||||
this.infoTableService.getSchemas().subscribe( |
||||
(response : String[]) => { |
||||
this.allSchema = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public useTablesWithBaseSchema (event: any){ |
||||
this.baseSchema = event.target.value; |
||||
this.infoTableService.getTablesBySchema(event.target.value).subscribe( |
||||
(response : InfoTable[]) => { |
||||
this.tablesByBaseSchemaAll = response; |
||||
this.divideTablesAndViews(); |
||||
this.refreshRequestData(); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
|
||||
} |
||||
|
||||
public divideTablesAndViews(){ |
||||
|
||||
if(this.tablesByBaseSchemaAll){ |
||||
this.tablesByBaseSchemaNoViews = []; |
||||
this.tablesByBaseSchemaAll.forEach((el, i) => { |
||||
if(el.nameTable.length < 5){ |
||||
this.tablesByBaseSchemaNoViews?.push(el); |
||||
} |
||||
}); |
||||
} |
||||
if(this.isChecked){ |
||||
this.tablesByBaseSchema = this.tablesByBaseSchemaAll; |
||||
} else { |
||||
this.tablesByBaseSchema = this.tablesByBaseSchemaNoViews; |
||||
} |
||||
} |
||||
|
||||
public getNameBaseTable(){ |
||||
let previousBaseAlias; |
||||
if(this.baseSchema && this.baseTableData){ |
||||
this.baseTableName = this.baseTableData.nameTable; |
||||
this.baseTableNameLowerCase = this.baseTableName?.toLowerCase(); |
||||
this.baseAlias = { |
||||
nameSchema: this.baseSchema, |
||||
nameTable: this.baseTableName, |
||||
nameAlias: this.baseTableNameLowerCase, |
||||
} |
||||
if(this.aliasData.length != 0){ |
||||
previousBaseAlias = this.aliasData[0].nameAlias; |
||||
for(let iz = this.allData.length; iz >= 0; iz--){ |
||||
if( this.allData[iz] && this.allData[iz].baseAlias == previousBaseAlias){ |
||||
this.allData.splice(iz, 1); |
||||
this.requestInfoJoin.splice(iz, 1); |
||||
this.aliasData.splice(iz, 1); |
||||
} |
||||
} |
||||
if(this.requestInfoJoin.length === 0 ){ |
||||
this.requestInfoJoin.push(new JoinsTableComponent(this.infoColumnService, this.infoTableService)); |
||||
} |
||||
} |
||||
this.aliasData.shift(); |
||||
this.aliasData.unshift(this.baseAlias); |
||||
} |
||||
this.refreshRequestData(); |
||||
} |
||||
|
||||
public addTable(){ |
||||
this.requestInfoJoin.push(new JoinsTableComponent(this.infoColumnService, this.infoTableService)); |
||||
this.checkLength(); |
||||
} |
||||
|
||||
public addCondition(){ |
||||
this.whereCardList.push(new WhereCardComponent(this.infoColumnService, this.infoTableService)); |
||||
} |
||||
|
||||
public checkAndRemoveIfAliasWasUse(previousAlias: String){ |
||||
for(let iz = this.allData.length; iz >= 0; iz--){ |
||||
if( this.allData[iz] && this.allData[iz].baseAlias == previousAlias){ |
||||
this.allData.splice(iz, 1); |
||||
this.requestInfoJoin.splice(iz, 1); |
||||
this.aliasData.splice(iz, 1); |
||||
} |
||||
} |
||||
if(this.conditionData.length != 0){ |
||||
for(let iy = this.conditionData.length; iy >= 0; iy--){ |
||||
if( this.conditionData[iy] && this.conditionData[iy].alias == previousAlias){ |
||||
this.conditionData.splice(iy, 1); |
||||
this.whereCardList.splice(iy, 1); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public removeTable(i: number){ |
||||
this.requestInfoJoin.splice(i, 1); |
||||
|
||||
if(this.allData[i]){ |
||||
const deleteAlias = this.allData[i].aliasSpecificTable; |
||||
let aliasSplitName = deleteAlias.slice(0, -1); |
||||
this.allData.splice(i, 1); |
||||
this.aliasData.shift(); |
||||
|
||||
this.checkAndRemoveIfAliasWasUse(deleteAlias); |
||||
|
||||
let indexOfHighest = -1; |
||||
let highestValue = 0; |
||||
let tempAlias; |
||||
let inInclude = false; |
||||
|
||||
if(this.allData.length === 0){ |
||||
this.requestInfoJoin.push(new JoinsTableComponent(this.infoColumnService, this.infoTableService)); |
||||
} else { |
||||
this.allData.forEach((join, ind) => { |
||||
const alias = join.aliasSpecificTable; |
||||
if(alias.includes(aliasSplitName.toString())){ |
||||
tempAlias = alias.slice(-1); |
||||
let numTempAlias = +tempAlias; |
||||
if(numTempAlias > highestValue){ |
||||
indexOfHighest = ind; |
||||
highestValue = numTempAlias; |
||||
} |
||||
inInclude = true; |
||||
} |
||||
}) |
||||
} |
||||
if(inInclude && highestValue != 0){ |
||||
this.allData[indexOfHighest].aliasSpecificTable = deleteAlias || ""; |
||||
this.aliasData.splice(i, 1); |
||||
this.aliasData[indexOfHighest].nameAlias = deleteAlias; |
||||
} else { |
||||
this.aliasData.splice(i, 1); |
||||
} |
||||
if(this.baseAlias){ |
||||
this.aliasData.unshift(this.baseAlias); |
||||
} |
||||
} |
||||
|
||||
this.checkLength(); |
||||
this.aliasData = [...this.aliasData] |
||||
this.refreshRequestData(); |
||||
} |
||||
|
||||
public checkLength(){ |
||||
console.log(this.requestInfoJoin.length); |
||||
if(this.requestInfoJoin.length > 1){ |
||||
this.oneJoinRemaining = false; |
||||
} else { |
||||
this.oneJoinRemaining = true; |
||||
} |
||||
} |
||||
|
||||
|
||||
public retrieveData(event: Join, index: number){ |
||||
const tempData = event; |
||||
if(this.allData.length != 0 && this.allData[index]){ |
||||
const antAlias = this.allData[index].aliasSpecificTable; |
||||
if(this.allData[index].aliasSpecificTable.includes(tempData.aliasSpecificTable.toString())){ |
||||
|
||||
} else { |
||||
this.checkAndRemoveIfAliasWasUse(antAlias); |
||||
} |
||||
} |
||||
|
||||
let switchData = ""; |
||||
let tempNum = ""; |
||||
let first = 0; |
||||
let tem = 0; |
||||
let tempAllData: Join[] = []; |
||||
let indexAliasData: Join[] = []; |
||||
let noIndexAliasData: Join[] = []; |
||||
let alias = ""; |
||||
let inInclude = false; |
||||
let indexOfHighest = -1; |
||||
let highestValue= -1; |
||||
let tempAlias; |
||||
tempAllData = [...this.allData]; |
||||
|
||||
if(this.allData.length === 0){ |
||||
switchData = "emptyData"; |
||||
} else { |
||||
if(this.allData[index]){ |
||||
if(this.allData.length != 1){ |
||||
tempAllData.splice(index, 1); |
||||
} |
||||
tempAllData.forEach((join, i) => { |
||||
alias = join.aliasSpecificTable.toString(); |
||||
if(alias.includes(tempData.aliasSpecificTable.toString())){ |
||||
indexAliasData.push(tempAllData[i]); |
||||
switchData = "indexAlias"; |
||||
first = 1; |
||||
} else { |
||||
if(first === 0){ |
||||
switchData = "indexNoAlias"; |
||||
} |
||||
} |
||||
}) |
||||
} else { |
||||
this.allData.forEach((join, i) => { |
||||
alias = join.aliasSpecificTable.toString(); |
||||
if(alias.includes(tempData.aliasSpecificTable.toString())){ |
||||
noIndexAliasData.push(tempAllData[i]); |
||||
switchData = "noIndexAlias"; |
||||
first = 1 |
||||
} else { |
||||
if(first === 0){ |
||||
switchData = "noIndexNoAlias"; |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
switch (switchData) { |
||||
case "emptyData": |
||||
tempData.aliasSpecificTable = tempData.aliasSpecificTable + "0"; |
||||
this.allData.push(tempData); |
||||
break; |
||||
|
||||
case "indexAlias": |
||||
let memo = 0; |
||||
const rememberAlias = this.allData[index].aliasSpecificTable; |
||||
const aliasSplitName = rememberAlias.slice(0, -1); |
||||
if(this.allData[index].aliasSpecificTable == tempData.aliasSpecificTable+"0"){ |
||||
tempNum = "0" |
||||
} |
||||
else { |
||||
indexAliasData.forEach((jo) => { |
||||
const indexAliasName = jo.aliasSpecificTable; |
||||
for(let num = 8; num > -1; num--){ |
||||
if(indexAliasName == (tempData.aliasSpecificTable+num.toString())){ |
||||
tem = +num + +1; |
||||
if(memo < tem){ |
||||
memo = tem; |
||||
tempNum = memo.toString(); |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
this.allData.forEach((join, ind) => { |
||||
const aliasRem = join.aliasSpecificTable; |
||||
if(aliasRem.includes(aliasSplitName.toString())){ |
||||
tempAlias = aliasRem.slice(-1); |
||||
let numTempAlias = +tempAlias; |
||||
if(numTempAlias > highestValue){ |
||||
indexOfHighest = ind; |
||||
highestValue = numTempAlias; |
||||
} |
||||
inInclude = true; |
||||
} |
||||
}) |
||||
} |
||||
|
||||
if(inInclude && highestValue != 0){ |
||||
this.allData[indexOfHighest].aliasSpecificTable = rememberAlias || ""; |
||||
} |
||||
this.allData[index] = tempData; |
||||
this.allData[index].aliasSpecificTable = tempData.aliasSpecificTable + tempNum; |
||||
break; |
||||
|
||||
case "indexNoAlias": |
||||
const rememberIndexAlias = this.allData[index].aliasSpecificTable; |
||||
const indexAliasSplitName = rememberIndexAlias.slice(0, -1); |
||||
this.allData.forEach((join, ind) => { |
||||
const aliasRem = join.aliasSpecificTable; |
||||
if(aliasRem.includes(indexAliasSplitName.toString())){ |
||||
tempAlias = aliasRem.slice(-1); |
||||
let numTempAlias = +tempAlias; |
||||
if(numTempAlias > highestValue){ |
||||
indexOfHighest = ind; |
||||
highestValue = numTempAlias; |
||||
} |
||||
inInclude = true; |
||||
} |
||||
}) |
||||
if(inInclude && highestValue != 0){ |
||||
this.allData[indexOfHighest].aliasSpecificTable = rememberIndexAlias || ""; |
||||
} |
||||
this.allData[index] = tempData; |
||||
this.allData[index].aliasSpecificTable = tempData.aliasSpecificTable + "0"; |
||||
break; |
||||
|
||||
case "noIndexAlias": |
||||
let memRem = 0; |
||||
noIndexAliasData.forEach((jo) => { |
||||
const indexAliasName = jo.aliasSpecificTable; |
||||
for(let num = 8; num > -1; num--){ |
||||
if(indexAliasName == (tempData.aliasSpecificTable+num.toString())){ |
||||
tem = +num + +1; |
||||
if(memRem < tem){ |
||||
memRem = tem; |
||||
tempNum = memRem.toString(); |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
tempData.aliasSpecificTable = tempData.aliasSpecificTable + tempNum; |
||||
this.allData.push(tempData); |
||||
break; |
||||
|
||||
case "noIndexNoAlias": |
||||
tempData.aliasSpecificTable = tempData.aliasSpecificTable + "0"; |
||||
this.allData.push(tempData); |
||||
break; |
||||
} |
||||
this.allData = [...this.allData] |
||||
|
||||
if(this.baseAlias){ |
||||
this.aliasData.splice(0); |
||||
this.aliasData.push(this.baseAlias) |
||||
this.allData.forEach((all) => { |
||||
const ephAlias: Alias = { |
||||
nameSchema: all.specificSchema, |
||||
nameTable: all.specificTable, |
||||
nameAlias: all.aliasSpecificTable |
||||
} |
||||
this.aliasData.push(ephAlias); |
||||
}); |
||||
} |
||||
this.aliasData = [...this.aliasData]; |
||||
this.refreshRequestData(); |
||||
} |
||||
|
||||
public removeWhereCard(i: number){ |
||||
this.whereCardList.splice(i, 1); |
||||
if(this.conditionData[i]){ |
||||
this.conditionData.splice(i, 1); |
||||
} |
||||
if(this.conditionData[0]){ |
||||
this.conditionData[0].operator = "WHERE"; |
||||
} |
||||
this.refreshRequestData(); |
||||
} |
||||
|
||||
public getConditionData(event: String[], index: number){ |
||||
const tempCondition: Condition = { |
||||
operator: event[0], |
||||
alias: event[1], |
||||
column: event[2], |
||||
condition: event[3], |
||||
value: event[4] |
||||
} |
||||
if(this.conditionData[index]){ |
||||
this.conditionData[index] = tempCondition; |
||||
} else { |
||||
this.conditionData.push(tempCondition); |
||||
} |
||||
this.refreshRequestData(); |
||||
} |
||||
|
||||
public checkValue(event: any){ |
||||
this.tablesByBaseSchema = this.isChecked ? |
||||
this.tablesByBaseSchemaAll |
||||
: this.tablesByBaseSchemaNoViews; |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
<div [ngClass]="{'normalCard' : goodAlias, 'alternativeCard' : !goodAlias}" class="p-4"> |
||||
<div class="font-bold text-xl text-left mb-2">Selectionner les informations de la jointure :</div> |
||||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4"> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Jointures : </label> |
||||
<select [(ngModel)]="joinData" (change)="verifyAndSendData()" size="4" class="my-2 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let join of alljoins" [ngValue]="join">{{ join }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Schémas : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterBaseSchema" placeholder="Rechercher..."> |
||||
|
||||
<select (change)="useTablesWithSpecificSchema($event)" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let schema of allSchema | filter : filterBaseSchema" value="{{ schema }}">{{ schema }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Tables : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterBaseTables" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="specificTableData" (change)="getSpecificColumns()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let table of tablesByBaseSchema | filter : filterBaseTables" id="{{ table.id }}" [ngValue]="table">{{ table.nameTable }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div *ngIf="allAlias"> |
||||
<label class="text-black text-left">Alias(Base) : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterAlias" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="baseAlias" (change)="getBaseColumns()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let alias of tempAliasData | filter : filterAlias" [ngValue]="alias">{{ alias.nameAlias }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<div *ngIf="tablesByBaseSchema" class="mb-2"> |
||||
<input type="checkbox" [(ngModel)]="isChecked" (change)="checkValue(isChecked?'true':'false')" class="w-4 h-4 text-orange-400 bg-slate-400 border-slate-200 rounded focus:ring-orange-400 focus:ring-2"/> |
||||
<label class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300">Afficher aussi les Vues</label> |
||||
</div> |
||||
|
||||
<div *ngFor="let cols of columnsInfo, index as ind"> |
||||
<app-columns-card [baseColumns]="baseColumns" [specificColumns]="specificColumns" [childIndex]="ind" (selectedColumn)="retrieveColumnsData($event, ind)"></app-columns-card> |
||||
|
||||
<div class="inline-flex space-x-4"> |
||||
<button (click)="addSelectColumns()" type="button" class="btn-grad-green-teal mr-2 my-2">+</button> |
||||
|
||||
<button *ngIf="columnsInfo.length > 1" (click)="removeSelectColumns(ind)" type="button" class="btn-grad-red-rose my-2">-</button> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,25 @@ |
||||
// rounded-lg overflow-hidden shadow-lg bg-slate-100 border-solid border-orange-400 border-2 my-2 |
||||
|
||||
.normalCard { |
||||
border-radius: 0.5rem; |
||||
overflow: hidden; |
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); |
||||
background-color: rgb(241 245 249); |
||||
border-style: solid; |
||||
border-color: rgb(251 146 60); |
||||
border-width: 2px; |
||||
margin-top: 0.5rem; /* 8px */ |
||||
margin-bottom: 0.5rem; /* 8px */ |
||||
} |
||||
|
||||
.alternativeCard { |
||||
border-radius: 0.5rem; |
||||
overflow: hidden; |
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); |
||||
background-color: rgb(71 85 105); |
||||
border-style: solid; |
||||
border-color: rgb(251 146 60); |
||||
border-width: 2px; |
||||
margin-top: 0.5rem; /* 8px */ |
||||
margin-bottom: 0.5rem; /* 8px */ |
||||
} |
@ -0,0 +1,198 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, QueryList, ViewChildren } from '@angular/core'; |
||||
import { InfoColumn } from '../../model/info-column'; |
||||
import { InfoTable } from '../../model/info-table'; |
||||
import { InfoColumnService } from '../../service/info-column.service'; |
||||
import { InfoTableService } from '../../service/info-table.service'; |
||||
import { Alias } from '../../model/alias'; |
||||
import { Join } from '../../model/join'; |
||||
import { ColumnData } from '../../model/column-data'; |
||||
import { ColumnsCardComponent } from '../columns-card/columns-card.component'; |
||||
|
||||
@Component({ |
||||
selector: 'app-joins-table', |
||||
templateUrl: './joins-table.component.html', |
||||
styleUrls: ['./joins-table.component.scss'] |
||||
}) |
||||
export class JoinsTableComponent implements OnInit, OnChanges{ |
||||
@ViewChildren(ColumnsCardComponent)joinsColumnsComponent!: QueryList<ColumnsCardComponent>; |
||||
@Input() allAlias: Alias[] = []; |
||||
@Input() passJoinData: Join | undefined; |
||||
@Output() data = new EventEmitter<Join>(); |
||||
@Output() selectedAlias = new EventEmitter<String>(); |
||||
public allSchema: String[] | undefined; |
||||
filterBaseSchema: string = ""; |
||||
filterBaseTables: string = ""; |
||||
isChecked: boolean = false; |
||||
filterAlias: string = ""; |
||||
specificTableData: InfoTable | undefined; |
||||
tablesByBaseSchema: InfoTable[] | undefined; |
||||
tablesByBaseSchemaAll: InfoTable[] | undefined; |
||||
tablesByBaseSchemaNoViews: InfoTable[] | undefined; |
||||
joinData: string | undefined; |
||||
alljoins: string[] = ['INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'FULL JOIN']; |
||||
selectedSchema: string | undefined; |
||||
columnsForSpecificTable: InfoColumn[] | undefined; |
||||
baseColumns: InfoColumn[] | undefined; |
||||
specificColumns: InfoColumn[] | undefined; |
||||
specificSchema: string | undefined; |
||||
specificTable: string | undefined; |
||||
baseAlias: Alias | undefined; |
||||
myJoinData: Join | undefined; |
||||
isGood: boolean = true; |
||||
positionIndex: number = 0; |
||||
tempAliasData: Alias[] = []; |
||||
goodAlias = true; |
||||
columnsInfo: Array<ColumnsCardComponent> = []; |
||||
columnsData: ColumnData[] = []; |
||||
|
||||
constructor( |
||||
private infoColumnService: InfoColumnService, |
||||
private infoTableService: InfoTableService |
||||
){} |
||||
|
||||
ngOnInit(): void { |
||||
this.getSchemas(); |
||||
this.getBaseColumns(); |
||||
this.columnsInfo.push(new ColumnsCardComponent()); |
||||
} |
||||
|
||||
ngOnChanges(): void { |
||||
this.getBaseColumns(); |
||||
this.verifyAlias(); |
||||
} |
||||
|
||||
public verifyAlias(){ |
||||
this.tempAliasData = this.allAlias; |
||||
if(this.passJoinData){ |
||||
this.tempAliasData = []; |
||||
const myAlias = this.passJoinData.aliasSpecificTable; |
||||
this.allAlias.forEach((alias, i) =>{ |
||||
if(alias.nameAlias !== myAlias){ |
||||
this.tempAliasData.push(alias); |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
public getSchemas():void { |
||||
this.infoTableService.getSchemas().subscribe( |
||||
(response : String[]) => { |
||||
this.allSchema = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public useTablesWithSpecificSchema (event: any){ |
||||
this.specificSchema = event.target.value; |
||||
this.infoTableService.getTablesBySchema(event.target.value).subscribe( |
||||
(response : InfoTable[]) => { |
||||
this.tablesByBaseSchemaAll = response; |
||||
this.divideTablesAndViews(); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public divideTablesAndViews(){ |
||||
if(this.tablesByBaseSchemaAll){ |
||||
this.tablesByBaseSchemaNoViews = []; |
||||
this.tablesByBaseSchemaAll.forEach((el, i) => { |
||||
if(el.nameTable.length < 5){ |
||||
this.tablesByBaseSchemaNoViews?.push(el); |
||||
} |
||||
}); |
||||
} |
||||
if(this.isChecked){ |
||||
this.tablesByBaseSchema = this.tablesByBaseSchemaAll; |
||||
} else { |
||||
this.tablesByBaseSchema = this.tablesByBaseSchemaNoViews; |
||||
} |
||||
} |
||||
|
||||
public getBaseColumns():void { |
||||
if(this.baseAlias){ |
||||
this.infoColumnService.getSelectedColumns(this.baseAlias.nameSchema, this.baseAlias.nameTable).subscribe( |
||||
(response : InfoColumn[]) => { |
||||
this.baseColumns = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
public getSpecificColumns():void { |
||||
if(this.specificTableData) |
||||
this.specificTable = this.specificTableData.nameTable; |
||||
if(this.specificSchema && this.specificTable){ |
||||
this.infoColumnService.getSelectedColumns(this.specificSchema, this.specificTable).subscribe( |
||||
(response : InfoColumn[]) => { |
||||
this.specificColumns = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
public verifyAndSendData(){ |
||||
if(this.specificSchema && this.specificTable && this.joinData && this.baseAlias && this.columnsData){ |
||||
const tempLower = this.specificTable.toLowerCase(); |
||||
this.myJoinData = { |
||||
joinSpec: this.joinData, |
||||
specificSchema: this.specificSchema, |
||||
specificTable: this.specificTable, |
||||
baseAlias: this.baseAlias.nameAlias, |
||||
columns: this.columnsData, |
||||
aliasSpecificTable: tempLower, |
||||
} |
||||
this.data.emit(this.myJoinData); |
||||
} |
||||
} |
||||
|
||||
public addSelectColumns(){ |
||||
this.columnsInfo.push(new ColumnsCardComponent()); |
||||
|
||||
} |
||||
|
||||
public removeSelectColumns(index: number){ |
||||
this.columnsInfo.splice(index, 1) |
||||
if(this.columnsData[index]){ |
||||
this.columnsData.splice(index, 1); |
||||
} |
||||
if(this.columnsData[0]){ |
||||
this.columnsData[0].operator = "ON"; |
||||
} |
||||
this.verifyAndSendData() |
||||
} |
||||
|
||||
public retrieveColumnsData(data: ColumnData, index: number){ |
||||
if(this.columnsData.length === 0){ |
||||
this.columnsData.push(data); |
||||
} |
||||
if(this.columnsData[index]){ |
||||
this.columnsData[index] = data; |
||||
} else { |
||||
this.columnsData.push(data); |
||||
} |
||||
|
||||
this.verifyAndSendData(); |
||||
} |
||||
|
||||
public checkValue(event: any){ |
||||
if(this.isChecked){ |
||||
this.tablesByBaseSchema = this.tablesByBaseSchemaAll; |
||||
} else { |
||||
this.tablesByBaseSchema = this.tablesByBaseSchemaNoViews; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@ |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-slate-100 border-solid border-orange-400 border-2 my-2 p-4"> |
||||
<div class="font-bold text-xl text-left mb-2">Selectionner les informations de la Condition :</div> |
||||
<div class="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-5 gap-4"> |
||||
|
||||
<div *ngIf="childIndex != 0"> |
||||
<label class="text-black text-left">Opérateurs : </label> |
||||
<select [(ngModel)]="operator" (change)="verifyAndSendConditionData()" size="4" class="my-2 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let ope of operatorList" [ngValue]="ope">{{ ope }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Alias : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterAlias" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="baseAlias" (change)="getColumns()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let alias of allAlias | filter : filterAlias" [ngValue]="alias">{{ alias.nameAlias }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Colonnes : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterColumn" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="baseColumnData" (change)="verifyAndSendConditionData()" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let col of baseColumns | filter : filterColumn" id="{{ col.id }}" [ngValue]="col">{{ col.nameColumn }} ({{col.columnText}})</option> |
||||
</select> |
||||
</div> |
||||
|
||||
<div *ngIf="allAlias"> |
||||
<label class="text-black text-left">Conditions : </label> |
||||
<input type="text" (change)="verifyAndSendConditionData()" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="conditionOperator" placeholder="Condition..."> |
||||
</div> |
||||
|
||||
<div> |
||||
<label class="text-black text-left">Valeurs : </label> |
||||
<input type="text" (change)="verifyAndSendConditionData()" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="conditionValue" placeholder="Valeur..."> |
||||
</div> |
||||
|
||||
</div> |
||||
</div> |
@ -0,0 +1,54 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Component, EventEmitter, Input, Output } from '@angular/core'; |
||||
import { Alias } from '../../model/alias'; |
||||
import { InfoColumn } from '../../model/info-column'; |
||||
import { InfoColumnService } from '../../service/info-column.service'; |
||||
import { InfoTableService } from '../../service/info-table.service'; |
||||
|
||||
@Component({ |
||||
selector: 'app-where-card', |
||||
templateUrl: './where-card.component.html', |
||||
styleUrls: ['./where-card.component.scss'] |
||||
}) |
||||
export class WhereCardComponent { |
||||
@Input() allAlias: Alias[] = []; |
||||
@Input() childIndex: number | undefined; |
||||
@Output() conditionData = new EventEmitter<String[]>(); |
||||
|
||||
operator: string | undefined; |
||||
operatorList: string[] = ["AND", "OR"]; |
||||
conditionValue: any; |
||||
conditionOperator: any; |
||||
filterAlias: string = ""; |
||||
filterColumn: string = ""; |
||||
baseAlias: Alias | undefined; |
||||
baseColumns: InfoColumn[] | undefined; |
||||
baseColumnData: InfoColumn | undefined; |
||||
|
||||
constructor( |
||||
private infoColumnService: InfoColumnService, |
||||
private infoTableService: InfoTableService |
||||
){} |
||||
|
||||
public getColumns():void { |
||||
if(this.baseAlias){ |
||||
this.infoColumnService.getSelectedColumns(this.baseAlias.nameSchema, this.baseAlias.nameTable).subscribe( |
||||
(response : InfoColumn[]) => { |
||||
this.baseColumns = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
public verifyAndSendConditionData(){ |
||||
if(this.childIndex === 0){ |
||||
this.operator = "WHERE"; |
||||
} |
||||
if(this.operator && this.baseAlias && this.baseColumnData && this.conditionOperator && this.conditionValue){ |
||||
this.conditionData.emit([this.operator, this.baseAlias.nameAlias, this.baseColumnData.nameColumn, this.conditionOperator, this.conditionValue]); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
import { Pipe, PipeTransform } from '@angular/core'; |
||||
import { Script } from '../model/script'; |
||||
|
||||
@Pipe({ |
||||
name: 'filterscript', |
||||
pure: false |
||||
}) |
||||
export class CustomFilterScript implements PipeTransform { |
||||
transform(items: Script[], filter: string): any { |
||||
if (!items || !filter) { |
||||
return items; |
||||
} |
||||
// filter items array, items which match and return true will be
|
||||
// kept, false will be filtered out
|
||||
if(filter){ |
||||
return items.filter(item => item.name.toLowerCase().indexOf(filter) !== -1); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
import { InfoTable } from '../model/info-table'; |
||||
import { Pipe, PipeTransform } from '@angular/core'; |
||||
|
||||
|
||||
@Pipe({ |
||||
name: 'filtertable', |
||||
pure: false |
||||
}) |
||||
export class CustomFilterTable implements PipeTransform { |
||||
transform(items: InfoTable[], filter: string): any { |
||||
if (!items || !filter) { |
||||
return items; |
||||
} |
||||
|
||||
// Filter items array, keeping items that match the filter
|
||||
const filteredItems = items.filter(item => item.nameTable.toLowerCase().indexOf(filter.toLowerCase()) !== -1); |
||||
|
||||
// Sort the filtered items by the length of the text in ascending order
|
||||
const sortedItems = filteredItems.sort((a, b) => { |
||||
if (a.nameTable.length < b.nameTable.length) { |
||||
return -1; |
||||
} else if (a.nameTable.length > b.nameTable.length) { |
||||
return 1; |
||||
} else { |
||||
return 0; |
||||
} |
||||
}); |
||||
|
||||
return sortedItems; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,62 @@ |
||||
import { Pipe, PipeTransform, Injectable } from "@angular/core"; |
||||
|
||||
@Pipe({ |
||||
name: "filter", |
||||
pure: false |
||||
}) |
||||
@Injectable() |
||||
export class Custom_Ng2SearchPipe implements PipeTransform { |
||||
|
||||
transform(items: any, term: string, excludes: any = []): any { |
||||
if (!term || !items) return items; |
||||
return Custom_Ng2SearchPipe.filter(items, term, excludes); |
||||
} |
||||
|
||||
static filter( |
||||
items: Array<{ [key: string]: any }>, |
||||
term: string, |
||||
excludes: any |
||||
): Array<{ [key: string]: any }> { |
||||
const toCompare = term.toLowerCase(); |
||||
|
||||
function checkInside(item: any, term: string) { |
||||
if ( |
||||
typeof item === "string" && |
||||
item |
||||
.toString() |
||||
.toLowerCase() |
||||
.includes(toCompare) |
||||
) { |
||||
return true; |
||||
} |
||||
|
||||
for (let property in item) { |
||||
if ( |
||||
item[property] === null || |
||||
item[property] == undefined || |
||||
excludes.includes(property) |
||||
) { |
||||
continue; |
||||
} |
||||
|
||||
if (typeof item[property] === "object") { |
||||
if (checkInside(item[property], term)) { |
||||
return true; |
||||
} |
||||
} else if ( |
||||
item[property] |
||||
.toString() |
||||
.toLowerCase() |
||||
.includes(toCompare) |
||||
) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
return items.filter(function (item) { |
||||
return checkInside(item, term); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
import { Directive, EventEmitter, HostBinding, HostListener, Output } from '@angular/core'; |
||||
|
||||
@Directive({ |
||||
selector: '[appDnd]' |
||||
}) |
||||
export class DndDirective { |
||||
@HostBinding('class.animate-pulse') fileOver: boolean | undefined; |
||||
@Output() fileDropped = new EventEmitter<any>(); |
||||
@Output() textDrop = new EventEmitter<string[]>(); |
||||
listOfContent: string[] = []; |
||||
|
||||
// Dragover listener
|
||||
@HostListener('dragover', ['$event']) onDragOver(evt: any) { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
this.fileOver = true; |
||||
} |
||||
|
||||
// Dragleave listener
|
||||
@HostListener('dragleave', ['$event']) public onDragLeave(evt: any) { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
this.fileOver = false; |
||||
} |
||||
|
||||
// Drop listener
|
||||
@HostListener('drop', ['$event']) public ondrop(evt: any) { |
||||
evt.preventDefault(); |
||||
evt.stopPropagation(); |
||||
this.fileOver = false; |
||||
let files = evt.dataTransfer.files; |
||||
if (files.length > 0) { |
||||
this.fileDropped.emit(files); |
||||
|
||||
} |
||||
} |
||||
|
||||
constructor(){ |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,141 @@ |
||||
<div class="my-4 grid sm:grid-cols-1 md:grid-cols-2 gap-5"> |
||||
<!--Card--> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 py-4"> |
||||
<div class="font-bold text-xl text-center">Selectionner un Schéma et une Table :</div> |
||||
|
||||
<div class="bg-orange-400 w-full h-2 rounded-lg overflow-hidden my-2"></div> |
||||
|
||||
<label class="text-black">Schémas : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterFirstSchema" placeholder="Rechercher..."> |
||||
|
||||
<select (change)="useTablesWithFirstSchema($event)" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let schema of allSchema | filter : filterFirstSchema" value="{{ schema }}">{{ schema }}</option> |
||||
</select> |
||||
|
||||
<div class="bg-orange-400 w-full h-2 rounded-lg overflow-hidden my-2"></div> |
||||
|
||||
<div *ngIf="tablesByFirstSchema"> |
||||
<label class="text-black">Tables : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterFirstTable" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="firstTableData" (change)="getColumnsForJoinTwo()" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let table of tablesByFirstSchema | filtertable : filterFirstTable" id="{{ table.id }}" [ngValue]="table">{{ table.nameTable }}</option> |
||||
</select> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 py-4 "> |
||||
<div class="font-bold text-xl text-center">Selectionner un Schéma et une Table :</div> |
||||
<div class="bg-orange-400 w-full h-2 rounded-lg overflow-hidden my-2"></div> |
||||
|
||||
<label class="text-black">Schémas : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterSecondSchema" placeholder="Rechercher..."> |
||||
|
||||
<select (change)="useTablesWithSecondSchema($event)" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let schema of allSchema | filter : filterSecondSchema" value="{{ schema }}">{{ schema }}</option> |
||||
</select> |
||||
|
||||
<div class="bg-orange-400 w-full h-2 rounded-lg overflow-hidden my-2"></div> |
||||
|
||||
<div *ngIf="tablesBySecondSchema"> |
||||
<label class="text-black">Tables : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterSecondTable" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="secondTableData" (change)="getColumnsForJoinTwo()" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let table of tablesBySecondSchema | filtertable : filterSecondTable" id="{{ table.id }}" [ngValue]="table">{{ table.nameTable }}</option> |
||||
</select> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<div *ngIf="!columnIsFull && infoColumn" class="my-4 grid grid-cols-1 sm:grid-cols-4 gap-5"> |
||||
<!--Card--> |
||||
<div class="sm:col-start-2 sm:col-span-2 rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 p-4 text-center"> |
||||
<label class="text-red-600">ATTENTION : Il n'y a pas de colonnes en commun entre les deux tables sélectionnées.</label> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div *ngIf="columnIsFull && infoColumn" class="my-4 grid grid-cols-1 sm:grid-cols-4 gap-5"> |
||||
<!--Card--> |
||||
<div class="sm:col-start-2 sm:col-span-2 rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 pt-4 "> |
||||
<label class="text-black mb-4">Colonne(s) en commun : </label> |
||||
|
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterColumn" placeholder="Rechercher..."> |
||||
|
||||
<select (change)="displayColumnsInformations($event)" size="3" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let column of infoColumn | filter: filterColumn" id="{{ column.id }}" value="{{ column.id }}">{{ column.nameColumn }}</option> |
||||
</select> |
||||
</div> |
||||
|
||||
|
||||
<!--Card--> |
||||
<div *ngIf="displayColumns" class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="bg-orange-400 w-full h-2 overflow-hidden my-2"></div> |
||||
|
||||
<div class="px-6 pb-4 grid justify-items-center"> |
||||
<div class="font-bold text-xl mb-2">Colonne : {{ displayColumns.nameColumn }}</div> |
||||
<p class="text-lg">Data Type : {{ displayColumns.dataType }}</p> |
||||
<p class="text-lg">Taille : {{ displayColumns.lengthColumn }}</p> |
||||
<p class="text-lg">Description : {{ displayColumns.columnText }}</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
|
||||
<div *ngIf="displayColumns" class="my-4 grid sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5"> |
||||
<!--Card--> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="font-bold text-xl text-center pt-2">INNER JOIN</div> |
||||
<div class="px-2 py-2"> |
||||
<textarea rows="4" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"> |
||||
SELECT {{ nameFirstTableLowerCase }}.*, {{ nameSecondTableLowerCase }}.* |
||||
FROM {{firstSchema}}.{{nameFirstTable}} AS {{ nameFirstTableLowerCase }} |
||||
INNER JOIN {{secondSchema}}.{{nameSecondTable}} AS {{ nameSecondTableLowerCase }} |
||||
ON {{ nameFirstTableLowerCase }}.{{ displayColumns.nameColumn }}={{ nameSecondTableLowerCase }}.{{ displayColumns.nameColumn }}</textarea> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="font-bold text-xl text-center pt-2">FULL JOIN</div> |
||||
<div class="px-2 py-2"> |
||||
<textarea rows="4" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"> |
||||
SELECT {{ nameFirstTableLowerCase }}.*, {{ nameSecondTableLowerCase }}.* |
||||
FROM {{firstSchema}}.{{nameFirstTable}} AS {{ nameFirstTableLowerCase }} |
||||
FULL JOIN {{secondSchema}}.{{nameSecondTable}} AS {{ nameSecondTableLowerCase }} |
||||
ON {{ nameFirstTableLowerCase }}.{{ displayColumns.nameColumn }}={{ nameSecondTableLowerCase }}.{{ displayColumns.nameColumn }}</textarea> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="font-bold text-xl text-center pt-2">LEFT JOIN</div> |
||||
<div class="px-2 py-2"> |
||||
<textarea rows="4" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"> |
||||
SELECT {{ nameFirstTableLowerCase }}.*, {{ nameSecondTableLowerCase }}.* |
||||
FROM {{firstSchema}}.{{nameFirstTable}} AS {{ nameFirstTableLowerCase }} |
||||
LEFT JOIN {{secondSchema}}.{{nameSecondTable}} AS {{ nameSecondTableLowerCase }} |
||||
ON {{ nameFirstTableLowerCase }}.{{ displayColumns.nameColumn }}={{ nameSecondTableLowerCase }}.{{ displayColumns.nameColumn }}</textarea> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="font-bold text-xl text-center pt-2">RIGHT JOIN</div> |
||||
<div class="px-2 py-2"> |
||||
<textarea rows="4" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"> |
||||
SELECT {{ nameFirstTableLowerCase }}.*, {{ nameSecondTableLowerCase }}.* |
||||
FROM {{firstSchema}}.{{nameFirstTable}} AS {{ nameFirstTableLowerCase }} |
||||
RIGHT JOIN {{secondSchema}}.{{nameSecondTable}} AS {{ nameSecondTableLowerCase }} |
||||
ON {{ nameFirstTableLowerCase }}.{{ displayColumns.nameColumn }}={{ nameSecondTableLowerCase }}.{{ displayColumns.nameColumn }}</textarea> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
@ -0,0 +1,130 @@ |
||||
import { Component, OnInit } from '@angular/core'; |
||||
import { InfoColumnService } from '../../service/info-column.service'; |
||||
import { InfoTableService } from '../../service/info-table.service'; |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { InfoTable } from '../../model/info-table'; |
||||
import { InfoColumn } from '../../model/info-column'; |
||||
|
||||
@Component({ |
||||
selector: 'app-joins-page', |
||||
templateUrl: './joins-page.component.html', |
||||
styleUrls: ['./joins-page.component.scss'] |
||||
}) |
||||
export class JoinsPageComponent implements OnInit{ |
||||
public allSchema: String[] | undefined; |
||||
filterFirstSchema: string = ""; |
||||
filterSecondSchema: string = ""; |
||||
filterFirstTable: string = ""; |
||||
filterSecondTable: string = ""; |
||||
filterColumn: string = ""; |
||||
public firstSchema: string | undefined; |
||||
public secondSchema: string | undefined; |
||||
public tablesByFirstSchema: InfoTable[] | undefined; |
||||
public tablesBySecondSchema: InfoTable[] | undefined; |
||||
firstTableData: InfoTable | undefined; |
||||
secondTableData: InfoTable | undefined; |
||||
public infoColumn: InfoColumn[] | undefined; |
||||
public columnIsFull: boolean = false; |
||||
public endRequestForColumns: boolean = false; |
||||
public displayColumns: InfoColumn | undefined; |
||||
|
||||
|
||||
public nameFirstTableLowerCase: string = ""; |
||||
public nameSecondTableLowerCase: string = ""; |
||||
public nameFirstTable: string = ""; |
||||
public nameSecondTable: string = ""; |
||||
public tables: string[] | undefined; |
||||
public schemas: string[] | undefined; |
||||
|
||||
constructor( |
||||
|
||||
private infoColumnService: InfoColumnService, |
||||
private infoTableService: InfoTableService |
||||
){} |
||||
|
||||
ngOnInit(): void { |
||||
this.getSchemas(); |
||||
} |
||||
|
||||
public getSchemas():void { |
||||
this.infoTableService.getSchemas().subscribe( |
||||
(response : String[]) => { |
||||
this.allSchema = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public useTablesWithFirstSchema (event: any){ |
||||
this.firstSchema = event.target.value; |
||||
this.displayColumns = undefined; |
||||
this.columnIsFull = false; |
||||
this.infoColumn = undefined; |
||||
this.infoTableService.getTablesBySchema(event.target.value).subscribe( |
||||
(response : InfoTable[]) => { |
||||
this.tablesByFirstSchema = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public useTablesWithSecondSchema (event: any){ |
||||
this.columnIsFull = false; |
||||
this.secondSchema = event.target.value; |
||||
this.displayColumns = undefined; |
||||
this.infoColumn = undefined; |
||||
this.infoTableService.getTablesBySchema(event.target.value).subscribe( |
||||
(response : InfoTable[]) => { |
||||
this.tablesBySecondSchema = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public displayColumnsInformations (event: any){ |
||||
if(this.firstTableData && this.secondTableData){ |
||||
this.nameFirstTableLowerCase = this.firstTableData.nameTable.toLowerCase(); |
||||
this.nameSecondTableLowerCase = this.secondTableData.nameTable.toLowerCase(); |
||||
this.nameFirstTable = this.firstTableData.nameTable; |
||||
this.nameSecondTable = this.secondTableData.nameTable; |
||||
this.infoColumnService.getColumn(event.target.value).subscribe( |
||||
(response : InfoColumn) => { |
||||
this.displayColumns = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
} |
||||
|
||||
public getColumnsForJoinTwo (){ |
||||
this.displayColumns = undefined; |
||||
if(this.firstTableData && this.secondTableData && this.firstSchema && this.secondSchema){ |
||||
this.schemas = [this.firstSchema, this.secondSchema]; |
||||
this.tables = [this.firstTableData.nameTable, this.secondTableData.nameTable]; |
||||
|
||||
this.infoColumnService.getColumnsForJoinTwo(this.tables, this.schemas).subscribe( |
||||
(response : InfoColumn[]) => { |
||||
this.infoColumn = response; |
||||
if(this.infoColumn?.length === 0){ |
||||
this.columnIsFull = false; |
||||
} else { |
||||
this.columnIsFull = true; |
||||
} |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message); |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
|
||||
<div class="mx-auto"> |
||||
<img src="assets/images/logo-apsidetop-blanc.png" alt="Apside logo" class="mx-auto"> |
||||
<div class="text-center text-lg text-white">Produit créé par APSIDE TOP</div> |
||||
</div> |
||||
<div class="text-center text-white my-4"> |
||||
<p>Cette application, AssistDB a pour objectif de vous aider à rechercher des informations, créer des jointures et gérer un ensemble de scripts et de requêtes de manière centralisée entre tous les membres de l'équipe.</p> |
||||
<p class="mt-4">L'application est composée de plusieurs pages correspondant à des fonctionnalités bien disctintes :</p> |
||||
</div> |
||||
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-4"> |
||||
<div class="text-justify text-white"> |
||||
<p class="mt-2">-|- La page de Recherche : Permet de récupérer les informations d'une ou plusieurs colonnes spécifiques.</p> |
||||
<p class="mt-2">-|- La page de Jointures : Permet de générer automatiquement des jointures entre des tables possédant des colonnes identiques.</p> |
||||
</div> |
||||
<div class="text-justify text-white"> |
||||
<p class="mt-2">-|- La page de Création : Permet de créer des requêtes SQL complexes avec des jointures sur plusieurs colonnes ainsi que des conditions.</p> |
||||
<p class="mt-2">-|- La page de Gestionnaire : Permet de voir, ajouter, modifier et supprimer des scripts ou requêtes. Un système de Tags permet aussi une classification et une catégorisation complète. Les tags peuvent aussi être ajoutés, modifiés et supprimés. L'ensemble de cette page est actualisé et centralisé via GitHub pour l'ensemble des utilisateurs de l'application. |
||||
</p> |
||||
</div> |
||||
</div> |
||||
|
||||
|
@ -0,0 +1,11 @@ |
||||
.landing-block { |
||||
position: absolute; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate(-50%, -50%); |
||||
} |
||||
|
||||
.landing-links { |
||||
width: 100%; |
||||
text-align: center; |
||||
} |
@ -0,0 +1,10 @@ |
||||
import { Component } from '@angular/core'; |
||||
|
||||
@Component({ |
||||
selector: 'app-landing-page', |
||||
templateUrl: './landing-page.component.html', |
||||
styleUrls: ['./landing-page.component.scss'] |
||||
}) |
||||
export class LandingPageComponent { |
||||
|
||||
} |
@ -0,0 +1,72 @@ |
||||
|
||||
<div class="flex sm:flex-nowrap flex-wrap sm:space-x-4 my-4"> |
||||
<div class="w-full sm:w-2/3 h-full text-center rounded-lg overflow-hidden shadow-lg bg-white p-4 "> |
||||
<div class="flex"> |
||||
<button (click)="isNewFile()" class="btn-grad-purple-pink m-2" >Nouveau</button> |
||||
<button (click)="isExistingFile()" class="btn-grad-purple-pink m-2" >Fichier Existant</button> |
||||
</div> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-slate-100 border-solid border-orange-400 border-2 p-4"> |
||||
<div *ngIf="newFile"> |
||||
<div class="font-bold text-xl text-left mb-2">Veuillez rentrer le contenu du Script : </div> |
||||
<textarea [(ngModel)]="newFileData" rows="20" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-orange-400 focus:border-orange-400"> |
||||
</textarea> |
||||
</div> |
||||
|
||||
<div *ngIf="!newFile"> |
||||
<div class="py-2 relative rounded-lg overflow-hidden bg-slate-900 border-solid border-orange-400 border-2 text-center text-white" appDnd (fileDropped)="onFileDropped($event)" > |
||||
<input type="file" multiple class=" z-10 opacity-0 absolute w-full h-full top-0 left-0"/> |
||||
<mat-icon class="flex !h-20 !w-20" svgIcon="upload"></mat-icon> |
||||
<div>Glisser / Déposer le script ici</div> |
||||
</div> |
||||
<div *ngIf="files.length > 0" class="my-2"> |
||||
<div *ngFor="let file of files, index as i" class="mb-2 p-2 rounded-lg overflow-hidden bg-slate-200 border-solid border-orange-400 border-2" (click)="displayText(i)"> |
||||
<div class="grid grid-cols-1 sm:grid-cols-2 "> |
||||
|
||||
<div class="flex justify-start "> |
||||
<div class="font-bold mr-2">{{ file?.name }}</div> |
||||
<div>Taille: {{ formatBytes(file.size) }}</div> |
||||
</div> |
||||
|
||||
<div class="flex justify-end my-auto"> |
||||
<mat-icon (click)="deleteFile(i)" class="text-red-600 mx-2 hover:cursor-pointer" svgIcon="trash"></mat-icon> |
||||
</div> |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="font-bold text-xl text-left mb-2">Contenu du Script : </div> |
||||
<textarea [(ngModel)]="existingFileData" rows="20" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-orange-400 focus:border-orange-400"> |
||||
</textarea> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="w-full mt-2 sm:mt-0 sm:w-1/3 h-full rounded-lg shadow-lg bg-white p-4 "> |
||||
<div class="text-xl font-bold pb-2 text-center">Informations du Script :</div> |
||||
<div class="font-bold text-lg">Nom du Script :</div> |
||||
<input type="text" class="block w-full my-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="nameOfFile" placeholder="Tapez ici..."> |
||||
<div class="font-bold text-lg">Type d'extension :</div> |
||||
<select [(ngModel)]="nameOfExtension" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none" required> |
||||
<option [ngValue]="undefined" disabled>Sélectionner l'extension</option> |
||||
<option *ngFor="let ext of listOfExtension" value="{{ ext }}">{{ ext }}</option> |
||||
</select> |
||||
<div class="font-bold text-lg">Description du Script :</div> |
||||
<textarea type="text" class="block w-full my-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="description" placeholder="Description..."></textarea> |
||||
<div class="font-bold text-lg">Tags associés :</div> |
||||
<ng-multiselect-dropdown class="overflow-y-auto" |
||||
[placeholder]="'Selectionner les Tags'" |
||||
[settings]="dropdownSettings" |
||||
[data]="dropdownTagList" |
||||
[(ngModel)]="selectedTagList" |
||||
(onSelect)="onItemSelect($event)" |
||||
(onSelectAll)="onSelectAll($event)" |
||||
(onDeSelect)="onItemDeselect($event)" |
||||
(onDeSelectAll)="onDeselectAll($event)" |
||||
> |
||||
</ng-multiselect-dropdown> |
||||
<button (click)="addScriptToCentral()" type="button" class="btn-grad-teal-lime mr-2 mb-2 mt-4">Ajouter le Script</button> |
||||
|
||||
|
||||
</div> |
||||
</div> |
||||
|
@ -0,0 +1,183 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Component } from '@angular/core'; |
||||
import { MatIconRegistry } from '@angular/material/icon'; |
||||
import { DomSanitizer } from '@angular/platform-browser'; |
||||
import { Observable, Subject } from 'rxjs'; |
||||
import { Script } from '../../model/script'; |
||||
import { Router, RouterModule } from '@angular/router'; |
||||
import { ScriptService } from '../../service/script.service'; |
||||
import { Tag } from '../../model/tag'; |
||||
import { TagsService } from '../../service/tags.service'; |
||||
|
||||
@Component({ |
||||
selector: 'app-add-script', |
||||
templateUrl: './add-script.component.html', |
||||
styleUrls: ['./add-script.component.scss'] |
||||
}) |
||||
export class AddScriptComponent { |
||||
nameOfFile : string | undefined; |
||||
nameOfExtension : string | undefined; |
||||
listOfExtension : string[] = ["sql", "ps1", "txt", "bat"]; |
||||
newFile : boolean = false; |
||||
newFileData: string | undefined; |
||||
existingFileData: string | undefined; |
||||
files: File[] = []; |
||||
contentOfFiles: string[] = []; |
||||
scriptToSend: Script | undefined; |
||||
dropdownTagList: Tag[] = []; |
||||
selectedTagList: Tag[] = []; |
||||
dropdownSettings = {}; |
||||
linkId: number | undefined; |
||||
description: string | undefined; |
||||
|
||||
constructor( |
||||
private scriptService: ScriptService, |
||||
private tagService: TagsService, |
||||
private router: Router, |
||||
private matIconRegistry: MatIconRegistry, |
||||
private domSanitizer: DomSanitizer){ |
||||
this.matIconRegistry.addSvgIcon('upload', this.domSanitizer.bypassSecurityTrustResourceUrl('../../assets/svg/upload.svg')), |
||||
this.matIconRegistry.addSvgIcon('trash', this.domSanitizer.bypassSecurityTrustResourceUrl('../../assets/svg/trash.svg')) |
||||
|
||||
const navigation = this.router.getCurrentNavigation(); |
||||
if(navigation){ |
||||
const state = navigation.extras.state as { |
||||
nextId: number |
||||
}; |
||||
this.linkId = state.nextId; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
ngOnInit(): void{ |
||||
this.retrieveTags(); |
||||
|
||||
this.dropdownSettings = { |
||||
singleSelection: false, |
||||
idField: "tagId", |
||||
textField: "nameTag", |
||||
selectAllText: "Tout Sélectionner", |
||||
unSelectAllText: "Déselectionner tout", |
||||
itemsShowLimit: 3, |
||||
allowSearchFilter: true |
||||
}; |
||||
} |
||||
|
||||
public retrieveTags(){ |
||||
this.tagService.getAllTags().subscribe( |
||||
(response: Tag[]) => { |
||||
this.dropdownTagList = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
|
||||
public isNewFile (){ |
||||
this.newFile = true; |
||||
} |
||||
|
||||
public isExistingFile (){ |
||||
this.newFile = false; |
||||
} |
||||
|
||||
public deleteFile(index: number) { |
||||
this.files.splice(index, 1); |
||||
if(index == 0){ |
||||
this.newFileData = undefined; |
||||
} |
||||
} |
||||
|
||||
public onFileDropped(event: any){ |
||||
this.readFile(event[0]).subscribe((output) => { |
||||
this.existingFileData = output; |
||||
}) |
||||
for(const item of event){ |
||||
this.files.push(item); |
||||
} |
||||
} |
||||
|
||||
public displayText(index: number){ |
||||
this.readFile(this.files[index]).subscribe((output) => { |
||||
this.existingFileData = output; |
||||
}) |
||||
} |
||||
|
||||
readFile(file: File): Observable<string> { |
||||
const sub = new Subject<string>(); |
||||
var reader = new FileReader(); |
||||
|
||||
reader.onload = () => { |
||||
const content: string = reader.result as string; |
||||
sub.next(content); |
||||
sub.complete(); |
||||
}; |
||||
|
||||
reader.readAsText(file); |
||||
return sub.asObservable(); |
||||
} |
||||
|
||||
public renderFileContent( value: string[] ) : void { |
||||
this.newFileData = value[0]; |
||||
} |
||||
|
||||
public formatBytes(bytes: number) { |
||||
if (bytes === 0) { |
||||
return '0 Bytes'; |
||||
} |
||||
const k = 1024; |
||||
const dm = 2; |
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; |
||||
const i = Math.floor(Math.log(bytes) / Math.log(k)); |
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; |
||||
} |
||||
|
||||
public addScriptToCentral(){ |
||||
if(this.nameOfExtension && this.nameOfFile && this.description && this.linkId && this.selectedTagList && (this.existingFileData || this.newFileData)){ |
||||
|
||||
let listOfTags: String[] = [] |
||||
this.selectedTagList.forEach(tag => { |
||||
listOfTags.push(tag.nameTag); |
||||
}); |
||||
|
||||
const fullName = this.nameOfFile + "." + this.nameOfExtension; |
||||
let tempData: String = ""; |
||||
if(this.newFile && this.newFileData){ |
||||
tempData = this.newFileData |
||||
} else if(!this.newFile && this.existingFileData){ |
||||
tempData = this.existingFileData |
||||
} |
||||
this.scriptToSend = { |
||||
extension: this.nameOfExtension, |
||||
name: fullName, |
||||
data: tempData, |
||||
} |
||||
this.scriptService.addOneScript(this.scriptToSend, this.description, listOfTags, this.linkId).subscribe( |
||||
() => { |
||||
this.router.navigateByUrl('scriptmanagement'); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
} |
||||
|
||||
onItemSelect(item: any) { |
||||
|
||||
} |
||||
|
||||
onSelectAll(items: any) { |
||||
this.selectedTagList = items; |
||||
|
||||
} |
||||
|
||||
onItemDeselect(item: any){ |
||||
|
||||
} |
||||
|
||||
onDeselectAll(items: any){ |
||||
this.selectedTagList = []; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
|
||||
<div class="flex sm:flex-nowrap flex-wrap sm:space-x-4 my-4"> |
||||
<div class="w-full sm:w-2/3 h-full text-center rounded-lg overflow-hidden shadow-lg bg-white p-4 "> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-slate-100 border-solid border-orange-400 border-2"> |
||||
<div class="p-4"> |
||||
<div class="font-bold text-xl text-left mb-2">Contenu du Script : </div> |
||||
<textarea [(ngModel)]="newData" rows="20" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-orange-400 focus:border-orange-400"> |
||||
</textarea> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="w-full mt-2 sm:mt-0 sm:w-1/3 h-full rounded-lg shadow-lg bg-white p-4 "> |
||||
<div class="text-xl font-bold pb-2 text-center">Informations du Script :</div> |
||||
<div class="font-bold text-lg">Nom du Script :</div> |
||||
<input [(ngModel)]="newName" type="text" class="block w-full my-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" placeholder="Tapez ici..."> |
||||
<div class="font-bold text-lg">Type d'extension :</div> |
||||
<select [(ngModel)]="newExtension" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none" required> |
||||
<option [ngValue]="undefined" disabled>Sélectionner l'extension</option> |
||||
<option *ngFor="let ext of listOfExtension" value="{{ ext }}">{{ ext }}</option> |
||||
</select> |
||||
<div class="font-bold text-lg">Description du Script :</div> |
||||
<textarea type="text" class="block w-full my-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="description" placeholder="Description..."></textarea> |
||||
<div class="font-bold text-lg">Tags associés :</div> |
||||
<ng-multiselect-dropdown class="overflow-y-auto" |
||||
[placeholder]="'Selectionner les Tags'" |
||||
[settings]="dropdownSettings" |
||||
[data]="dropdownTagList" |
||||
[(ngModel)]="selectedTagList" |
||||
(onSelect)="onItemSelect($event)" |
||||
(onSelectAll)="onSelectAll($event)" |
||||
(onDeSelect)="onItemDeselect($event)" |
||||
(onDeSelectAll)="onDeselectAll($event)" |
||||
> |
||||
</ng-multiselect-dropdown> |
||||
<button (click)="editScript()" type="button" class="btn-grad-teal-lime mr-2 mb-2 mt-4">Modifier le Script</button> |
||||
</div> |
||||
</div> |
||||
|
||||
|
@ -0,0 +1,109 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Component } from '@angular/core'; |
||||
import { Router } from '@angular/router'; |
||||
import { ScriptService } from '../../service/script.service'; |
||||
import { Tag } from '../../model/tag'; |
||||
import { TagsService } from '../../service/tags.service'; |
||||
|
||||
@Component({ |
||||
selector: 'app-edit-script', |
||||
templateUrl: './edit-script.component.html', |
||||
styleUrls: ['./edit-script.component.scss'] |
||||
}) |
||||
export class EditScriptComponent { |
||||
defaultName: string | undefined; |
||||
newName: string | undefined; |
||||
newExtension: string | undefined; |
||||
newData: string | undefined; |
||||
editedId: number | undefined; |
||||
listOfExtension : String[] = ["sql", "ps1", "txt", "bat"]; |
||||
dropdownTagList: Tag[] = []; |
||||
selectedTagList: Tag[] = []; |
||||
dropdownSettings = {}; |
||||
description: string | undefined; |
||||
|
||||
constructor(private router: Router, |
||||
private scriptService: ScriptService, |
||||
private tagService: TagsService,){ |
||||
const navigation = this.router.getCurrentNavigation(); |
||||
if(navigation){ |
||||
const state = navigation.extras.state as { |
||||
name: string, |
||||
extension: string, |
||||
data: string, |
||||
linkId: number, |
||||
tags: Tag[], |
||||
description: string, |
||||
}; |
||||
const splitString = state.name.split("."); |
||||
this.defaultName = state.name; |
||||
this.newName = splitString[0]; |
||||
this.newExtension = state.extension; |
||||
this.newData = state.data; |
||||
this.editedId = state.linkId; |
||||
this.selectedTagList = state.tags; |
||||
this.description = state.description; |
||||
} |
||||
} |
||||
|
||||
ngOnInit(): void{ |
||||
this.retrieveTags(); |
||||
|
||||
this.dropdownSettings = { |
||||
singleSelection: false, |
||||
idField: "tagId", |
||||
textField: "nameTag", |
||||
selectAllText: "Tout Sélectionner", |
||||
unSelectAllText: "Déselectionner tout", |
||||
itemsShowLimit: 3, |
||||
allowSearchFilter: true |
||||
}; |
||||
} |
||||
|
||||
public retrieveTags(){ |
||||
this.tagService.getAllTags().subscribe( |
||||
(response: Tag[]) => { |
||||
this.dropdownTagList = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
|
||||
public editScript(){ |
||||
if(this.newExtension && this.editedId && this.newName && this.description && this.newData && this.defaultName){ |
||||
const fullName = this.newName + "." + this.newExtension; |
||||
let listOfTags: String[] = [] |
||||
this.selectedTagList.forEach(tag => { |
||||
listOfTags.push(tag.nameTag); |
||||
}); |
||||
|
||||
this.scriptService.editScript(this.newData, this.defaultName, fullName, this.description, listOfTags, this.editedId).subscribe( |
||||
() => { |
||||
this.router.navigateByUrl('scriptmanagement'); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
} |
||||
|
||||
onItemSelect(item: any) { |
||||
|
||||
} |
||||
|
||||
onSelectAll(items: any) { |
||||
this.selectedTagList = items; |
||||
|
||||
} |
||||
|
||||
onItemDeselect(item: any){ |
||||
|
||||
} |
||||
|
||||
onDeselectAll(items: any){ |
||||
this.selectedTagList = []; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,112 @@ |
||||
<div class="max-w-full rounded-2xl overflow-hidden shadow-lg bg-white"> |
||||
<div class="m-2 justify-items-center grid grid-cols-1 sm:grid-cols-12 gap-4 "> |
||||
<div class="sm:col-span-3 my-auto"> |
||||
<button class="flex btn-grad-purple-blue m-2" (click)="getAllScriptsWithTags(); getAllScripts()">Rafraichir</button> |
||||
</div> |
||||
<div class="sm:col-span-6 my-auto text-2xl font-bold"> |
||||
Gestionnaire de Scripts |
||||
</div> |
||||
<div class="sm:col-span-3 my-auto md:flex"> |
||||
<a routerLink="/tagsmanagement" class="flex btn-grad-red-yellow font-semibold m-2" >Gérer les Tags</a> |
||||
<button (click)="addScript()" class="flex btn-grad-red-yellow font-semibold m-2" >Ajouter un Script</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="max-w-full rounded-2xl overflow-hidden shadow-lg bg-white my-4 p-4"> |
||||
<div class="grid grid-cols-1 md:grid-cols-3 md:gap-4"> |
||||
<div class="col-span-2 rounded-lg overflow-hidden shadow-lg bg-slate-100 border-solid border-orange-400 border-2 p-4"> |
||||
<div class="flex space-x-2"> |
||||
<input [(ngModel)]="filterScriptName" type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" (ngModelChange)="sortWithFilter()" placeholder="Rechercher par nom ou description..."> |
||||
|
||||
</div> |
||||
<div> |
||||
<ng-multiselect-dropdown |
||||
[placeholder]="'Selectionner les Tags'" |
||||
[settings]="dropdownSettings" |
||||
[data]="dropdownTagList" |
||||
[(ngModel)]="selectedTagList" |
||||
(onSelect)="sortWithFilter()" |
||||
(onSelectAll)="onSelectAll($event)" |
||||
(onDeSelect)="sortWithFilter()" |
||||
(onDeSelectAll)="onDeselectAll()" |
||||
> |
||||
</ng-multiselect-dropdown> |
||||
</div> |
||||
<div class="overflow-y-auto h-96"> |
||||
<div class="grid grid-cols-1 md:grid-cols-2"> |
||||
<div *ngFor="let script of allScripts, index as i" class="grid grid-cols-2 rounded-2xl overflow-hidden shadow-lg bg-gray-300 p-4 m-2 " (click)="displayText(script)"> |
||||
<div class="flex justify-start"> |
||||
<div class="hidden xl:block font-bold font-mono mr-2 text-lg rounded-full overflow-hidden shadow-lg bg-green-300 p-2"> |
||||
{{script.extension}} |
||||
</div> |
||||
<div class="my-auto font-bold "> |
||||
{{script.name}} |
||||
</div> |
||||
</div> |
||||
<div class="my-auto flex justify-end"> |
||||
<mat-icon (click)="editScript(script)" class="text-orange-400 ml-2 hover:cursor-pointer" svgIcon="edit"></mat-icon> |
||||
<mat-icon (click)="deleteSpecifiedScript(script.name)" class="text-red-600 mx-2 hover:cursor-pointer" svgIcon="trash"></mat-icon> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="mt-4 md:mt-0"> |
||||
<cdk-accordion> |
||||
<cdk-accordion-item > |
||||
<div class="rounded-lg bg-slate-300 shadow-lg p-2"> |
||||
<div class="flex justify-between hover:cursor-pointer" (click)="descriptionDisplay = !descriptionDisplay"> |
||||
<div class="text-xl font-bold pb-2">Description :</div> |
||||
<span class="example-accordion-item-description" class="font-semibold"> |
||||
Cliquer pour {{ descriptionDisplay ? 'fermer' : 'ouvrir' }} |
||||
</span> |
||||
</div> |
||||
<div |
||||
role="region" |
||||
[style.display]="descriptionDisplay ? '' : 'none'" |
||||
class="rounded-lg bg-white p-2 shadow-md" |
||||
*ngIf="descText"> |
||||
{{ descText }} |
||||
</div> |
||||
</div> |
||||
</cdk-accordion-item> |
||||
<cdk-accordion-item> |
||||
<div class="rounded-lg bg-slate-300 p-2 mt-2"> |
||||
<div (click)="contentDisplay = !contentDisplay" class="flex justify-between hover:cursor-pointer"> |
||||
<div class="text-xl font-bold pb-2">Contenu du Script :</div> |
||||
<span class="example-accordion-item-description" class="font-semibold"> |
||||
Cliquer pour {{ contentDisplay ? 'fermer' : 'ouvrir' }} |
||||
</span> |
||||
</div> |
||||
<div |
||||
role="region" |
||||
[style.display]="contentDisplay ? '' : 'none'"> |
||||
<textarea rows="20" class="block p-2.5 w-full text-sm rounded-lg border bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-orange-400 focus:border-orange-400"> |
||||
{{textTo}}</textarea> |
||||
</div> |
||||
</div> |
||||
</cdk-accordion-item> |
||||
<cdk-accordion-item> |
||||
<div class="rounded-lg bg-slate-300 p-2 mt-2"> |
||||
<div (click)="tagsDisplay = !tagsDisplay" class="flex justify-between hover:cursor-pointer"> |
||||
<div class="text-xl font-bold pb-2">Tags associés :</div> |
||||
<span class="example-accordion-item-description" class="font-semibold"> |
||||
Cliquer pour {{ tagsDisplay ? 'fermer' : 'ouvrir' }} |
||||
</span> |
||||
</div> |
||||
<div |
||||
role="region" |
||||
[style.display]="tagsDisplay ? '' : 'none'"> |
||||
<div class="grid grid-cols-2 xl:grid-cols-4 text-center"> |
||||
<div *ngFor="let tagString of tagsListOfSpecScript" class="rounded-2xl overflow-hidden shadow-lg bg-green-300 p-4 m-2 font-bold"> |
||||
{{tagString}} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</cdk-accordion-item> |
||||
</cdk-accordion> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,192 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Component, OnInit } from '@angular/core'; |
||||
import { ScriptService } from '../../service/script.service'; |
||||
import { Script } from '../../model/script'; |
||||
import { MatIconRegistry } from '@angular/material/icon'; |
||||
import { DomSanitizer } from '@angular/platform-browser'; |
||||
import { Router, NavigationExtras } from '@angular/router'; |
||||
import { TagsService } from '../../service/tags.service'; |
||||
import { Tag } from '../../model/tag'; |
||||
import { LinkScriptTag } from '../../model/link-script-tag'; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-script-management', |
||||
templateUrl: './script-management.component.html', |
||||
styleUrls: ['./script-management.component.scss'] |
||||
}) |
||||
export class ScriptManagementComponent implements OnInit { |
||||
textTo: String | undefined; |
||||
descText: String | undefined; |
||||
tagsListOfSpecScript: String[] | undefined; |
||||
allScripts: Script[] = []; |
||||
memoryScripts: Script[] = []; |
||||
allLinksScriptTag: LinkScriptTag[]= []; |
||||
filterScriptName: string = ""; |
||||
dropdownTagList: Tag[] = []; |
||||
selectedTagList: Tag[] = []; |
||||
dropdownSettings = {}; |
||||
descriptionDisplay: boolean = true; |
||||
tagsDisplay: boolean = true; |
||||
contentDisplay: boolean = false; |
||||
|
||||
constructor( |
||||
private router: Router, |
||||
private tagService: TagsService, |
||||
private scriptService: ScriptService, |
||||
private matIconRegistry: MatIconRegistry, |
||||
private domSanitizer: DomSanitizer |
||||
){ |
||||
this.matIconRegistry.addSvgIcon('edit', this.domSanitizer.bypassSecurityTrustResourceUrl('../../assets/svg/edit.svg')), |
||||
this.matIconRegistry.addSvgIcon('trash', this.domSanitizer.bypassSecurityTrustResourceUrl('../../assets/svg/trash.svg')), |
||||
this.matIconRegistry.addSvgIcon('refresh', this.domSanitizer.bypassSecurityTrustResourceUrl('../../assets/svg/arrows.svg')) |
||||
|
||||
} |
||||
|
||||
ngOnInit(): void{ |
||||
this.getAllScriptsWithTags(); |
||||
this.getAllScripts(); |
||||
this.retrieveTags(); |
||||
|
||||
this.dropdownSettings = { |
||||
singleSelection: false, |
||||
idField: "tagId", |
||||
textField: "nameTag", |
||||
selectAllText: "Tout Sélectionner", |
||||
unSelectAllText: "Déselectionner tout", |
||||
itemsShowLimit: 3, |
||||
allowSearchFilter: true |
||||
}; |
||||
} |
||||
|
||||
public displayText(script: Script){ |
||||
if(this.allScripts){ |
||||
this.textTo = script.data; |
||||
const tempDescScript = this.allLinksScriptTag.filter(link => link.scriptName === script.name); |
||||
this.descText = tempDescScript[0].description; |
||||
this.tagsListOfSpecScript = tempDescScript[0].tags; |
||||
} |
||||
} |
||||
|
||||
public retrieveTags(){ |
||||
this.tagService.getAllTags().subscribe( |
||||
(response: Tag[]) => { |
||||
this.dropdownTagList = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
|
||||
onSelectAll(items: any) { |
||||
this.selectedTagList = items; |
||||
this.sortWithFilter(); |
||||
} |
||||
|
||||
onDeselectAll(){ |
||||
this.selectedTagList = []; |
||||
this.allScripts = this.memoryScripts; |
||||
} |
||||
|
||||
public sortWithFilter(){ |
||||
let tempLinksScriptsWithTags: LinkScriptTag[] = []; |
||||
if(this.selectedTagList.length !==0){ |
||||
this.allLinksScriptTag.forEach((one, i ) => { |
||||
const oneData = one.tags; |
||||
if(this.selectedTagList.every(sel => oneData.includes(sel.nameTag))){ |
||||
tempLinksScriptsWithTags.push(one); |
||||
} |
||||
}) |
||||
} else { |
||||
tempLinksScriptsWithTags = this.allLinksScriptTag; |
||||
} |
||||
if(!this.allScripts || !this.filterScriptName){ |
||||
this.allScripts = this.memoryScripts.filter(scr => tempLinksScriptsWithTags.some(temp => temp.scriptName === scr.name)) |
||||
} |
||||
if(this.filterScriptName){ |
||||
const tempFindDesc = tempLinksScriptsWithTags.filter(lnk => lnk.description.toLowerCase().includes(this.filterScriptName)) |
||||
|
||||
this.allScripts = this.memoryScripts.filter(item => item.name.toLowerCase().indexOf(this.filterScriptName) !== -1 && tempLinksScriptsWithTags.some(tm => tm.scriptName === item.name) || tempFindDesc.some(tmp => tmp.scriptName === item.name)); |
||||
} |
||||
} |
||||
|
||||
|
||||
public editScript(script: Script){ |
||||
let linkId; |
||||
let editedTagList: Tag[] = []; |
||||
this.allLinksScriptTag.forEach((linkTag, i) => { |
||||
if(linkTag.scriptName == script.name){ |
||||
linkId = linkTag.id; |
||||
editedTagList = this.dropdownTagList.filter(dp => linkTag.tags.some(lt => lt === dp.nameTag)); |
||||
} |
||||
}); |
||||
const tempDescScript = this.allLinksScriptTag.filter(link => link.scriptName === script.name); |
||||
const navigationExtras: NavigationExtras = { |
||||
state: { |
||||
name: script.name, |
||||
extension: script.extension, |
||||
data: script.data, |
||||
linkId: linkId, |
||||
tags: editedTagList, |
||||
description: tempDescScript[0].description, |
||||
} |
||||
}; |
||||
this.router.navigate(['editscript'], navigationExtras); |
||||
} |
||||
|
||||
public addScript(){ |
||||
let remId; |
||||
if(this.allLinksScriptTag.length > 0){ |
||||
remId = this.allLinksScriptTag[this.allLinksScriptTag.length - 1].id + 1; |
||||
} else { |
||||
remId = 1; |
||||
} |
||||
const navigationExtras: NavigationExtras = { |
||||
state: { |
||||
nextId: remId |
||||
|
||||
} |
||||
}; |
||||
this.router.navigate(['addscript'], navigationExtras); |
||||
} |
||||
|
||||
public getAllScripts(){ |
||||
this.scriptService.retreiveScripts().subscribe( |
||||
(response : Script[]) => { |
||||
this.allScripts = response; |
||||
this.memoryScripts = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public getAllScriptsWithTags(){ |
||||
this.scriptService.getAllScriptsWithTags().subscribe( |
||||
(response : LinkScriptTag[]) => { |
||||
this.allLinksScriptTag = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public deleteSpecifiedScript(name: String){ |
||||
if(window.confirm('Êtes-vous sûr de vouloir supprimer ce Script ?')){ |
||||
this.scriptService.deleteScript(name).subscribe( |
||||
() => { |
||||
this.getAllScripts(); |
||||
this.textTo = undefined; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
|
||||
<div class="text-center rounded-lg overflow-hidden shadow-lg bg-white p-4 my-4"> |
||||
<div class="text-2xl font-bold">Gestion des Tags</div> |
||||
<div class="grid grid-cols-3 gap-4 mt-2"> |
||||
<button class="btn-grad-teal-lime mx-2" (click)="addPress = !addPress">Ajouter un Tag</button> |
||||
<input [(ngModel)]="filterTag" type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" placeholder="Rechercher..."> |
||||
<button class="btn-grad-pink-orange mx-2" (click)="deleteAllTags()" disabled>Supprimer tous les Tags</button> |
||||
</div> |
||||
|
||||
<div *ngIf="addPress"> |
||||
<div class="bg-orange-400 w-full h-2 overflow-hidden my-4 rounded-lg"></div> |
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
||||
<div> |
||||
<div class="text-lg font-semibold">Nom du Tag : </div> |
||||
<input [(ngModel)]="nameOfTag" type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" placeholder="Taper le nom ici..."> |
||||
</div> |
||||
<div> |
||||
<div class="text-lg font-semibold">Description du Tag : </div> |
||||
<input [(ngModel)]="descOfTag" type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" placeholder="Taper la description ici..."> |
||||
</div> |
||||
</div> |
||||
<button class="btn-grad-green-blue mx-2 mt-4" (click)="addTag()">Valider</button> |
||||
</div> |
||||
|
||||
<div class="bg-orange-400 w-full h-2 overflow-hidden my-4 rounded-lg"></div> |
||||
|
||||
<div *ngIf="modifyPress"> |
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
||||
<div> |
||||
<div class="text-lg font-semibold">Nom du Tag : </div> |
||||
<div>{{ previousName }}</div> |
||||
<div class="text-lg font-semibold">Nouveau nom : </div> |
||||
<input [(ngModel)]="modifyName" type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" placeholder="Taper le nom ici..."> |
||||
</div> |
||||
<div> |
||||
<div class="text-lg font-semibold">Description du Tag : </div> |
||||
<div>{{ previousDesc }}</div> |
||||
<div class="text-lg font-semibold">Nouvelle description : </div> |
||||
<input [(ngModel)]="modifyDesc" type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" placeholder="Taper la description ici..."> |
||||
</div> |
||||
</div> |
||||
<button class="btn-grad-green-blue mx-2 my-4" (click)="modifyTag()">Valider</button> |
||||
</div> |
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4"> |
||||
<div *ngFor="let tag of allTags | filter: filterTag" class="rounded-2xl overflow-hidden shadow-lg bg-slate-800 p-2"> |
||||
<div class="text-white font-bold">Nom du Tag : {{ tag.nameTag }}</div> |
||||
<div class="text-white">{{ tag.descriptionTag }}</div> |
||||
<div class="flex justify-between my-2"> |
||||
<button class="btn-grad-purple-blue mx-2" (click)="pressModifyBtn(tag.tagId, tag.nameTag, tag.descriptionTag)">Modifier</button> |
||||
<button class="btn-grad-pink-orange mx-2" (click)="deleleTag(tag)">Supprimer</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
|
@ -0,0 +1,115 @@ |
||||
import { Component, OnInit } from '@angular/core'; |
||||
import { TagsService } from '../../service/tags.service'; |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Tag } from '../../model/tag'; |
||||
|
||||
@Component({ |
||||
selector: 'app-tags-management', |
||||
templateUrl: './tags-management.component.html', |
||||
styleUrls: ['./tags-management.component.scss'] |
||||
}) |
||||
export class TagsManagementComponent implements OnInit{ |
||||
allTags: Tag[]= []; |
||||
filterTag: string = ""; |
||||
nameOfTag: string | undefined; |
||||
descOfTag: string | undefined; |
||||
addPress: boolean = false; |
||||
modifyPress: boolean = false; |
||||
previousId: number | undefined |
||||
previousName: string | undefined; |
||||
previousDesc: string | undefined; |
||||
modifyName: string | undefined; |
||||
modifyDesc: string | undefined; |
||||
|
||||
constructor(private tagService: TagsService){} |
||||
|
||||
ngOnInit(): void{ |
||||
this.retrieveTags(); |
||||
} |
||||
|
||||
public retrieveTags(){ |
||||
this.tagService.getAllTags().subscribe( |
||||
(response: Tag[]) => { |
||||
this.allTags = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
|
||||
public addTag(){ |
||||
if(this.nameOfTag && this.descOfTag){ |
||||
|
||||
let tag: Tag = { |
||||
tagId: this.allTags[this.allTags.length - 1].tagId + 1, |
||||
nameTag: this.nameOfTag, |
||||
descriptionTag: this.descOfTag |
||||
} |
||||
this.tagService.addTag(tag).subscribe( |
||||
() => { |
||||
this.addPress = false; |
||||
this.nameOfTag =undefined; |
||||
this.descOfTag = undefined; |
||||
this.retrieveTags(); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
} |
||||
|
||||
public modifyTag(){ |
||||
if(this.previousName && this.previousDesc && this.previousId && this.modifyName && this.modifyDesc){ |
||||
let modifyTag: Tag = { |
||||
tagId: this.previousId, |
||||
nameTag: this.modifyName.toString(), |
||||
descriptionTag: this.modifyDesc.toString() |
||||
} |
||||
this.tagService.updateTag(this.previousName.toString(), modifyTag).subscribe( |
||||
() => { |
||||
this.modifyPress = false; |
||||
this.previousId = undefined; |
||||
this.previousName = undefined; |
||||
this.previousDesc = undefined; |
||||
this.modifyName = undefined; |
||||
this.modifyDesc = undefined; |
||||
this.retrieveTags(); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
} |
||||
|
||||
public deleleTag(tag: Tag){ |
||||
this.tagService.deleteTag(tag.nameTag).subscribe( |
||||
() => { |
||||
this.retrieveTags(); |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
}); |
||||
} |
||||
|
||||
public deleteAllTags(){ |
||||
if(window.confirm('Êtes-vous sûr de vouloir supprimer tous les tags ?')){ |
||||
this.tagService.deleteAllTags().subscribe( |
||||
() => { |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
public pressModifyBtn(id: number, name: string, desc: string){ |
||||
this.previousId = id; |
||||
this.previousName = name; |
||||
this.previousDesc = desc; |
||||
this.modifyName = name; |
||||
this.modifyDesc = desc; |
||||
this.modifyPress = !this.modifyPress; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,60 @@ |
||||
|
||||
<nav class="sticky top-0 left-0 right-0 z-50 bg-slate-900 hover:border-solid hover:border-b-2 hover:border-white border-b-2 border-slate-900 hover:ease-in-out duration-300"> |
||||
<div class="mx-auto max-w-7xl px-2 md:px-6 lg:px-8 relative flex h-16 items-center justify-between"> |
||||
<div class="absolute inset-y-0 left-0 flex items-center md:hidden"> |
||||
<!-- Mobile menu button--> |
||||
<button type="button" class="inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white" aria-controls="mobile-menu" aria-expanded="false"> |
||||
<svg (click)="openMobileMenu()" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"> |
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> |
||||
</svg> |
||||
</button> |
||||
</div> |
||||
<div class="flex flex-1 items-center justify-center md:items-stretch md:justify-start"> |
||||
<div class="flex flex-shrink-0 items-center"> |
||||
<img routerLink="" class="block h-8 w-auto lg:hidden hover:cursor-pointer" src="../../assets/images/logo-apsidetop-blanc.png" alt="Your Company"> |
||||
<img routerLink="" class="hidden h-8 w-auto lg:block hover:cursor-pointer" src="../../assets/images/logo-apsidetop-blanc.png" alt="Your Company"> |
||||
</div> |
||||
<div class="hidden md:ml-6 md:flex space-x-4" id="extend-menu"> |
||||
<a routerLinkActive="active" routerLink="request" class="btn-gray-simple">Recherche</a> |
||||
|
||||
<a routerLinkActive="active" routerLink="joins" class="btn-gray-simple">Jointures</a> |
||||
|
||||
<a routerLinkActive="active" routerLink="createjoins" class="btn-gray-simple">Création</a> |
||||
|
||||
<a routerLinkActive="active" routerLink="scriptmanagement" class="btn-gray-simple">Gestionnaire</a> |
||||
|
||||
<button (click)="applyResetDatabase()" class="btn-orange-simple">MAJ BDD</button> |
||||
|
||||
<mat-spinner *ngIf="isLoading" diameter="30"></mat-spinner> |
||||
</div> |
||||
</div> |
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2 md:static md:inset-auto md:ml-6 md:pr-0"> |
||||
<!-- Profile dropdown --> |
||||
|
||||
<div class="relative ml-3"> |
||||
<button type="button" class="flex rounded-full bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800" id="user-menu-button" aria-expanded="false" aria-haspopup="true"> |
||||
<img class="h-8 w-8 rounded-full border-solid border-2 border-white" src="../../assets/images/userpng.png" alt=""> |
||||
</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- Mobile menu, show/hide based on menu state. --> |
||||
<div *ngIf="mobileOpen" class="md:hidden" id="mobile-menu"> |
||||
<div class="space-y-1 px-2 pt-2 pb-3"> |
||||
<!-- Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" --> |
||||
<a routerLink="request" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Recherche</a> |
||||
|
||||
<a routerLink="joins" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Jointures</a> |
||||
|
||||
<a routerLink="createjoins" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Création</a> |
||||
|
||||
<a routerLink="scriptmanagement" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Gestionnaire</a> |
||||
|
||||
<button (click)="applyResetDatabase()" class="ml-2 text-white bg-orange-400 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium hover:animate-pulse">MAJ BDD</button> |
||||
|
||||
<mat-spinner *ngIf="isLoading" diameter="30" class="ml-2 mt-2"></mat-spinner> |
||||
</div> |
||||
</div> |
||||
</nav> |
||||
|
@ -0,0 +1,4 @@ |
||||
.active { |
||||
background-color: rgb(59 130 246); |
||||
color: white; |
||||
} |
@ -0,0 +1,52 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import { Component } from '@angular/core'; |
||||
import { ResetDataService } from '../../service/reset_data.service'; |
||||
import { Router, RouterModule } from '@angular/router'; |
||||
import { AppRoutingModule } from '../../app-routing.module'; |
||||
import { MatDialog, MatDialogModule } from '@angular/material/dialog'; |
||||
|
||||
@Component({ |
||||
selector: 'app-navbar', |
||||
templateUrl: './navbar.component.html', |
||||
styleUrls: ['./navbar.component.scss'] |
||||
}) |
||||
export class NavbarComponent { |
||||
public mobileOpen: boolean = false; |
||||
public isLoading: boolean = false; |
||||
|
||||
constructor(private resetDataService: ResetDataService, private router: Router){} |
||||
|
||||
public openMobileMenu(){ |
||||
this.mobileOpen = !this.mobileOpen; |
||||
} |
||||
|
||||
public applyResetDatabase():void { |
||||
if(window.confirm('Êtes-vous sûr de vouloir recharger le BDD ? Cela peut prendre du temps !')){ |
||||
this.isLoading = true; |
||||
this.resetDataService.resetDatabase().subscribe( |
||||
() => { |
||||
this.router.navigateByUrl(''); |
||||
this.isLoading = false; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
} |
||||
|
||||
public testreset(): void { |
||||
this.isLoading = true; |
||||
this.resetDataService.testres().subscribe( |
||||
() => { |
||||
this.router.navigateByUrl(''); |
||||
this.isLoading = false; |
||||
|
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,5 @@ |
||||
export interface Alias { |
||||
nameSchema: String, |
||||
nameTable: String, |
||||
nameAlias: String, |
||||
} |
@ -0,0 +1,5 @@ |
||||
export interface ColumnData { |
||||
operator: String; |
||||
aliasColumn: String; |
||||
specColumn: String; |
||||
} |
@ -0,0 +1,7 @@ |
||||
export interface Condition { |
||||
operator: String; |
||||
alias: String; |
||||
column: String; |
||||
condition: String; |
||||
value: String; |
||||
} |
@ -0,0 +1,7 @@ |
||||
export interface Employee { |
||||
id: number; |
||||
firstName: string; |
||||
lastName: string; |
||||
mail: string; |
||||
password: string; |
||||
} |
@ -0,0 +1,7 @@ |
||||
export interface InfoColumn { |
||||
id: number; |
||||
nameColumn: string; |
||||
dataType: string; |
||||
lengthColumn: number; |
||||
columnText: string; |
||||
} |
@ -0,0 +1,6 @@ |
||||
export interface InfoTable { |
||||
id: number; |
||||
nameTable: string; |
||||
nameSchema: string; |
||||
tableText: string; |
||||
} |
@ -0,0 +1,9 @@ |
||||
import { ColumnData } from './column-data'; |
||||
export interface Join { |
||||
joinSpec: String; |
||||
specificSchema: String; |
||||
specificTable: String; |
||||
baseAlias: String; |
||||
columns: ColumnData[]; |
||||
aliasSpecificTable: String; |
||||
} |
@ -0,0 +1,6 @@ |
||||
export interface LinkScriptTag { |
||||
id: number; |
||||
scriptName: String; |
||||
description: String; |
||||
tags: String[]; |
||||
} |
@ -0,0 +1,5 @@ |
||||
export interface Script { |
||||
extension: String, |
||||
name: String, |
||||
data: String |
||||
} |
@ -0,0 +1,5 @@ |
||||
export interface Tag { |
||||
tagId: number; |
||||
nameTag: string; |
||||
descriptionTag: string; |
||||
} |
@ -0,0 +1,96 @@ |
||||
<button class="flex btn-white-simple my-2" (click)="refreshEverything()">Réinitialiser</button> |
||||
|
||||
<div class="max-w-full rounded-2xl overflow-hidden shadow-lg bg-white"> |
||||
<mat-vertical-stepper class="text-white" [linear]="true"> |
||||
<mat-step label="Choisissez un Schéma"> |
||||
<div class="my-2"> |
||||
|
||||
<label class="text-black">Schémas : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterSchema" placeholder="Rechercher..."> |
||||
|
||||
<select [(ngModel)]="schemaName" (change)="useTablesWithSchemaName()" *ngIf="!schemasByTable" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let schema of allSchema | filter : filterSchema" [ngValue]="schema">{{ schema }}</option> |
||||
</select> |
||||
|
||||
<select [(ngModel)]="schemaData" (change)="useTablesWithSchemaName()" *ngIf="schemasByTable" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let schema of schemasByTable | filter : filterSchema" [ngValue]="schema">{{ schema.nameSchema }}</option> |
||||
</select> |
||||
|
||||
<button class="btn-white-simple" matStepperNext>Continuer</button> |
||||
</div> |
||||
</mat-step> |
||||
|
||||
<mat-step label="Choisissez une Table"> |
||||
<div class="my-2"> |
||||
|
||||
<label class="text-black">Tables : </label> |
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterTable" (ngModelChange)="sortCorrectly()" placeholder="Rechercher..." > |
||||
|
||||
<select [(ngModel)]="tableData" (change)="useSchemaWithTableName()" *ngIf="!tablesBySchema" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let table of infoTable | filter : filterTable" id="{{ table.id }}" [ngValue]="table">{{ table.nameTable }}</option> |
||||
</select> |
||||
|
||||
<select [(ngModel)]="tableData" (change)="useSchemaWithTableName()" *ngIf="tablesBySchema" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let table of tablesBySchema | filter : filterTable" id="{{ table.id }}" [ngValue]="table">{{ table.nameTable }}</option> |
||||
</select> |
||||
|
||||
<button class="btn-white-simple mr-2 mb-2" matStepperPrevious>Retour</button> |
||||
<button class="btn-white-simple" matStepperNext>Continuer</button> |
||||
</div> |
||||
</mat-step> |
||||
|
||||
<mat-step label="(Optionnel) Choisissez une colonne"> |
||||
<div class="my-2"> |
||||
|
||||
<label class="text-black mb-4">Colonnes : </label> |
||||
<button class="flex btn-white-simple my-2" (click)="resetColumnsInformations()">Reset</button> |
||||
|
||||
|
||||
<input type="text" class="block w-full my-2 pl-2 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-slate-800 focus:border-slate-800" [(ngModel)]="filterColumn" placeholder="Rechercher..."> |
||||
|
||||
<select (change)="displayColumnsInformations($event)" size="5" class="mb-4 bg-gray-50 text-sm text-slate-800 rounded-lg focus:ring-slate-800 focus:border-slate-800 block w-full p-2.5 bg-none"> |
||||
<option *ngFor="let column of infoColumn | filter: filterColumn" id="{{ column.id }}" value="{{ column.id }}">{{ column.nameColumn }} ({{ column.columnText }})</option> |
||||
</select> |
||||
|
||||
<button class="btn-white-simple mr-2 mb-2" matStepperPrevious>Retour</button> |
||||
</div> |
||||
</mat-step> |
||||
</mat-vertical-stepper> |
||||
</div> |
||||
|
||||
<div class="my-4 grid grid-cols-1 sm:grid-cols-3 gap-5"> |
||||
<!--Card--> |
||||
<div *ngIf="currentTable" class="sm:col-start-2 rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 py-4 grid justify-items-center"> |
||||
<div class="font-bold text-xl">Table : {{ currentTable.nameTable }}</div> |
||||
<div class="font-bold text-xl">Schéma : {{ selectedSchema }}</div> |
||||
<div class="bg-orange-400 w-full h-2 rounded-lg overflow-hidden my-2"></div> |
||||
<p class="text-base">{{ currentTable.tableText }}</p> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<div *ngIf="!displayColumns" class="my-4 grid sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5"> |
||||
<!--Card--> |
||||
<div *ngFor="let column of infoColumn" class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 py-4"> |
||||
<div class="font-bold text-xl mb-2">Colonne : {{ column.nameColumn }}</div> |
||||
<p class="text-base">Data Type : {{ column.dataType }}</p> |
||||
<p class="text-base">Taille : {{ column.lengthColumn }}</p> |
||||
<p class="text-base">Description : {{ column.columnText }}</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div *ngIf="displayColumns" class="my-4 grid sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5"> |
||||
<!--Card--> |
||||
<div class="rounded-lg overflow-hidden shadow-lg bg-white"> |
||||
<div class="px-6 py-4"> |
||||
<div class="font-bold text-xl mb-2">Colonne : {{ displayColumns.nameColumn }}</div> |
||||
<p class="text-base">Data Type : {{ displayColumns.dataType }}</p> |
||||
<p class="text-base">Taille : {{ displayColumns.lengthColumn }}</p> |
||||
<p class="text-base">Description : {{ displayColumns.columnText }}</p> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,171 @@ |
||||
import { HttpErrorResponse } from '@angular/common/http'; |
||||
import {FormBuilder, Validators} from '@angular/forms'; |
||||
import { Component, Input, OnInit } from '@angular/core'; |
||||
import { Employee } from '../../model/employee'; |
||||
import { EmployeeService } from '../../service/employee.service'; |
||||
import { InfoTable } from '../../model/info-table'; |
||||
import { InfoTableService } from '../../service/info-table.service'; |
||||
import { InfoColumn } from '../../model/info-column'; |
||||
import { InfoColumnService } from '../../service/info-column.service'; |
||||
import { MatStepperModule } from '@angular/material/stepper'; |
||||
|
||||
@Component({ |
||||
selector: 'app-request-page', |
||||
templateUrl: './request-page.component.html', |
||||
styleUrls: ['./request-page.component.scss'] |
||||
}) |
||||
export class RequestPageComponent implements OnInit { |
||||
|
||||
public allSchema: String[] | undefined; |
||||
public infoTable: InfoTable[] | undefined; |
||||
public infoColumn: InfoColumn[] | undefined; |
||||
public tablesBySchema: InfoTable[] | undefined; |
||||
public schemasByTable: InfoTable[] | undefined; |
||||
public displayColumns: InfoColumn | undefined; |
||||
public currentTable: InfoTable | undefined; |
||||
public selectedSchema: String | undefined; |
||||
filterSchema: string = ""; |
||||
filterTable: string = ""; |
||||
filterColumn: string = ""; |
||||
tableData: InfoTable | undefined; |
||||
schemaData: any; |
||||
schemaName: String | undefined; |
||||
|
||||
firstFormGroup = this._formBuilder.group({ |
||||
firstCtrl: ['', Validators.required], |
||||
}); |
||||
secondFormGroup = this._formBuilder.group({ |
||||
secondCtrl: ['', Validators.required], |
||||
}); |
||||
|
||||
constructor( |
||||
private _formBuilder: FormBuilder , |
||||
private infoColumnService: InfoColumnService, |
||||
private infoTableService: InfoTableService |
||||
){} |
||||
|
||||
|
||||
ngOnInit(): void {; |
||||
this.getSchemas(); |
||||
//this.getTables();
|
||||
} |
||||
|
||||
public getSchemas():void { |
||||
this.infoTableService.getSchemas().subscribe( |
||||
(response : String[]) => { |
||||
this.allSchema = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public getTables():void { |
||||
this.infoTableService.getAllTables().subscribe( |
||||
(response : InfoTable[]) => { |
||||
this.infoTable = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public sortCorrectly(){ |
||||
if(this.filterTable.length > 2){ |
||||
if(this.schemaName){ |
||||
this.infoTableService.getTablesWithFilterAndSchema(this.filterTable, this.schemaName).subscribe( |
||||
(response: InfoTable[]) => { |
||||
this.tablesBySchema = response; |
||||
}); |
||||
} else { |
||||
this.infoTableService.getTablesWithFilter(this.filterTable).subscribe( |
||||
(response: InfoTable[]) => { |
||||
this.infoTable = response; |
||||
}); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
public divideColumns(nameSch: String, tempsTab: InfoTable):void { |
||||
this.infoColumnService.getSelectedColumns(nameSch, tempsTab.nameTable).subscribe( |
||||
(response : InfoColumn[]) => { |
||||
this.infoColumn = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
this.displayColumns = undefined; |
||||
this.infoTableService.getTable(tempsTab.id).subscribe( |
||||
(response : InfoTable) => { |
||||
this.currentTable = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
|
||||
} |
||||
|
||||
public displayColumnsInformations (event: any){ |
||||
this.infoColumnService.getColumn(event.target.value).subscribe( |
||||
(response : InfoColumn) => { |
||||
this.displayColumns = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
} |
||||
|
||||
public useTablesWithSchemaName (){ |
||||
if(this.schemaName){ |
||||
this.selectedSchema = this.schemaName; |
||||
} else { |
||||
this.selectedSchema = this.schemaData.nameSchema; |
||||
} |
||||
if(this.selectedSchema){ |
||||
if(this.tableData){ |
||||
this.divideColumns(this.selectedSchema, this.tableData); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public useSchemaWithTableName (){ |
||||
if(this.tableData){ |
||||
this.infoTableService.getSchemasByTable(this.tableData.nameTable).subscribe( |
||||
(response : InfoTable[]) => { |
||||
this.schemasByTable = response; |
||||
}, |
||||
(error: HttpErrorResponse) => { |
||||
alert(error.message) |
||||
} |
||||
); |
||||
if(this.selectedSchema){ |
||||
this.divideColumns(this.selectedSchema, this.tableData); |
||||
} |
||||
this.schemaName = undefined; |
||||
} |
||||
} |
||||
|
||||
public resetColumnsInformations(){ |
||||
this.displayColumns = undefined; |
||||
} |
||||
|
||||
public refreshEverything(){ |
||||
this.tablesBySchema = undefined; |
||||
this.schemasByTable = undefined; |
||||
this.selectedSchema = undefined; |
||||
this.displayColumns = undefined; |
||||
this.infoColumn = undefined; |
||||
this.currentTable = undefined; |
||||
this.tableData = undefined; |
||||
this.filterTable = ""; |
||||
this.infoTable = undefined; |
||||
this.schemaName = undefined; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import { HttpClient, HttpParams } from '@angular/common/http'; |
||||
import { InfoColumn } from '../model/info-column'; |
||||
import { Observable } from 'rxjs'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class InfoColumnService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
public getAllColumns(): Observable<InfoColumn[]>{ |
||||
return this.http.get<InfoColumn[]>(`/api/columns/all`); |
||||
} |
||||
|
||||
public getColumn(columnId: Number): Observable<InfoColumn>{ |
||||
return this.http.get<InfoColumn>(`/api/column/${columnId}`); |
||||
} |
||||
|
||||
public getSelectedColumns(schema: String, table: String): Observable<InfoColumn[]>{ |
||||
return this.http.get<InfoColumn[]>(`/api/columns/${schema}/${table}`); |
||||
} |
||||
|
||||
public getColumnsForJoin(firstSchema: String, secondSchema: String, firstTable: String, secondTable: String): Observable<InfoColumn[]>{ |
||||
return this.http.get<InfoColumn[]>(`/api/columns/${firstSchema}/${secondSchema}/${firstTable}/${secondTable}`); |
||||
} |
||||
|
||||
public getColumnsForJoinTwo(tables: string[], schemas: string[]): Observable<InfoColumn[]>{ |
||||
const paramsGetJoins = new HttpParams() |
||||
.set('tables', tables.toString()) |
||||
.set('schemas', schemas.toString()); |
||||
return this.http.get<InfoColumn[]>(`/api/columns/joins`, {params: paramsGetJoins}); |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import { HttpClient } from '@angular/common/http'; |
||||
import { Observable } from 'rxjs'; |
||||
import { InfoTable } from '../model/info-table'; |
||||
|
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class InfoTableService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
public getAllTables(): Observable<InfoTable[]>{ |
||||
return this.http.get<InfoTable[]>(`/api/tables/all`); |
||||
} |
||||
|
||||
public getTable(tableId: Number): Observable<InfoTable>{ |
||||
return this.http.get<InfoTable>(`/api/table/${tableId}`); |
||||
} |
||||
|
||||
public getSchemas(): Observable<String[]>{ |
||||
return this.http.get<String[]>(`/api/schemas/all`); |
||||
} |
||||
|
||||
public getTablesBySchema(nameSchema : String): Observable<InfoTable[]>{ |
||||
return this.http.get<InfoTable[]>(`/api/tables/${nameSchema}`); |
||||
} |
||||
|
||||
public getSchemasByTable(nameTable : String): Observable<InfoTable[]>{ |
||||
return this.http.get<InfoTable[]>(`/api/schemas/${nameTable}`); |
||||
} |
||||
|
||||
public getTablesWithFilter(filter : String): Observable<InfoTable[]>{ |
||||
return this.http.get<InfoTable[]>(`/api/tables/filter/${filter}`); |
||||
} |
||||
|
||||
public getTablesWithFilterAndSchema(filter : String, schema: String): Observable<InfoTable[]>{ |
||||
return this.http.get<InfoTable[]>(`/api/tables/filter/${schema}/${filter}`); |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import { HttpClient } from '@angular/common/http'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class ResetDataService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
public resetDatabase(){ |
||||
return this.http.post<void>(`/api/reset`, null); |
||||
} |
||||
|
||||
public testres(){ |
||||
return this.http.post<void>(`/api/testres`, null); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,44 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import { HttpClient, HttpParams } from '@angular/common/http'; |
||||
import { Observable } from 'rxjs'; |
||||
import { Script } from '../model/script'; |
||||
import { LinkScriptTag } from '../model/link-script-tag'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class ScriptService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
public retreiveScripts(): Observable<Script[]>{ |
||||
return this.http.get<Script[]>(`/api/scripts`); |
||||
} |
||||
|
||||
public getAllScriptsWithTags(): Observable<LinkScriptTag[]>{ |
||||
return this.http.get<LinkScriptTag[]>(`/api/scripts/link`); |
||||
} |
||||
|
||||
public deleteScript(name: String){ |
||||
return this.http.delete<void>(`/api/script/delete/${name}`); |
||||
} |
||||
|
||||
public addOneScript(script: Script, description: String, tagList: String[], id: number){ |
||||
const paramsAddScript = new HttpParams() |
||||
.set('name', script.name.toString()) |
||||
.set('desc', description.toString()) |
||||
.set('tagList', tagList.join(', ')) |
||||
.set('linkid', id); |
||||
return this.http.post<void>(`/api/script/add`, script.data, {params: paramsAddScript}); |
||||
} |
||||
|
||||
public editScript(content: String, defaultName: String, newName: String, description: String, tagList: String[], id: number){ |
||||
const paramsAddScript = new HttpParams() |
||||
.set('defaultname', defaultName.toString()) |
||||
.set('newname', newName.toString()) |
||||
.set('desc', description.toString()) |
||||
.set('tagList', tagList.join(', ')) |
||||
.set('linkid', id); |
||||
return this.http.post<void>(`/api/script/edit`, content, {params: paramsAddScript}); |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import { HttpClient } from '@angular/common/http'; |
||||
import { Observable } from 'rxjs'; |
||||
import { Tag } from '../model/tag'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class TagsService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
public addTag(tag: Tag){ |
||||
return this.http.post<void>(`/api/tag/add`, tag); |
||||
} |
||||
|
||||
public updateTag(prevName: string, tag: Tag){ |
||||
return this.http.put<void>(`/api/tag/update/${prevName}`, tag); |
||||
} |
||||
|
||||
public getTag(tagId: Number): Observable<Tag>{ |
||||
return this.http.get<Tag>(`/api/tag/${tagId}`); |
||||
} |
||||
|
||||
public getAllTags(): Observable<Tag[]>{ |
||||
return this.http.get<Tag[]>(`/api/tags/all`); |
||||
} |
||||
|
||||
public deleteTag(tagName: String){ |
||||
return this.http.delete<void>(`/api/tag/delete/${tagName}`); |
||||
} |
||||
|
||||
public deleteAllTags(){ |
||||
return this.http.delete<void>(`/api/tags/deleteAll`); |
||||
} |
||||
} |
@ -0,0 +1,51 @@ |
||||
|
||||
@layer components { |
||||
|
||||
.btn-white-simple { |
||||
@apply bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow; |
||||
} |
||||
|
||||
.btn-gray-simple { |
||||
@apply text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium; |
||||
} |
||||
|
||||
.btn-orange-simple { |
||||
@apply text-white bg-orange-400 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium hover:animate-pulse; |
||||
} |
||||
|
||||
.btn-grad-red-rose { |
||||
@apply text-gray-900 text-lg bg-gradient-to-br from-rose-600 to-red-400 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-red-200 font-medium rounded-full px-5 py-2.5 text-center; |
||||
} |
||||
|
||||
.btn-grad-green-teal { |
||||
@apply text-white text-lg bg-gradient-to-br from-teal-400 to-green-500 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-green-200 font-medium rounded-full px-5 py-2.5 text-center; |
||||
} |
||||
|
||||
.btn-grad-pink-orange { |
||||
@apply text-white bg-gradient-to-br from-pink-500 to-orange-400 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-pink-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center; |
||||
} |
||||
|
||||
.btn-grad-red-yellow { |
||||
@apply text-gray-900 bg-gradient-to-r from-red-200 via-red-300 to-yellow-200 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-red-100 font-medium rounded-lg text-sm px-5 py-2.5 text-center; |
||||
} |
||||
|
||||
.btn-grad-green-blue { |
||||
@apply text-white bg-gradient-to-br from-green-400 to-blue-600 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-green-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center; |
||||
} |
||||
|
||||
.btn-grad-cyon-blue { |
||||
@apply text-white bg-gradient-to-r from-cyan-500 to-blue-500 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-cyan-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center; |
||||
} |
||||
|
||||
.btn-grad-purple-blue { |
||||
@apply text-white bg-gradient-to-br from-purple-600 to-blue-500 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium py-2.5 px-5 rounded-lg text-sm text-center; |
||||
} |
||||
|
||||
.btn-grad-teal-lime { |
||||
@apply text-black bg-gradient-to-r from-teal-200 to-lime-200 hover:bg-gradient-to-l hover:from-teal-200 hover:to-lime-200 focus:ring-4 focus:outline-none focus:ring-lime-200 font-medium py-2.5 px-5 rounded-lg text-center; |
||||
} |
||||
|
||||
.btn-grad-purple-pink { |
||||
@apply text-white bg-gradient-to-r from-purple-500 to-pink-500 hover:bg-gradient-to-l focus:ring-4 focus:outline-none focus:ring-purple-200 font-semibold py-2 px-4 rounded text-center; |
||||
} |
||||
} |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 996 B |
After Width: | Height: | Size: 503 B |
After Width: | Height: | Size: 749 B |
After Width: | Height: | Size: 502 B |
After Width: | Height: | Size: 675 B |
@ -0,0 +1,3 @@ |
||||
export const environment = { |
||||
production: false, |
||||
}; |
@ -0,0 +1,3 @@ |
||||
export const environment = { |
||||
production: false, |
||||
}; |
After Width: | Height: | Size: 948 B |
@ -0,0 +1,16 @@ |
||||
<!doctype html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<title>AngularTest</title> |
||||
<base href="/"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
<link rel="icon" type="image/x-icon" href="favicon.ico"> |
||||
<link rel="preconnect" href="https://fonts.gstatic.com"> |
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> |
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> |
||||
</head> |
||||
<body class="bg-slate-900"> |
||||
<app-root ></app-root> |
||||
</body> |
||||
</html> |
@ -0,0 +1,7 @@ |
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; |
||||
|
||||
import { AppModule } from './app/app.module'; |
||||
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule) |
||||
.catch(err => console.error(err)); |
@ -0,0 +1,13 @@ |
||||
/* You can add global styles to this file, and also import other style files */ |
||||
/* More informations on https://tailwindcss.com/ */ |
||||
|
||||
@import 'tailwindcss/base'; |
||||
@import 'tailwindcss/components'; |
||||
@import 'tailwindcss/utilities'; |
||||
|
||||
@import 'assets/button.scss'; |
||||
|
||||
|
||||
|
||||
html, body { height: 100%; } |
||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } |
@ -0,0 +1,17 @@ |
||||
/** @type {import('tailwindcss').Config} */ |
||||
module.exports = { |
||||
prefix: '', |
||||
purge: { |
||||
content: [ |
||||
'./src/**/*.{html,ts}', |
||||
] |
||||
}, |
||||
darkMode: 'class', // or 'media' or 'class'
|
||||
theme: { |
||||
extend: {}, |
||||
}, |
||||
variants: { |
||||
extend: {}, |
||||
}, |
||||
plugins: [require('@tailwindcss/forms'),require('@tailwindcss/typography')], |
||||
}; |
@ -0,0 +1,14 @@ |
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "./out-tsc/app", |
||||
"types": [] |
||||
}, |
||||
"files": [ |
||||
"src/main.ts" |
||||
], |
||||
"include": [ |
||||
"src/**/*.d.ts" |
||||
] |
||||
} |
@ -0,0 +1,33 @@ |
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
{ |
||||
"compileOnSave": false, |
||||
"compilerOptions": { |
||||
"baseUrl": "./", |
||||
"outDir": "./dist/out-tsc", |
||||
"forceConsistentCasingInFileNames": true, |
||||
"strict": true, |
||||
"noImplicitOverride": true, |
||||
"noPropertyAccessFromIndexSignature": true, |
||||
"noImplicitReturns": true, |
||||
"noFallthroughCasesInSwitch": true, |
||||
"sourceMap": true, |
||||
"declaration": false, |
||||
"downlevelIteration": true, |
||||
"experimentalDecorators": true, |
||||
"moduleResolution": "node", |
||||
"importHelpers": true, |
||||
"target": "ES2022", |
||||
"module": "ES2022", |
||||
"useDefineForClassFields": false, |
||||
"lib": [ |
||||
"ES2022", |
||||
"dom" |
||||
] |
||||
}, |
||||
"angularCompilerOptions": { |
||||
"enableI18nLegacyMessageIdFormat": false, |
||||
"strictInjectionParameters": true, |
||||
"strictInputAccessModifiers": true, |
||||
"strictTemplates": true |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "./out-tsc/spec", |
||||
"types": [ |
||||
"jasmine" |
||||
] |
||||
}, |
||||
"include": [ |
||||
"src/**/*.spec.ts", |
||||
"src/**/*.d.ts" |
||||
] |
||||
} |