Skip to content

Commit

Permalink
migrations: create the migration module
Browse files Browse the repository at this point in the history
Co-Authored-by: Johnny Mariéthoz <[email protected]>
  • Loading branch information
jma committed Oct 8, 2024
1 parent 1ed7763 commit abdb6be
Show file tree
Hide file tree
Showing 22 changed files with 1,665 additions and 0 deletions.
4 changes: 4 additions & 0 deletions projects/admin/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import { PERMISSIONS } from '@rero/shared';
import { PermissionGuard } from './guard/permission.guard';

const routes: Routes = [
{
path: 'migrations',
loadChildren: () => import('./migration/migration.module').then(m => m.MigrationModule)
},
{
path: '',
component: FrontpageComponent
Expand Down
9 changes: 9 additions & 0 deletions projects/admin/src/app/menu/menu-definition/menu-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,15 @@ export const MENU_APP: IMenuParent[] = [
permissions: [PERMISSIONS.PERM_MANAGEMENT]
}
},
{
name: 'Migrations',
router_link: ['/', 'migrations', 'records', 'migrations'],
attributes: { id: 'permissions-menu' },
extras: { iconClass: 'fa fa-cloud-upload' },
access: {
permissions: [PERMISSIONS.MIG_ACCESS]
}
},
]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
RERO ILS UI
Copyright (C) 2024 RERO
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
@if (record) {
<h5>
<a
[routerLink]="[detailUrl.link]"
[queryParams]="{ migration: record.metadata.migration_id }"
>{{ record.id }}
<p-badge
[severity]="severityTag"
[value]="record.metadata.conversion.status | translate"
/></a>
</h5>
@if (record?.metadata?.conversion?.json?.title) {
{{ record.metadata.conversion.json.title | mainTitle }}
}
<div>
<i
><small
><span translate>Last modification:</span>&nbsp;{{
record?.metadata?.updated_at | dateTranslate : "medium"
}}</small
></i
>
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* RERO ILS UI
* Copyright (C) 2024 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { Component, Input, OnInit } from '@angular/core';

@Component({
selector: 'admin-migration-data',
templateUrl: './migration-data.component.html',
})
export class MigrationDataBriefComponent implements OnInit {
// current record
@Input() record: any;

/** Type of record */
@Input() type: string;

/** Detail Url */
@Input() detailUrl: { link: string; external: boolean };

severityTag: string;

/** OnInit hook */
ngOnInit(): void {
this.setSeverityBadge();
}

/**
* Set the badge color from the status.
*/
setSeverityBadge() {
let severity = 'secondary';
const status = this.record?.metadata?.conversion.status;

if (status === 'complete') {
severity = 'success';
}
if (status.endsWith('error')) {
severity = 'danger';
}
this.severityTag = severity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
RERO ILS UI
Copyright (C) 2020-2024 RERO
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
@if (record) {

<h5>
{{ record.id }} <p-badge [severity]="severityTag" [value]="record.conversion.status | translate" />
</h5>
<i
><small
><span translate>Last modification:</span>&nbsp;{{
record?.updated_at | dateTranslate : "medium"
}}</small
></i
>
<hr />
@if (messages) {
<p-messages [(value)]="messages" [enableService]="false" [closable]="false" />
}
<div class="text-sm grid data">
<div class="markdown col" [innerHTML]="record.raw | markdown"></div>
<div
class="json col"
[innerHTML]="record?.conversion?.json | json | highlightJson"
></div>
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* RERO ILS UI
* Copyright (C) 2024 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

::ng-deep {
.markdown td,
.markdown th {
padding: 0 10px;
vertical-align: top;
}
tbody tr:nth-child(odd) {
background-color: #f8fafc;
}
}

.data {
.col {
max-height: 600px;
overflow: auto;
}
.json {
border-left: 1px solid gray;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* RERO ILS UI
* Copyright (C) 2024 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { HttpClient } from '@angular/common/http';
import { Component, inject, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ApiService, Record } from '@rero/ng-core';
import { of, Subscription, switchMap, tap } from 'rxjs';

@Component({
selector: 'admin-migration-data',
templateUrl: './migration-data.component.html',
styleUrl: './migration-data.component.scss',
})
export class MigrationDataDetailComponent implements OnInit, OnDestroy {
/** Observable resolving record data */

// current record
record: any;

// services
protected route = inject(ActivatedRoute);
protected http = inject(HttpClient);
protected apiService = inject(ApiService);

/** all component subscription */
private subscriptions = new Subscription();

// log messages from the backend
messages = [];

severityTag: string;

/** OnInit hook */
ngOnInit(): void {
// get the record when the pid is changed in the the route
this.subscriptions.add(
this.route.paramMap
.pipe(
switchMap(() => {
// route params
const docType = this.route.snapshot.params.type;
const id = this.route.snapshot.params.pid;
const migrationId = this.route.snapshot.queryParams.migration;
// nothing to do
if (docType == null || id == null || migrationId == null) {
return of(null);
}
// get the record from the backend
return this.http.get<Record>(
`${this.apiService.getEndpointByType(docType, true)}/${id}?migration=${migrationId}`
);
}),
tap((record: any) => {
// add message logs
if (record?.conversion.logs) {
['info', 'warning', 'error'].map((field) => {
const log = record.conversion.logs[field];
if (log) {
this.messages.push({
severity: field == 'warning' ? 'warn' : field,
detail: log,
});
}
});
}
}),
)
.subscribe((res) => {
this.record = res;
this.setSeverityBadge();
}
)
);
}

/**
* Set the badge color from the status.
*/
setSeverityBadge() {
let severity = 'secondary';
const status = this.record?.conversion.status;

if (status === 'complete') {
severity = 'success';
}
if (status.endsWith('error')) {
severity = 'danger';
}
this.severityTag = severity;
}
/** OnDestroy hook */
ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* RERO ILS UI
* Copyright (C) 2024 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

/**
* Highlight a JSON structure.
* from SONAR
*/
@Pipe({
name: 'highlightJson',
})
export class HighlightJsonPipe implements PipeTransform {
/**
* Constructor.
*
* @param sanitizer DOM Sanitizer.
*/
constructor(public sanitizer: DomSanitizer) {}

/**
* Highlight a JSON structure.
*
* @param value Json structure.
* @return Highlighted string.
*/
transform(value: string): any {
if (value == null) {
return;
}
let json = value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/(?:\r\n|\r|\n)/g, '<br>')
.replace(/( )/g, '&thinsp;');

json = json.replace(
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
(match: any) => {
let cls = 'text-gray-600';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'text-cyan-600';
} else {
cls = 'text-orange-600';
}
} else if (/true|false/.test(match)) {
cls = 'text-blue-600';
} else if (/null/.test(match)) {
cls = 'text-blue-600';
}
return `<span class="${cls}">${match}</span>`;
}
);
const html = this.sanitizer.bypassSecurityTrustHtml(json);
return html;
}
}
Loading

0 comments on commit abdb6be

Please sign in to comment.