Skip to content
Snippets Groups Projects
Commit 1ee95424 authored by Kawtar Laariche's avatar Kawtar Laariche
Browse files

#22: fix merge issues

parent d5a01b16
No related branches found
No related tags found
No related merge requests found
Showing
with 1090 additions and 207 deletions
...@@ -4,12 +4,14 @@ import { Observable, catchError, map, tap } from 'rxjs'; ...@@ -4,12 +4,14 @@ import { Observable, catchError, map, tap } from 'rxjs';
import { HttpSharedService } from '../http-shared/http-shared.service'; import { HttpSharedService } from '../http-shared/http-shared.service';
import { HttpClient, HttpEvent, HttpRequest } from '@angular/common/http'; import { HttpClient, HttpEvent, HttpRequest } from '@angular/common/http';
import { import {
AuthorPublisherModel,
CommentModel, CommentModel,
PublicSolution, PublicSolution,
ThreadModel, ThreadModel,
UserDetails, UserDetails,
} from 'src/app/shared/models'; } from 'src/app/shared/models';
import { CreateRatingRequestPayload } from 'src/app/shared/models/request-payloads'; import { CreateRatingRequestPayload } from 'src/app/shared/models/request-payloads';
import { MessageStatusModel } from 'src/app/shared/models/message-status.model';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
...@@ -122,7 +124,7 @@ export class PrivateCatalogsService { ...@@ -122,7 +124,7 @@ export class PrivateCatalogsService {
); );
} }
uploadFileToUrl( uploadExistingModelLicenseProfile(
loginUserID: string, loginUserID: string,
solutionId: string, solutionId: string,
revisionId: string, revisionId: string,
...@@ -140,8 +142,6 @@ export class PrivateCatalogsService { ...@@ -140,8 +142,6 @@ export class PrivateCatalogsService {
revisionId + revisionId +
'/' + '/' +
versionId; versionId;
const uploadUrl =
'https://dev02.ki-lab.nrw/api/license/upload/9b36ce33-ec9c-48e3-964f-5fd7e75ede6c/620ec698-4027-414a-8b9f-8d6503cbf35b/86e0f4fd-694a-4ba2-ba9f-bb3db1dc850f/1.0.0';
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
...@@ -154,6 +154,24 @@ export class PrivateCatalogsService { ...@@ -154,6 +154,24 @@ export class PrivateCatalogsService {
return this.http.request(req); return this.http.request(req);
} }
uploadNewModelLicenseProfile(userId: string, file: File) {
const url =
apiConfig.apiBackendURL +
'/api/model/upload/' +
userId +
'/?licUploadFlag=' +
true;
const formData = new FormData();
formData.append('file', file);
const req = new HttpRequest('POST', url, formData, {
reportProgress: true,
responseType: 'json',
});
return this.http.request(req);
}
createUpdateLicenseProfile( createUpdateLicenseProfile(
loginUserID: string, loginUserID: string,
solutionId: string, solutionId: string,
...@@ -377,4 +395,136 @@ export class PrivateCatalogsService { ...@@ -377,4 +395,136 @@ export class PrivateCatalogsService {
}), }),
); );
} }
getAuthors(
solutionId: string,
revisionId: string,
): Observable<AuthorPublisherModel[]> {
const url = `${apiConfig.apiBackendURL}/api/solution/${solutionId}/revision/${revisionId}/authors`;
return this._httpSharedService.get(url, undefined).pipe(
map((res) => res.response_body),
catchError((error) => {
throw error;
}),
);
}
addAuthor(
solutionId: string,
revisionId: string,
author: AuthorPublisherModel,
): Observable<AuthorPublisherModel[]> {
const url = `${apiConfig.apiBackendURL}/api/solution/${solutionId}/revision/${revisionId}/authors`;
const obj = {
request_body: author,
};
return this._httpSharedService.put(url, undefined, obj).pipe(
map((res) => res.response_body),
catchError((error) => {
throw error;
}),
);
}
removeAuthor(
solutionId: string,
revisionId: string,
author: AuthorPublisherModel,
): Observable<AuthorPublisherModel[]> {
const url = `${apiConfig.apiBackendURL}/api/solution/${solutionId}/revision/${revisionId}/removeAuthor`;
const obj = {
request_body: author,
};
return this._httpSharedService.put(url, undefined, obj).pipe(
map((res) => res.response_body),
catchError((error) => {
throw error;
}),
);
}
getPublisher(solutionId: string, revisionId: string): Observable<string> {
const url = `${apiConfig.apiBackendURL}/api/solution/${solutionId}/revision/${revisionId}/publisher`;
return this._httpSharedService.get(url, undefined).pipe(
map((res) => res.response_body),
catchError((error) => {
throw error;
}),
);
}
updatePublisher(
solutionId: string,
revisionId: string,
publisherName: string,
) {
const url = `${apiConfig.apiBackendURL}/api/solution/${solutionId}/revision/${revisionId}/publisher`;
const obj = publisherName;
return this._httpSharedService.put(url, undefined, obj).pipe(
catchError((error) => {
throw error;
}),
);
}
addCatalog(
userId: string,
solutionName: string,
dockerUrl: string,
): Observable<string> {
const urlCreateFavorite =
apiConfig.apiBackendURL + apiConfig.urlAddToCatalog + '/' + userId;
const addToReqObj = {
request_body: {
name: solutionName,
dockerfileURI: dockerUrl,
},
};
return this._httpSharedService
.post(urlCreateFavorite, undefined, addToReqObj)
.pipe(
map((res) => res.response_detail),
catchError((error) => {
throw error;
}),
);
}
uploadProtoBufFile(file: File) {
const url =
apiConfig.apiBackendURL + '/api/proto/upload/' + '?protoUploadFlag=true';
const formData = new FormData();
formData.append('file', file);
const req = new HttpRequest('POST', url, formData, {
reportProgress: true,
responseType: 'json',
});
return this.http.request(req);
}
getMessagingStatus(
userId: string,
trackId: string,
): Observable<MessageStatusModel[]> {
const url =
apiConfig.apiBackendURL +
apiConfig.urlMessagingStatus +
'/' +
userId +
'/' +
trackId;
return this._httpSharedService.post(url, undefined).pipe(
map((res) => res.response_body),
catchError((error) => {
throw error;
}),
);
}
} }
...@@ -41,39 +41,11 @@ ...@@ -41,39 +41,11 @@
</mat-menu> </mat-menu>
</div> </div>
</div> </div>
<div class="version-container"> <gp-version-dropdown
<button [selectedDefaultRevision]="selectedDefaultRevision"
class="mdl-button" [revisionsList]="revisionsList"
#menuTrigger2="matMenuTrigger" (revisionChange)="onChangeVersion($event)"
[matMenuTriggerFor]="menu2" ></gp-version-dropdown>
(click)="menuTrigger2.openMenu()"
>
<span class="text-ellipsis"
>Version - {{ selectedDefaultRevision?.version }}</span
>
<i class="material-icons">keyboard_arrow_down</i>
</button>
<mat-menu #menu2="matMenu"
><ul>
<li
*ngFor="let revision of revisionsList"
[ngClass]="{
selected: revision.version === selectedDefaultRevision.version
}"
(click)="onChangeVersion(revision)"
class="li-border-bottom"
>
<span
[ngClass]="{
'md-cat-txtellipsis': revision.version.length > 15
}"
>{{ revision.version }}</span
>
<span class="custom-tooltip-text">{{ revision.version }}</span>
</li>
</ul></mat-menu
>
</div>
</div> </div>
<ng-container *ngIf="isLoggedIn$ | async; else notLoggedIn"> <ng-container *ngIf="isLoggedIn$ | async; else notLoggedIn">
<div class="md-head-container2"> <div class="md-head-container2">
......
...@@ -51,6 +51,7 @@ import { apiConfig } from 'src/app/core/config'; ...@@ -51,6 +51,7 @@ import { apiConfig } from 'src/app/core/config';
import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service'; import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service';
import { SolutionIdComponent } from 'src/app/shared/components/solution-id/solution-id.component'; import { SolutionIdComponent } from 'src/app/shared/components/solution-id/solution-id.component';
import { BreadcrumbNavigationComponent } from 'src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component'; import { BreadcrumbNavigationComponent } from 'src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component';
import { VersionDropdownComponent } from 'src/app/shared/components/version-dropdown/version-dropdown.component';
interface SolutionData { interface SolutionData {
solutionId: string; solutionId: string;
...@@ -90,6 +91,7 @@ interface SolutionData { ...@@ -90,6 +91,7 @@ interface SolutionData {
FormsModule, FormsModule,
SolutionIdComponent, SolutionIdComponent,
BreadcrumbNavigationComponent, BreadcrumbNavigationComponent,
VersionDropdownComponent,
], ],
templateUrl: './model-details.component.html', templateUrl: './model-details.component.html',
styleUrl: './model-details.component.scss', styleUrl: './model-details.component.scss',
...@@ -103,14 +105,8 @@ export class ModelDetailsComponent implements OnInit { ...@@ -103,14 +105,8 @@ export class ModelDetailsComponent implements OnInit {
imageToShow: any; imageToShow: any;
isImageLoading = true; isImageLoading = true;
selectedDefaultCatalog!: Catalog; selectedDefaultCatalog!: Catalog;
revisionsList!: { revisionsList!: Revision[];
version: string; selectedDefaultRevision!: Revision;
revisionId: string;
}[];
selectedDefaultRevision!: {
version: string;
revisionId: string;
};
averageRatings!: AverageRatings; averageRatings!: AverageRatings;
allRatings: AllUserRating[] = []; allRatings: AllUserRating[] = [];
totalRatingsCount: number = 0; totalRatingsCount: number = 0;
...@@ -371,7 +367,7 @@ export class ModelDetailsComponent implements OnInit { ...@@ -371,7 +367,7 @@ export class ModelDetailsComponent implements OnInit {
}); });
} }
onChangeVersion(revision: { version: string; revisionId: string }) { onChangeVersion(revision: Revision) {
this.selectedDefaultRevision = revision; this.selectedDefaultRevision = revision;
this.setVersionIdInService(); this.setVersionIdInService();
this.setRevisionInService(revision); this.setRevisionInService(revision);
......
<mat-toolbar class="dialog-header"> <mat-toolbar class="dialog-header">
<div style="display: flex; align-items: center; padding: 0; flex: 1 1 auto"> <div style="display: flex; align-items: center; padding: 0; flex: 1 1 auto">
<h2>Delete Shared Member</h2> <h2>{{ title }}</h2>
</div> </div>
<button <button
type="button" type="button"
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
<mat-dialog-content> <mat-dialog-content>
<div class="star-rating-container"> <div class="star-rating-container">
<p> <p>
Would you like to delete '{{ user.firstName }} {{ user.lastName }}' from {{ content }}
the shared list?
</p> </p>
</div></mat-dialog-content </div></mat-dialog-content
> >
......
...@@ -27,34 +27,38 @@ import { AlertService } from 'src/app/core/services/alert.service'; ...@@ -27,34 +27,38 @@ import { AlertService } from 'src/app/core/services/alert.service';
styleUrl: './delete-user-dialog-confirmation-action.component.scss', styleUrl: './delete-user-dialog-confirmation-action.component.scss',
}) })
export class DeleteUserDialogConfirmationActionComponent implements OnInit { export class DeleteUserDialogConfirmationActionComponent implements OnInit {
user!: UserDetails; title!: string;
content!: string;
alertMessage!: string;
constructor( constructor(
public dialogRef: MatDialogRef<DeleteUserDialogConfirmationActionComponent>, public dialogRef: MatDialogRef<DeleteUserDialogConfirmationActionComponent>,
private privateCatalogsService: PrivateCatalogsService,
@Inject(MAT_DIALOG_DATA) public data: any, @Inject(MAT_DIALOG_DATA) public data: any,
private alertService: AlertService, private alertService: AlertService,
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
this.user = this.data.dataKey.user; this.title = this.data.dataKey.title;
this.content = this.data.dataKey.content;
this.alertMessage = this.data.dataKey.alertMessage;
} }
confirm() { confirm() {
this.privateCatalogsService this.data.dataKey.action().subscribe({
.deleteShareWithTeam(this.user.userId ?? '', this.data.dataKey.solutionId) next: (res: any) => {
.subscribe((res) => { this.alertService.notify(
const alert: Alert = { { message: this.alertMessage, type: AlertType.Success },
message: '', 3000,
type: AlertType.Success, );
}; this.dialogRef.close(true);
},
if (res.error_code === '100') { error: (err: any) => {
alert.message = 'Deleted successfully. '; this.alertService.notify(
} { message: 'Operation failed', type: AlertType.Error },
3000,
this.alertService.notify(alert, 3000); );
this.dialogRef.close(); this.dialogRef.close(false);
}); },
});
} }
} }
<div class="workflow-right-header workflow-header">Manage Authors</div> <div class="workflow-right-header workflow-header">Manage Authors</div>
<div style="display: flex; width: 100%; height: 60%; padding: 20px">
<div
style="
display: flex;
flex-direction: column;
padding: 10px;
width: 100%;
gap: 20px;
"
>
<span>PUBLISHER</span>
<mat-divider></mat-divider>
<form
style="display: flex; flex-direction: column; height: 100%"
[formGroup]="publisherForm"
>
<div
style="display: flex; flex-direction: column; flex-grow: 1; gap: 20px"
>
<mat-label>Publisher Name </mat-label>
<div style="display: flex; flex-direction: column">
<mat-form-field>
<input class="example-full-width" matInput formControlName="name" />
@if (publisherForm.value.name) {
<button
matSuffix
mat-icon-button
aria-label="Clear"
(click)="publisherForm.setValue({ name: '' })"
>
<mat-icon>close</mat-icon>
</button>
}
@if (
publisherForm.controls["name"].hasError("required") &&
publisherForm.controls["name"].touched
) {
<mat-error class="modal-error"
>Publisher name is required</mat-error
>
}
@if (
publisherForm.controls["name"].errors?.["minlength"] &&
publisherForm.controls["name"].touched
) {
<mat-error class="modal-error"
>Publisher name should contain at least 2 characters.</mat-error
>
}
@if (
publisherForm.controls["name"].errors?.["pattern"] &&
publisherForm.controls["name"].touched
) {
<mat-error class="modal-error"
>Publisher name must contain only alphanumeric
letters.</mat-error
>
}
@if (publisherForm.get("name")?.hasError("sameAsPublisher")) {
<mat-error class="modal-error"
>Please type in a new publisher name to save changes.</mat-error
>
}
</mat-form-field>
</div>
</div>
<div style="display: flex; justify-content: space-between">
<button
style="margin-right: 20px; width: 135px"
mat-raised-button
(click)="onCancelClick()"
>
Discard changes
</button>
<button
style="margin-right: 20px; width: 100px"
color="primary"
mat-raised-button
(click)="OnEditPublisherClick()"
[disabled]="!publisherForm.controls['name'].value"
>
Save
</button>
</div>
</form>
</div>
<mat-divider vertical style="height: auto"></mat-divider>
<div
style="
display: flex;
flex-direction: column;
padding: 10px;
width: 100%;
height: 100%;
"
>
<div style="display: flex; flex-direction: column; gap: 20px; height: 100%">
<span>AUTHORS</span>
<mat-divider></mat-divider>
<mat-chip-set #chipGrid>
@for (author of authorsList; track author) {
<mat-chip-row (removed)="onRemoveAuthorClick(author)">
{{ author.name }}
<button matChipRemove [attr.aria-label]="'remove ' + author.name">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
} @empty {
<span>No authors listed.</span>
}
</mat-chip-set>
Please add additional names of one or more author of this model.
<form
style="
display: flex;
flex-direction: column;
height: 100%;
"
[formGroup]="authorForm"
#formDirective="ngForm"
>
<div style="display: flex; flex-direction: column; flex-grow: 1">
<div style="display: flex; flex-direction: column">
<mat-label class="asterisk--after">Name </mat-label>
<mat-form-field>
<input
class="example-full-width"
matInput
formControlName="name"
/>
@if (authorForm.value.name) {
<button
matSuffix
mat-icon-button
aria-label="Clear"
(click)="authorForm.controls['name'].setValue('')"
>
<mat-icon>close</mat-icon>
</button>
}
@if (authorForm.controls["contact"].hasError("required")) {
<mat-error class="modal-error">Name is required</mat-error>
}
</mat-form-field>
</div>
<div style="display: flex; flex-direction: column">
<mat-label class="asterisk--after"> Contact Info</mat-label>
<div style="display: flex; flex-direction: column">
<mat-form-field>
<input
class="example-full-width"
matInput
formControlName="contact"
/>
@if (authorForm.value.contact) {
<button
matSuffix
mat-icon-button
aria-label="Clear"
(click)="authorForm.controls['contact'].setValue('')"
>
<mat-icon>close</mat-icon>
</button>
}
<mat-hint align="start" class="modal-note example-full-width"
>You can mention Email Address,URL and Phone Number
</mat-hint>
</mat-form-field>
@if (
authorForm.controls["contact"].hasError("required") &&
authorForm.controls["contact"].touched
) {
<mat-error class="modal-error"
>Contact info is required</mat-error
>
}
</div>
</div>
</div>
<button
color="primary"
style="align-self: end; margin-right: 20px; width: 100px"
mat-raised-button
(click)="onAddAuthorClick(formDirective)"
[disabled]="!authorForm.valid"
>
Add author
</button>
</form>
</div>
</div>
</div>
.example-full-width {
width: 100%;
}
.purple {
color: #671c9d;
}
.mat-divider.mat-divider-vertical {
border-right-style: solid;
border-right-color: rgb(246, 243, 250);
border-right-width: 2px;
}
.modal-note {
color: #888;
font-size: 12px;
font-family: "Open Sans", sans-serif !important;
}
::ng-deep.mat-mdc-form-field-hint-wrapper,
::ng-deep.mat-mdc-form-field-error-wrapper {
padding: 0px !important;
}
.asterisk--after:after {
content: "*";
color: red;
}
.modal-error {
color: red;
font-size: 12px;
font-family: "Open Sans", sans-serif !important;
}
.btn-comments-edit {
background: #f1f1f1 url("../../../../assets/images/Comment_edit.png")
no-repeat 3px center;
width: 60px;
margin-left: 4px;
cursor: pointer;
}
import { Component } from '@angular/core'; import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import {
AbstractControl,
AsyncValidatorFn,
FormBuilder,
FormControl,
FormGroup,
FormGroupDirective,
FormsModule,
ReactiveFormsModule,
ValidatorFn,
Validators,
} from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { ActivatedRoute, Router } from '@angular/router';
import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service';
import { PublicSolutionsService } from 'src/app/core/services/public-solutions.service';
import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service';
import { Alert, AlertType, AuthorPublisherModel } from '../../models';
import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
import { LiveAnnouncer } from '@angular/cdk/a11y';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { DeleteUserDialogConfirmationActionComponent } from '../delete-user-dialog-confirmation-action/delete-user-dialog-confirmation-action.component';
import { Observable, map, of } from 'rxjs';
import { AlertService } from 'src/app/core/services/alert.service';
@Component({ @Component({
selector: 'gp-manage-publisher-authors-page', selector: 'gp-manage-publisher-authors-page',
standalone: true, standalone: true,
imports: [CommonModule], imports: [
CommonModule,
MatButtonModule,
MatDividerModule,
FormsModule,
MatFormFieldModule,
MatInputModule,
ReactiveFormsModule,
MatChipsModule,
MatIconModule,
],
templateUrl: './manage-publisher-authors-page.component.html', templateUrl: './manage-publisher-authors-page.component.html',
styleUrl: './manage-publisher-authors-page.component.scss' styleUrl: './manage-publisher-authors-page.component.scss',
}) })
export class ManagePublisherAuthorsPageComponent { export class ManagePublisherAuthorsPageComponent implements OnInit {
solutionId!: string;
revisionId!: string;
authorsList!: AuthorPublisherModel[];
publisherName!: string;
authorForm!: FormGroup;
publisherForm!: FormGroup;
editPublisher: boolean = false;
constructor(
private activatedRoute: ActivatedRoute,
private formBuilder: FormBuilder,
private privateCatalogsService: PrivateCatalogsService,
public dialog: MatDialog,
private alertService: AlertService,
) {
this.authorForm = this.formBuilder.group({
name: ['', Validators.required],
contact: ['', Validators.required],
});
this.publisherForm = this.formBuilder.group({
name: [
'',
[
Validators.required,
Validators.minLength(2),
Validators.pattern('^[A-Z|a-z|0-9 ]*$'),
// this.notSameAsPublisher(this.publisherName),
],
// [],
],
});
}
ngOnInit(): void {
this.activatedRoute.parent?.params.subscribe((params) => {
this.solutionId = params['solutionId'];
this.revisionId = params['revisionId'];
this.loadAuthorList(this.solutionId, this.revisionId);
this.loadPublisher(this.solutionId, this.revisionId);
});
}
loadAuthorList(solutionId: string, revisionId: string) {
this.privateCatalogsService.getAuthors(solutionId, revisionId).subscribe({
next: (res) => {
this.authorsList = res;
},
error: (error) => {
console.error('Error fetching users:', error);
},
});
}
loadPublisher(solutionId: string, revisionId: string) {
this.privateCatalogsService.getPublisher(solutionId, revisionId).subscribe({
next: (res) => {
if (res) {
this.publisherName = res;
this.publisherNameControlValue = res;
this.updateValidators();
}
},
error: (error) => {
console.error('Error fetching users:', error);
},
});
}
updatePublisherData(solutionId: string, revisionId: string) {
this.privateCatalogsService.getPublisher(solutionId, revisionId).subscribe({
next: (res) => {
this.publisherName = res;
this.publisherNameControlValue = res;
},
error: (error) => {
console.error('Error fetching users:', error);
},
});
}
onAddAuthorClick(formDirective: FormGroupDirective) {
const author = this.authorForm.value;
this.privateCatalogsService
.addAuthor(this.solutionId, this.revisionId, author)
.subscribe({
next: (res) => {
this.authorsList = res;
const alert: Alert = {
message: '',
type: AlertType.Success,
};
alert.message = 'Author added successfully. ';
this.alertService.notify(alert, 3000);
this.authorForm.reset();
formDirective.resetForm();
},
error: (error) => {
const alert: Alert = {
message: '',
type: AlertType.Error,
};
alert.message =
'Error while adding Author : ' + error.error.response_detail;
this.alertService.notify(alert, 3000);
},
});
}
onRemoveAuthorClick(author: AuthorPublisherModel) {
const dialogRef: MatDialogRef<DeleteUserDialogConfirmationActionComponent> =
this.dialog.open(DeleteUserDialogConfirmationActionComponent, {
data: {
dataKey: {
title: 'Delete Author',
content: `Would you like to delete author '${author.name}' `,
alertMessage: 'Author deleted successfully. ',
action: () => this.removeAuthor(author),
},
},
autoFocus: false,
});
dialogRef.afterClosed().subscribe((result) => {
this.loadAuthorList(this.solutionId, this.revisionId);
});
}
OnEditPublisherClick() {
if (this.publisherNameControl)
this.changeAsyncValidationRules(
[this.notSameAsPublisher()],
this.publisherNameControl,
);
if (this.publisherForm.valid)
this.privateCatalogsService
.updatePublisher(
this.solutionId,
this.revisionId,
this.publisherForm.value.name,
)
.subscribe({
next: (res) => {
const alert: Alert = {
message: '',
type: AlertType.Success,
};
alert.message = 'Publisher updated successfully. ';
this.alertService.notify(alert, 3000);
this.updatePublisherData(this.solutionId, this.revisionId);
if (this.publisherNameControl) {
this.clearPublisherNameValidation(this.publisherNameControl);
this.changeSyncValidationRules(
[
Validators.required,
Validators.minLength(2),
Validators.pattern('^[A-Za-z0-9 ]+$'),
],
this.publisherNameControl,
);
}
// this.updatePublisherNameControlValidators();
/* this.publisherForm.reset();
formDirective.resetForm(); */
},
error: (error) => {
console.log({ error });
},
});
}
removeAuthor(author: AuthorPublisherModel): Observable<any> {
return this.privateCatalogsService.removeAuthor(
this.solutionId,
this.revisionId,
author ?? null,
);
}
onClickEditPublisher() {
this.editPublisher = true;
}
onCancelClick() {
this.editPublisher = false;
this.publisherForm.setValue({ name: this.publisherName });
}
/* notSameAsPublisher(publisherName: string): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
console.log('publisher name validation', this.publisherName);
console.log('control.value validation', control.value);
const isSame =
control.value.trim().toLowerCase() ===
publisherName.trim().toLowerCase();
console.log({ isSame });
return isSame ? { sameAsPublisher: true } : null;
};
}
*/
/* notSameAsPublisher(publisherName: string): AsyncValidatorFn {
return (
control: AbstractControl,
): Observable<{ [key: string]: any } | null> => {
if (!control.value) {
console.log('inside if');
return of(null); // If no value, return null immediately
}
const isSame =
control.value.trim().toLowerCase() ===
publisherName.trim().toLowerCase();
console.log({ isSame });
return of(isSame ? { sameAsPublisher: true } : null);
};
}
*/
notSameAsPublisher(): AsyncValidatorFn {
return (
control: AbstractControl,
): Observable<{ [key: string]: any } | null> => {
return of(control.value).pipe(
map((value) => {
const isSame =
value.trim().toLowerCase() ===
this.publisherName.trim().toLowerCase();
return isSame ? { sameAsPublisher: true } : null;
}),
);
};
}
get publisherNameControl() {
return this.publisherForm.get('name');
}
get publisherNameControlValue() {
return this.publisherNameControl?.value;
}
set publisherNameControlValue(value) {
this.publisherNameControl?.setValue(value, { emitEvent: false });
}
updateValidators(): void {
const nameControl = this.publisherNameControl;
if (nameControl) {
nameControl.setValidators([
Validators.required,
Validators.minLength(2),
Validators.pattern('^[A-Za-z0-9 ]+$'),
]);
nameControl.setAsyncValidators(this.notSameAsPublisher());
nameControl.updateValueAndValidity({ emitEvent: false });
}
}
changeSyncValidationRules(
validators: ValidatorFn | ValidatorFn[] | null,
control: AbstractControl<any, any>,
): void {
control.setValidators(validators);
}
changeAsyncValidationRules(
validators: AsyncValidatorFn | AsyncValidatorFn[] | null,
control: AbstractControl<any, any>,
): void {
control.setAsyncValidators(validators);
// control.addAsyncValidators(validators);
control.updateValueAndValidity();
}
clearPublisherNameValidation(control: AbstractControl<any, any>) {
control.clearAsyncValidators();
}
} }
<mat-sidenav-container> <div
<mat-sidenav mode="side" opened> style="display: flex; flex-direction: column"
<div class="workflow-left-header workflow-header">MANAGEMENT OPTIONS</div> *ngIf="solution$ | async as data"
>
<div style="display: flex; flex-direction: column; padding: 20px">
<div <div
style=" style="
display: flex; display: flex;
flex-direction: column !important; flex-direction: row;
justify-content: center !important; align-items: center;
margin-left: 16px; justify-items: center;
gap: 8px;
" "
> >
<div> <span class="md-headline5">Manage {{ data.name }}</span
<span class="tab-box" style="font-size: 14px">On - Boarding</span> >|
</div>
<div> <gp-version-dropdown
<span class="version-on-boarded" *ngIf="selectedRevision?.onBoarded" [selectedDefaultRevision]="(selectedRevision$ | async)!"
>Completed on [revisionsList]="(revisions$ | async)!"
{{ selectedRevision.onBoarded | date: "MM/dd/yyyy, h:mm:ss a" }}</span (revisionChange)="onChangeVersion($event)"
> ></gp-version-dropdown>
|
<div
style="
display: flex;
flex-direction: row;
align-items: center;
justify-items: center;
"
*ngIf="sharedWith$ | async as sharedWithData"
>
<span>Author and Publisher - &nbsp; </span>
<img
style="width: 27px; height: 27px"
src="../../../../assets/images/user-profile-black.png"
/>
<div style="display: flex; flex-direction: row">
<button
mat-icon-button
[matMenuTriggerFor]="menu"
aria-label="Example icon-button with a menu"
>
<mat-icon>more_horiz</mat-icon>
</button>
<mat-menu #menu="matMenu" xPosition="after">
<mat-list role="list" *ngFor="let item of sharedWithData">
<mat-list-item role="listitem" style="font-size: 14px">
<div
style="
display: flex;
align-items: center;
justify-items: center;
gap: 4px;
"
>
<img
style="width: 27px; height: 27px; display: inline-block"
src="../../../../assets/images/user-profile-black.png"
/>
<span [title]="[item.firstName, item.lastName].join('')"
>{{
[item.firstName, item.lastName].join(" ") | truncate: 13
}}
</span>
</div>
</mat-list-item>
</mat-list>
</mat-menu>
</div>
</div> </div>
</div> </div>
<nav mat-tab-nav-bar class="margin: 20px 0 20px 0;" [tabPanel]="tabPanel">
<a <div>
mat-tab-link <gp-breadcrumb-navigation
routerLink="shareWithTeam" [solution]="data"
routerLinkActive="is-active" [firstNavigationLabel]="'Home'"
style="padding-top: 2px; padding-bottom: 8px" [secondNavigationLabel]="'Manage my model'"
(firstNavigationClicked)="onHomeClick()"
(secondNavigationClicked)="onManageMyModelClick()"
></gp-breadcrumb-navigation>
</div>
</div>
<mat-sidenav-container>
<mat-sidenav mode="side" opened>
<div class="workflow-left-header workflow-header">MANAGEMENT OPTIONS</div>
<div
*ngIf="selectedRevision$ | async as selectedRevision"
style="
display: flex;
flex-direction: column !important;
justify-content: center !important;
margin-left: 16px;
"
> >
<mat-icon fontIcon="share"></mat-icon> <div>
<div <span class="tab-box" style="font-size: 14px">On - Boarding</span>
style=" </div>
display: flex; <div>
flex-direction: column; <span class="version-on-boarded"
align-items: flex-start; >Completed on
gap: 2px; {{
margin-left: 14px; selectedRevision.onBoarded | date: "MM/dd/yyyy, h:mm:ss a"
" }}</span
>
</div>
</div>
<nav mat-tab-nav-bar class="margin: 20px 0 20px 0;" [tabPanel]="tabPanel">
<a
mat-tab-link
routerLink="shareWithTeam"
routerLinkActive="is-active"
style="padding-top: 2px; padding-bottom: 8px"
> >
<span class="tab-box" style="font-size: 14px"> Share with team</span> <mat-icon fontIcon="share"></mat-icon>
<span <div
style=" style="
margin: 0; display: flex;
padding: 0; flex-direction: column;
font-size: 12px; align-items: flex-start;
line-height: 16px; gap: 2px;
font-weight: 400; margin-left: 14px;
letter-spacing: 0;
" "
>Shared with {{ sharedWith.length }} co-workers</span
> >
</div> <span class="tab-box" style="font-size: 14px">
</a> Share with team</span
<a mat-tab-link routerLink="publisherAuthors" routerLinkActive="is-active" >
><span <span
class="managelefticon tabs-left authorsimg" *ngIf="sharedWith$ | async as sharedWithData"
[ngClass]=" style="
isActive( margin: 0;
'/dashboard/manageMyModel/' + padding: 0;
solutionId + font-size: 12px;
revisionId + line-height: 16px;
'/publisherAuthors' font-weight: 400;
) letter-spacing: 0;
? 'authorsimg-active' "
: 'authorsimg-inactive' >Shared with {{ sharedWithData.length }} co-workers</span
" >
></span </div>
><span class="tab-box" style="font-size: 14px" </a>
>Manage Publisher/Authors</span <a
></a mat-tab-link
> routerLink="publisherAuthors"
<a mat-tab-link routerLink="publishModel" routerLinkActive="is-active" routerLinkActive="is-active"
><span ><span
class="managelefticon tabs-left companyimg" class="managelefticon tabs-left authorsimg"
[ngClass]=" [ngClass]="
isActive( isActive(
'/dashboard/manageMyModel/' + '/dashboard/manageMyModel/' +
solutionId + solutionId +
revisionId + revisionId +
'/publishModel' '/publisherAuthors'
) )
? 'companyimg-active' ? 'authorsimg-active'
: 'companyimg-inactive' : 'authorsimg-inactive'
" "
></span ></span
><span class="tab-box" style="font-size: 14px" ><span class="tab-box" style="font-size: 14px"
>Publish to Marketplace</span >Manage Publisher/Authors</span
></a ></a
> >
<a mat-tab-link routerLink="deleteModel" routerLinkActive="is-active" <a mat-tab-link routerLink="publishModel" routerLinkActive="is-active"
><mat-icon fontIcon="delete"></mat-icon ><span
><span class="managelefticon tabs-left companyimg"
class="tab-box" [ngClass]="
style="font-size: 14px; margin-left: 15px !important" isActive(
>Delete Model</span '/dashboard/manageMyModel/' +
></a solutionId +
> revisionId +
</nav> '/publishModel'
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel> )
</mat-sidenav> ? 'companyimg-active'
<mat-sidenav-content> <router-outlet></router-outlet></mat-sidenav-content : 'companyimg-inactive'
></mat-sidenav-container> "
></span
><span class="tab-box" style="font-size: 14px"
>Publish to Marketplace</span
></a
>
<a mat-tab-link routerLink="deleteModel" routerLinkActive="is-active"
><mat-icon fontIcon="delete"></mat-icon
><span
class="tab-box"
style="font-size: 14px; margin-left: 15px !important"
>Delete Model</span
></a
>
</nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>
</mat-sidenav>
<mat-sidenav-content> <router-outlet></router-outlet></mat-sidenav-content
></mat-sidenav-container>
</div>
...@@ -148,3 +148,21 @@ mat-sidenav-content { ...@@ -148,3 +148,21 @@ mat-sidenav-content {
color: #681d9e; color: #681d9e;
font-weight: 700 !important; font-weight: 700 !important;
} }
::ng-deep.mat-mdc-menu-panel {
width: 160px;
}
.mat-mdc-menu-content {
padding: 0px !important;
}
.mdc-list {
padding: 0px !important;
}
.md-headline5 {
font-size: 20px;
font-weight: 600;
color: #671c9d;
}
...@@ -10,10 +10,24 @@ import { ...@@ -10,10 +10,24 @@ import {
Revision, Revision,
UserDetails, UserDetails,
} from '../../models'; } from '../../models';
import { Subscription } from 'rxjs'; import {
BehaviorSubject,
Observable,
Subscription,
map,
of,
switchMap,
tap,
} from 'rxjs';
import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service'; import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service';
import { PublicSolutionsService } from 'src/app/core/services/public-solutions.service'; import { PublicSolutionsService } from 'src/app/core/services/public-solutions.service';
import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service'; import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service';
import { BreadcrumbNavigationComponent } from '../breadcrumb-navigation/breadcrumb-navigation.component';
import { VersionDropdownComponent } from '../version-dropdown/version-dropdown.component';
import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu';
import { MatListModule } from '@angular/material/list';
import { TruncatePipe } from '../../pipes/truncate.pipe';
@Component({ @Component({
selector: 'gp-model-management', selector: 'gp-model-management',
...@@ -24,6 +38,13 @@ import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.s ...@@ -24,6 +38,13 @@ import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.s
MatTabsModule, MatTabsModule,
MatIconModule, MatIconModule,
RouterModule, RouterModule,
BreadcrumbNavigationComponent,
VersionDropdownComponent,
MatButtonModule,
MatMenuModule,
MatIconModule,
MatListModule,
TruncatePipe,
], ],
templateUrl: './model-management.component.html', templateUrl: './model-management.component.html',
styleUrl: './model-management.component.scss', styleUrl: './model-management.component.scss',
...@@ -34,6 +55,13 @@ export class ModelManagementComponent implements OnInit { ...@@ -34,6 +55,13 @@ export class ModelManagementComponent implements OnInit {
selectedRevision!: Revision; selectedRevision!: Revision;
selectedRevisionSubscription!: Subscription; selectedRevisionSubscription!: Subscription;
sharedWith: UserDetails[] = []; sharedWith: UserDetails[] = [];
solution!: PublicSolutionDetailsModel;
revisionsList!: Revision[];
solution$!: Observable<PublicSolutionDetailsModel>;
revisions$!: Observable<Revision[]>;
sharedWith$!: Observable<UserDetails[]>;
selectedRevision$: BehaviorSubject<Revision | null> =
new BehaviorSubject<Revision | null>(null);
constructor( constructor(
private router: Router, private router: Router,
...@@ -43,12 +71,45 @@ export class ModelManagementComponent implements OnInit { ...@@ -43,12 +71,45 @@ export class ModelManagementComponent implements OnInit {
private privateCatalogsService: PrivateCatalogsService, private privateCatalogsService: PrivateCatalogsService,
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
this.activatedRoute.params.subscribe((params) => { this.solution$ = this.activatedRoute.params.pipe(
this.solutionId = params['solutionId']; switchMap((params) => {
this.revisionId = params['revisionId']; this.solutionId = params['solutionId'];
this.getShareWithTeam(this.solutionId); this.revisionId = params['revisionId'];
this.loadData(this.solutionId, this.revisionId); this.sharedWith$ = this.privateCatalogsService.getShareWithTeam(
}); this.solutionId,
);
return this.publicSolutionsService.getSolutionDetails(
this.solutionId,
this.revisionId,
);
}),
tap((solution) => {
this.revisions$ = this.getRevisionsAsObservable(solution);
const initialRevision =
solution.revisions.find(
(rev) => rev.revisionId === this.revisionId,
) || solution.revisions[0];
this.revisions$ = this.getRevisionsAsObservable(solution);
this.updateSelectedRevision(this.revisionId, solution);
this.setRevisionInService(solution.revisions[0]);
}),
);
}
private updateSelectedRevision(
revisionId: string,
solution: PublicSolutionDetailsModel,
): void {
const revision = solution.revisions.find(
(rev) => rev.revisionId === revisionId,
);
if (revision) {
this.selectedRevision$.next({
revisionId: revision.revisionId,
version: revision.version,
onBoarded: revision.onboarded,
});
}
} }
isActive(modelRoute: string): boolean { isActive(modelRoute: string): boolean {
...@@ -59,6 +120,7 @@ export class ModelManagementComponent implements OnInit { ...@@ -59,6 +120,7 @@ export class ModelManagementComponent implements OnInit {
this.publicSolutionsService this.publicSolutionsService
.getSolutionDetails(solutionId, revisionId) .getSolutionDetails(solutionId, revisionId)
.subscribe((res) => { .subscribe((res) => {
console.log({ res });
const revisionsList = this.getRevisionsList(res); const revisionsList = this.getRevisionsList(res);
this.selectedRevision = revisionsList[0]; this.selectedRevision = revisionsList[0];
this.setRevisionInService(this.selectedRevision); this.setRevisionInService(this.selectedRevision);
...@@ -75,14 +137,6 @@ export class ModelManagementComponent implements OnInit { ...@@ -75,14 +137,6 @@ export class ModelManagementComponent implements OnInit {
); );
} }
setRevisionInService(revision: Revision): void {
this.sharedDataService.selectedRevision = {
version: revision.version,
revisionId: revision.revisionId,
onBoarded: revision.onBoarded,
};
}
getShareWithTeam(solutionId: string): void { getShareWithTeam(solutionId: string): void {
this.privateCatalogsService.getShareWithTeam(solutionId).subscribe({ this.privateCatalogsService.getShareWithTeam(solutionId).subscribe({
next: (users) => { next: (users) => {
...@@ -93,4 +147,35 @@ export class ModelManagementComponent implements OnInit { ...@@ -93,4 +147,35 @@ export class ModelManagementComponent implements OnInit {
}, },
}); });
} }
onHomeClick() {}
onManageMyModelClick() {}
private getRevisionsAsObservable(
solution: PublicSolutionDetailsModel,
): Observable<Revision[]> {
return new Observable<Revision[]>((subscriber) => {
const revisions = solution.revisions.map((rev) => ({
version: rev.version,
revisionId: rev.revisionId,
onBoarded: rev.onboarded,
}));
subscriber.next(revisions);
subscriber.complete();
});
}
onChangeVersion(revision: Revision): void {
this.selectedRevision$.next(revision);
this.setRevisionInService(revision);
this.setVersionIdInService(revision.version);
}
setRevisionInService(revision: Revision): void {
this.sharedDataService.selectedRevision = revision;
}
setVersionIdInService(version: string): void {
this.sharedDataService.versionId = version;
}
} }
...@@ -396,7 +396,6 @@ ...@@ -396,7 +396,6 @@
.mdl-button.btn-primary, .mdl-button.btn-primary,
.mdl-button.btn-secondary { .mdl-button.btn-secondary {
box-shadow: none; box-shadow: none;
webkit-box-shadow: none;
line-height: 27px; line-height: 27px;
text-transform: capitalize; text-transform: capitalize;
} }
......
...@@ -56,35 +56,6 @@ ...@@ -56,35 +56,6 @@
</span> </span>
</div> </div>
</div> </div>
<!-- <div
style="display: flex; flex-direction: row; justify-content: end"
>
<button matChipRemove [attr.aria-label]="'remove ' + sharedUser">
<mat-icon>cancel</mat-icon>
</button>
</div>
<div
style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
"
>
<img
style="width: 30px; height: 30px"
src="../../../../assets/images/user-profile-black.png"
/>
<span
[title]="[sharedUser.firstName, sharedUser.lastName].join(' ')"
>
{{
[sharedUser.firstName, sharedUser.lastName].join(" ")
| truncate: 8
}}
</span>
</div> -->
</mat-chip> </mat-chip>
} }
</mat-chip-set> </mat-chip-set>
...@@ -96,7 +67,7 @@ ...@@ -96,7 +67,7 @@
style="display: flex; flex-direction: row; gap: 4px" style="display: flex; flex-direction: row; gap: 4px"
class="manage-models" class="manage-models"
> >
<span class="purple">Sharing "{{ solution.name }}" </span> <span class="purple">Sharing "{{ solution?.name }}" </span>
|<span> Version - {{ selectedRevision.version }}</span> |<span> Version - {{ selectedRevision.version }}</span>
| |
<gp-solution-id [solutionId]="solutionId"></gp-solution-id> <gp-solution-id [solutionId]="solutionId"></gp-solution-id>
......
...@@ -256,8 +256,11 @@ export class ShareWithTeamPageComponent implements OnInit { ...@@ -256,8 +256,11 @@ export class ShareWithTeamPageComponent implements OnInit {
this.dialog.open(DeleteUserDialogConfirmationActionComponent, { this.dialog.open(DeleteUserDialogConfirmationActionComponent, {
data: { data: {
dataKey: { dataKey: {
solutionId: this.solutionId, title: 'Delete Shared Member',
user: user, content: `Would you like to delete '${user.firstName} ${user.lastName}' from
the shared list?`,
alertMessage: 'Deleted successfully. ',
action: () => this.deleteUser(user),
}, },
}, },
autoFocus: false, autoFocus: false,
...@@ -267,4 +270,11 @@ export class ShareWithTeamPageComponent implements OnInit { ...@@ -267,4 +270,11 @@ export class ShareWithTeamPageComponent implements OnInit {
this.getShareWithTeam(this.solutionId); this.getShareWithTeam(this.solutionId);
}); });
} }
deleteUser(user: UserDetails): Observable<any> {
return this.privateCatalogsService.deleteShareWithTeam(
user.userId ?? '',
this.solutionId,
);
}
} }
<div class="version-container">
<button
class="version-button"
#menuTrigger2="matMenuTrigger"
mat-raised-button
[matMenuTriggerFor]="menu2"
(click)="menuTrigger2.openMenu()"
>
<span>Version - {{ selectedDefaultRevision?.version }}</span>
<mat-icon iconPositionEnd>keyboard_arrow_down</mat-icon>
</button>
<mat-menu #menu2="matMenu">
<mat-list role="list" *ngFor="let revision of revisionsList">
<mat-list-item
(click)="onChangeVersion(revision)"
style="cursor: pointer"
[ngClass]="{
selected: revision.version === selectedDefaultRevision.version
}"
>
<span style="font-size: 14px; line-height: 24px; font-weight: 400"
>Version - {{ revision.version }}</span
>
</mat-list-item>
</mat-list>
</mat-menu>
</div>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment