Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/IOT-1583: Move application #167

Merged
merged 8 commits into from
Sep 13, 2024
14 changes: 14 additions & 0 deletions src/app/admin/organisation/organisation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ export class OrganisationService {
});
}

getMultipleWithApplicationAdmin(
limit: number = 1000,
offset: number = 0,
orderByColumn?: string,
orderByDirection?: string
): Observable<OrganisationGetManyResponse> {
return this.restService.get(`${this.URL}/applicationAdmin`, {
limit,
offset,
orderOn: orderByColumn,
sort: orderByDirection,
});
}

delete(id: number) {
return this.restService.delete(this.URL, id);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<div class="application-change-organization-dialog">
<h1 mat-dialog-title>{{ "APPLICATION.CHANGE-ORGANIZATION.TITLE" | translate }}</h1>
<div mat-dialog-content>
<label class="form-label" for="organizationSelect">{{
"APPLICATION.CHANGE-ORGANIZATION.CHOOSE-ORGANIZATION" | translate
}}</label>
<mat-select
id="organizationSelect"
class="form-control"
panelClass="overflow-x-hidden"
[(value)]="application.organizationId"
[compareWith]="compare"
(selectionChange)="onOrganizationChange()"
>
<mat-option *ngFor="let organization of filteredOrganizations | async" [value]="organization.id">
{{ organization.name }}
</mat-option>
</mat-select>
<label class="form-label" for="permissionSelect">{{
"APPLICATION.CHANGE-ORGANIZATION.CHOOSE-USER-GROUPS" | translate
}}</label>
<div *ngIf="permissions.length > 0">
<mat-select
id="permissionSelect"
class="form-control"
[multiple]="true"
panelClass="overflow-x-hidden"
[(value)]="application.permissionIds"
[compareWith]="compare"
>
<mat-option *ngFor="let permission of filteredPermissionsMulti | async" [value]="permission.id">
{{ permission.name }}
</mat-option>
</mat-select>
<mat-hint>{{ "APPLICATION.CHANGE-ORGANIZATION.USER-GROUP-AUTO-SELECT" | translate }}</mat-hint>
</div>
</div>
<div mat-dialog-actions class="d-flex flex-row">
<button (click)="onSubmit()" class="btn btn-primary">
{{ "GEN.SAVE" | translate }}
</button>
<button mat-dialog-close [mat-dialog-close]="false" class="btn btn-secondary ml-2">
{{ "GEN.CANCEL" | translate }}
</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.application-change-organization-dialog {
width: 50vw;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Component, Inject, OnInit } from "@angular/core";
import { UntypedFormControl } from "@angular/forms";
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
import { MatSnackBar } from "@angular/material/snack-bar";
import { Organisation } from "@app/admin/organisation/organisation.model";
import { OrganisationService } from "@app/admin/organisation/organisation.service";
import { PermissionResponse } from "@app/admin/permission/permission.model";
import { PermissionService } from "@app/admin/permission/permission.service";
import { Application, UpdateApplicationOrganization } from "@applications/application.model";
import { ApplicationService } from "@applications/application.service";
import { TranslateService } from "@ngx-translate/core";
import { ApplicationDialogModel } from "@shared/models/dialog.model";
import { SharedVariableService } from "@shared/shared-variable/shared-variable.service";
import { ReplaySubject, Subscription } from "rxjs";

@Component({
selector: "app-change-organization-dialog",
templateUrl: "./application-change-organization-dialog.component.html",
styleUrls: ["./application-change-organization-dialog.component.scss"],
})
export class ApplicationChangeOrganizationDialogComponent implements OnInit {
public applicationsSubscription: Subscription;
public permissionsSubscription: Subscription;
public organizationsSubscription: Subscription;
public application: UpdateApplicationOrganization;
public permissions: PermissionResponse[];
public organizations: Organisation[];
public filteredPermissionsMulti: ReplaySubject<PermissionResponse[]> = new ReplaySubject<PermissionResponse[]>(1);
public filteredOrganizations: ReplaySubject<Organisation[]> = new ReplaySubject<Organisation[]>(1);

constructor(
private applicationService: ApplicationService,
public translate: TranslateService,
private permissionService: PermissionService,
private organizationService: OrganisationService,
private sharedVariableService: SharedVariableService,
private snackBar: MatSnackBar,
private dialog: MatDialogRef<ApplicationChangeOrganizationDialogComponent>,
@Inject(MAT_DIALOG_DATA) public dialogModel: ApplicationDialogModel
) {
this.application = {
organizationId: this.dialogModel.organizationId ?? this.sharedVariableService.getSelectedOrganisationId(),
permissionIds: [],
};
}

ngOnInit(): void {
this.translate.use("da");
if (this.dialogModel.applicationId) {
this.getApplication(this.dialogModel.applicationId);
}
this.getOrganizations();
this.getPermissions();
}

getApplication(id: number): void {
this.applicationsSubscription = this.applicationService.getApplication(id).subscribe((application: Application) => {
this.application.permissionIds = application.permissionIds;
});
}

getOrganizations() {
this.organizationsSubscription = this.organizationService.getMultipleWithApplicationAdmin().subscribe(res => {
this.organizations = res.data;
this.filteredOrganizations.next(this.organizations.slice());
});
}

getPermissions() {
this.permissionsSubscription = this.permissionService.getPermissions(1000, 0).subscribe(res => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dit get permissions her henter kun for de organisationer hvor brugeren har userAdmin rettighed, hvilket vil sige at man ikke altid kan se alle da permissions ikke er herakiske. (Den bør nok laves om til at lave et fetch for den givne organisations permissions hvis man er applikations admin). Alternativt skal vi lige diskutere den rettighed her med Mogens

this.permissions = res.data.sort((a, b) => a.name.localeCompare(b.name, "da-DK", { numeric: true }));
this.filteredPermissionsMulti.next(
this.permissions.filter(p => p?.organization?.id === this?.application?.organizationId)
);
});
}

public compare(o1: any, o2: any): boolean {
return o1 === o2;
}

onOrganizationChange() {
this.filteredPermissionsMulti.next(
this.permissions.filter(p => p?.organization?.id === this?.application?.organizationId)
);
this.filteredPermissionsMulti.subscribe(res => {
this.application.permissionIds = res
.filter(permission => permission.automaticallyAddNewApplications)
.map(permission => permission.id);
});
}

onSubmit() {
this.applicationsSubscription = this.applicationService
.updateApplicationOrganization(this.application, this.dialogModel.applicationId)
.subscribe(savedApplication => {
this.snackBar.open(
this.translate.instant("APPLICATION.CHANGE-ORGANIZATION.SNACKBAR-SAVED", {
applicationName: savedApplication.name,
organizationName: savedApplication.belongsTo.name,
}),
"",
{
duration: 10000,
}
);
this.dialog.close(true);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ <h3>{{ "APPLICATION.DETAILS" | translate }}</h3>
</div>
</div>

<nav mat-tab-nav-bar [tabPanel]="tabPanel" >
<nav mat-tab-nav-bar [tabPanel]="tabPanel">
<a
mat-tab-link
*ngFor="let link of navTabs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import { map } from "rxjs/operators";
import { SharedVariableService } from "@shared/shared-variable/shared-variable.service";
import { ChirpstackGatewayService } from "@shared/services/chirpstack-gateway.service";
import { Gateway, GatewayResponseMany } from "@app/gateway/gateway.model";
import { MatDialog } from "@angular/material/dialog";
import { ApplicationChangeOrganizationDialogComponent } from "../application-change-organization-dialog/application-change-organization-dialog.component";
import { ApplicationDialogModel } from "@shared/models/dialog.model";

@Component({
selector: "app-application",
Expand Down Expand Up @@ -68,7 +71,8 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
private deleteDialogService: DeleteDialogService,
private restService: RestService,
private sharedVariableService: SharedVariableService,
private chirpstackGatewayService: ChirpstackGatewayService
private chirpstackGatewayService: ChirpstackGatewayService,
private changeOrganizationDialog: MatDialog
) {}

ngOnInit(): void {
Expand All @@ -79,7 +83,16 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
label: "",
editRouterLink: "../edit-application/" + this.id,
isErasable: true,
extraOptions: [],
};

this.translate.get("APPLICATION.CHANGE-ORGANIZATION.TITLE").subscribe(translation => {
this.dropdownButton.extraOptions.push({
id: this.id,
label: translation,
onClick: () => this.onOpenChangeOrganizationDialog(),
});
});
}

this.translate
Expand Down Expand Up @@ -193,6 +206,15 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
});
}

onOpenChangeOrganizationDialog() {
this.changeOrganizationDialog.open(ApplicationChangeOrganizationDialogComponent, {
data: {
applicationId: this.id,
organizationId: this.application.belongsTo.id,
} as ApplicationDialogModel,
});
}

bindApplication(id: number): void {
this.applicationsSubscription = this.applicationService.getApplication(id).subscribe(application => {
this.application = application;
Expand Down
5 changes: 5 additions & 0 deletions src/app/applications/application.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,8 @@ export interface ApplicationData {
ok?: boolean;
count?: number;
}

export class UpdateApplicationOrganization {
public organizationId: number;
public permissionIds: number[];
}
8 changes: 7 additions & 1 deletion src/app/applications/application.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from "@angular/core";
import { Application, ApplicationData } from "@applications/application.model";
import { Application, ApplicationData, UpdateApplicationOrganization } from "@applications/application.model";
import { RestService } from "../shared/services/rest.service";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
Expand Down Expand Up @@ -76,4 +76,10 @@ export class ApplicationService {
deleteApplication(id: number) {
return this.restService.delete("application", id);
}

updateApplicationOrganization(body: UpdateApplicationOrganization, id: number): Observable<Application> {
return this.restService.put("application/updateApplicationOrganization", body, id, {
observe: "response",
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@
"APPLICATION-TABLE-ROW.EDIT" | translate
}}</a>
</li>
<li class="dropdown-item">
<a (click)="onOpenChangeOrganizationDialog(element.id)" routerLinkActive="active">{{
"APPLICATION.CHANGE-ORGANIZATION.TITLE" | translate
}}</a>
</li>
<li class="dropdown-item">
<a (click)="deleteApplication(element.id)" [routerLink]="[]">{{
"APPLICATION-TABLE-ROW.DELETE" | translate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import { ApplicationDeviceType } from "@applications/models/application-device-t
import { Datatarget } from "@applications/datatarget/datatarget.model";
import { faFlag } from "@fortawesome/free-solid-svg-icons";
import { TableColumn } from "@shared/types/table.type";
import { MatDialog } from "@angular/material/dialog";
import { ApplicationDialogModel } from "@shared/models/dialog.model";
import { ApplicationChangeOrganizationDialogComponent } from "@applications/application-change-organization-dialog/application-change-organization-dialog.component";

const columnDefinitions: TableColumn[] = [
{
Expand Down Expand Up @@ -144,7 +147,8 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit {
private applicationService: ApplicationService,
private router: Router,
private deleteDialogService: DeleteDialogService,
private cdRef: ChangeDetectorRef
private cdRef: ChangeDetectorRef,
private changeOrganizationDialog: MatDialog
) {}

ngOnInit() {
Expand Down Expand Up @@ -268,5 +272,19 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit {
return !!result;
}

onOpenChangeOrganizationDialog(id: number) {
const dialog = this.changeOrganizationDialog.open(ApplicationChangeOrganizationDialogComponent, {
data: {
applicationId: id,
} as ApplicationDialogModel,
});

dialog.afterClosed().subscribe(res => {
if (!res) return;

location.reload();
fcv-iteratorIt marked this conversation as resolved.
Show resolved Hide resolved
});
}

protected readonly columnDefinitions = columnDefinitions;
}
2 changes: 2 additions & 0 deletions src/app/applications/applications.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { PipesModule } from "@shared/pipes/pipes.module";
import { ApplicationsTableComponent } from "./applications-list/applications-table/applications-table.component";
import { MulticastModule } from "./multicast/multicast.module";
import { ReactiveFormsModule } from "@angular/forms";
import { ApplicationChangeOrganizationDialogComponent } from "./application-change-organization-dialog/application-change-organization-dialog.component";

@NgModule({
declarations: [
Expand All @@ -28,6 +29,7 @@ import { ReactiveFormsModule } from "@angular/forms";
ApplicationsListComponent,
ApplicationsTableComponent,
BulkImportComponent,
ApplicationChangeOrganizationDialogComponent,
],
exports: [ApplicaitonsRoutingModule, ApplicationsComponent, ApplicationsTableComponent],
imports: [
Expand Down
3 changes: 3 additions & 0 deletions src/app/shared/components/top-bar/top-bar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ export class TopBarComponent implements OnInit {

onClickExtraDropdownOption(id: string) {
this.extraDropdownOptions.emit(id);
const extraDropdownOption = this.dropDownButton.extraOptions.find(opt => opt.id === id);

extraDropdownOption?.onClick();
}

public goToHelp() {
Expand Down
5 changes: 5 additions & 0 deletions src/app/shared/models/dialog.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ export class DialogModel {
export class WelcomeDialogModel {
hasSomePermission: boolean;
}

export class ApplicationDialogModel {
applicationId: number;
organizationId?: number;
}
1 change: 1 addition & 0 deletions src/app/shared/models/dropdown-button.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PermissionType } from "@app/admin/permission/permission.model";
export interface ExtraDropdownOption {
id: string | number;
label: string;
onClick?: () => void
}

export interface DropdownButton {
Expand Down
Loading
Loading