Skip to content

Commit

Permalink
2.1.0 dev merge (#98)
Browse files Browse the repository at this point in the history
* Initial commit

* updated simulators for styling

* branding updates for 2.1.0

* #92,warning icon-mywidgests,default theme branding

* issue #75- validating if simulator name exists

* issue#74- forced min not to be greater than max

* group template - Type support added

* updated power by logo

* fixed control by operation issue for browser based simulator

* updated 1018.0.151

* default brand for custom styling is updated

* added with Type option in dashboard catalog

* code refactor

* reverted to 1018.0.125

* widget catalog deprecation warning added

* updated home screen

* updated message

* added ids for automation

* device type added in simulator along with css and id changes for automation

* globalpresales logo added for branding

---------

Co-authored-by: YashPShah-swag <yash.pshah@softwareag.com>
  • Loading branch information
DarpanLalani and YashPShah-swag authored Nov 21, 2023
1 parent 9925143 commit cf8f46f
Show file tree
Hide file tree
Showing 79 changed files with 3,573 additions and 2,608 deletions.
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
registry=https://registry.npmjs.org/
@c8y:registry=https://download.cumulocity.com/npm/
4 changes: 2 additions & 2 deletions app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { SimulationStrategiesModule } from "./simulation-strategies/simulation-s
import { CustomWidgetsModule } from "./custom-widgets/custom-widgets.module";
import { interval } from 'rxjs';
import { SettingsService } from './builder/settings/settings.service';
import { WidgetsModule } from '@c8y/ngx-components/widgets';
import { cockpitWidgets } from '@c8y/ngx-components/widgets/cockpit';
@NgModule({
imports: [
// Upgrade module must be the first
Expand All @@ -41,7 +41,7 @@ import { WidgetsModule } from '@c8y/ngx-components/widgets';
DashboardUpgradeModule,
BuilderModule,
SimulationStrategiesModule,
WidgetsModule,
cockpitWidgets(),
CustomWidgetsModule
]
})
Expand Down
47 changes: 22 additions & 25 deletions builder/app-list/app-list.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,35 @@

<div class="card-group interact-grid">
<div class="col-xs-12 col-sm-4 col-md-3 col-lg-2" style="min-height: 194px;" *ngIf="userHasAdminRights">
<a class="card add-card clickable" id="addApplication" (click)="createAppWizard()">
<i c8yIcon="plus-square"></i><br>
Add application
</a>
<button (click)="createAppWizard()" class="card add-card" id="addApplication">
<i style="font-size: 36px;" c8y-icon="plus-circle" class="text-muted dlt-c8y-icon-plus-circle"></i>
<br>Add application
</button>
</div>
<div class="c8y-empty-state text-center" style="max-width:100%; flex-direction: column; align-items: center;" *ngIf="!isBusy && !applications.length">
<h3>No application to list.</h3>
</div>
<ng-container *ngIf="applications && applications.length > 0">
<div class="col-xs-12 col-sm-4 col-md-3 col-lg-2" *ngFor="let app of applications">
<div class="card clickable" (click)="openApp(app)">
<div class="dropdown card-actions" dropdown (click)="$event.stopPropagation()" *ngIf="userHasAdminRights">
<button title="Settings" id="appSettings-{{app.name}}" class="dropdown-toggle c8y-dropdown" dropdownToggle type="button">
<i c8yIcon="ellipsis-v"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right" *dropdownMenu role="menu">
<li role="menuitem">
<a class="dropdown-item" (click)="openApp(app, '/config')">
<i c8yIcon="edit"></i> Edit
</a>
</li>
<!-- <li role="menuitem">
<a class="dropdown-item" (click)="exportApp(app)">
<i c8yIcon="download"></i> Export
</a>
</li> -->
<li role="menuitem">
<a (click)="deleteApplication(app.id)" class="dropdown-item clickable">
<i c8yIcon="times"></i> Remove
</a>
</li>
</ul>
<div class="card-actions m-t-0">
<div class="dropdown" dropdown (click)="$event.stopPropagation()" *ngIf="userHasAdminRights">
<button title="Settings" id="appSettings-{{app.name}}" class="dropdown-toggle c8y-dropdown" dropdownToggle type="button">
<i c8yIcon="ellipsis-v"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right" *dropdownMenu role="menu">
<li role="menuitem">
<button type="button" title="Edit" (click)="openApp(app, '/config')">
<i c8yIcon="edit" ></i><span> Edit</span>
</button>
</li>
<li role="menuitem">
<button type="button" id="{{app.name}}-deleteApp" title="Remove" (click)="deleteApplication(app.id)">
<i c8yIcon="times" ></i> <span> Remove</span>
</button>
</li>
</ul>
</div>
</div>
<div class="card-block text-center" style="margin-bottom: 5px;">
<h1 style="margin: 15px 0 10px; font-size: 42px;"><c8y-app-icon [app]="app"></c8y-app-icon></h1>
Expand Down
8 changes: 4 additions & 4 deletions builder/app-list/app-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
} from "@c8y/client";
import { catchError, map } from "rxjs/operators";
import { from, Observable } from "rxjs";
import { AppStateService } from "@c8y/ngx-components";
import { AppStateService, PluginsService } from "@c8y/ngx-components";
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
import { NewApplicationModalComponent } from "./new-application-modal.component";
import { Router } from "@angular/router";
Expand All @@ -47,7 +47,7 @@ export class AppListComponent {
bsModalRef: BsModalRef;
isBusy = true;
constructor(private router: Router, private appService: ApplicationService,
private appStateService: AppStateService, private modalService: BsModalService,
private appStateService: AppStateService, private modalService: BsModalService, private pluginService: PluginsService,
private userService: UserService, private appListService: AppListService, private realTimeService: Realtime) {
this.userHasAdminRights = userService.hasRole(appStateService.currentUser.value, "ROLE_APPLICATION_MANAGEMENT_ADMIN")
this.appListService.refreshAppList$.subscribe(() => {
Expand All @@ -72,12 +72,12 @@ export class AppListComponent {
if (!this.allApplications || this.allApplications.length === 0) {
this.allApplications = (await this.appService.listByUser(this.appStateService.currentUser.value, { pageSize: 2000 })).data;
}
this.applications = this.allApplications.filter(app => app.hasOwnProperty('applicationBuilder'));
this.applications = this.allApplications.filter((app:IApplication)=> app.hasOwnProperty('applicationBuilder') && !this.pluginService.isPackage(app));
this.applications = this.applications.sort((a, b) => a.id > b.id ? 1 : -1);
this.isBusy = false;
} else {
this.allApplications = (await this.appService.listByUser(this.appStateService.currentUser.value, { pageSize: 2000 })).data;
this.applications = this.allApplications.filter(app => app.hasOwnProperty('applicationBuilder'));
this.applications = this.allApplications.filter((app:IApplication) => app.hasOwnProperty('applicationBuilder') && !this.pluginService.isPackage(app));
this.applications = this.applications.sort((a, b) => a.id > b.id ? 1 : -1);
this.isBusy = false;
}
Expand Down
155 changes: 155 additions & 0 deletions builder/application-binary.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* Copyright (c) 2023 Software AG, Darmstadt, Germany and/or its licensors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Injectable } from "@angular/core";
import { ApplicationService, ApplicationType, IApplication, IResultList, IUploadParamsOverride, TenantService } from "@c8y/client";
import { AppStateService, ModalService, Status, ZipService, gettext } from "@c8y/ngx-components";
import { BehaviorSubject, Observable } from 'rxjs';
import { kebabCase } from 'lodash-es';
import { SettingsService } from "./settings/settings.service";
import { DependencyDescription } from "./template-catalog/template-catalog.model";


@Injectable({ providedIn: 'root' })
export class ApplicationBinaryService {

private xhr: XMLHttpRequest;
progress: BehaviorSubject<number> = new BehaviorSubject<number>(null);

constructor(
private modal: ModalService,
private appStateService: AppStateService,
private applicationService: ApplicationService,
private zipService: ZipService,
private tenantService: TenantService,
private settingService: SettingsService
) { }

async createAppForMicroservice(binary, dependencies: DependencyDescription): Promise<IApplication> {
let appModel: any = {};
appModel = await this.getCumulocityJson(binary).toPromise();

const key = `${kebabCase(dependencies.id)}-key`
const contextPath = appModel?.contextPath || dependencies?.id.toLowerCase();

const appObj = {
resourcesUrl: '/',
type: ApplicationType.MICROSERVICE,
name: dependencies.id,
key,
contextPath
};

return (await this.applicationService.create({...appObj})).data;
}

private getCumulocityJson(archive: File): Observable<any> {
return this.zipService.getJsonData(archive, {
filename: 'cumulocity.json'
});
}

async uploadMicroservice(file: File, microservice: IApplication): Promise<void> {
const subscribeToCurrentTenant = await this.requestForSubscription();
const microserviceApp: IApplication = await this.uploadBinary(file, microservice);
if(microserviceApp) {
if(window && window['aptrinsic'] ){
window['aptrinsic']('track', 'gp_microservice_installed', {
"microserviceName": microserviceApp.name,
"tenantId": this.settingService.getTenantName()
});
}
}

await this.subscribeMicroservice(microservice, subscribeToCurrentTenant);
}

private async requestForSubscription(): Promise<boolean> {
try {
await this.modal.confirm(
gettext('Subscribe to microservice'),
gettext(
'You are about to subscribe to the microservice after upload. Do you want to subscribe to it?'
),
Status.INFO,
{ ok: gettext('Subscribe'), cancel: gettext("Don't subscribe") }
);
return true;
} catch (ex) {
return false;
}
}

private async subscribeMicroservice(
app: IApplication,
subscribeToCurrentTenant: boolean
): Promise<any> {
const tenant = (await this.tenantService.current()).data;
const applications = tenant.applications.references;

const isSubscribed = applications.some(({ application }) => application.id === app.id);
if (!isSubscribed && subscribeToCurrentTenant) {
try {
return await this.tenantService.subscribeApplication(tenant, app);
} catch (res) {
if (res.status === 409) {
throw Error("ALREADY_SUBSCRIBED");
}
}
} else if (isSubscribed && !subscribeToCurrentTenant) {
return this.tenantService.unsubscribeApplication(tenant, app);
}
}

async uploadBinary( file: File, app: IApplication ): Promise<IApplication> {
const appBinary = (await this.applicationService.binary(app).upload(file)).data;
return (await this.setActiveVersion(app, appBinary.id as string)).data;
}

setActiveVersion(app: IApplication, activeVersionId: string): Promise<IApplication> {
return this.applicationService.update({ id: app.id, activeVersionId });
}

getApplications(customFilter: any = {}): Promise<IResultList<IApplication>> {
const filter: object = {
pageSize: 2000,
withTotalPages: true
};
Object.assign(filter, customFilter);
const currentTenant = this.appStateService.currentTenant.value;
return this.applicationService.listByTenant(currentTenant.name, filter);
}

async verifyExistingMicroservices(name: string) {
const apps = (await this.getApplications()).data;
const ms = apps.filter(app => this.isMicroservice(app) && app.name === name);
return (ms && ms.length > 0 ? true: false);
}

isMicroservice(app: IApplication): boolean {
return app.type === 'MICROSERVICE';
}

isMicroserviceEnabled(appList: IApplication[]) {
const featureMSHosting = appList.find( app => app.contextPath == 'feature-microservice-hosting');
if(featureMSHosting) { return true;}
return false;

}
}

4 changes: 2 additions & 2 deletions builder/application-config/dashboard-config.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ <h3>No dashboards to list.</h3>
<div class="pt-15">Global Roles</div>
</div>
<div class="font-bold col-sm-2">
<div class="pt-15">Device(s)</div>
<div class="pt-15">Asset(s)</div>
</div>
<div class="col-sm-1">
<div class="pt-15">
Expand Down Expand Up @@ -195,7 +195,7 @@ <h3>No dashboards to list.</h3>
<div class="col">Tab Group</div>
<div class="col">Global Roles</div>
<div class="col">Icon</div>
<div class="col">Device(s)</div>
<div class="col">Asset(s)</div>
<div>
<i style="font-size:18px;" title="Edit Dashboard" c8yIcon="edit"></i>
<i c8yIcon="delete" title="Delete Dashboard"
Expand Down
15 changes: 11 additions & 4 deletions builder/application-config/dashboard-config.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { DOCUMENT } from "@angular/common";
import { moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { AppDataService } from "../app-data.service";
import { Clipboard } from '@angular/cdk/clipboard';

import { IconSelectorService } from "@c8y/ngx-components/icon-selector";
export interface DashboardConfig {
id: string,
name: string,
Expand All @@ -49,6 +49,7 @@ export interface DashboardConfig {
icon: string,
deviceId?: string,
roles?: any,
templateType?: number,
groupTemplate: {
groupId: string
},
Expand Down Expand Up @@ -108,13 +109,17 @@ export class DashboardConfigComponent implements OnInit, OnDestroy {

constructor(
private appIdService: AppIdService, private appService: ApplicationService, private appStateService: AppStateService,
private brandingService: BrandingService, private inventoryService: InventoryService, private navigation: AppBuilderNavigationService,
private inventoryService: InventoryService, private navigation: AppBuilderNavigationService,
private iconSelector: IconSelectorService, private brandingService: BrandingService,
private modalService: BsModalService, private alertService: AlertService, private settingsService: SettingsService,
private accessRightsService: AccessRightsService, private userService: UserService, private appDataService: AppDataService,
@Inject(DOCUMENT) private document: Document, private renderer: Renderer2, private cd: ChangeDetectorRef, private clipboard: Clipboard
) {
this.app = combineLatest([appIdService.appIdDelayedUntilAfterLogin$, this.refreshApp]).pipe(
map(([appId]) => appId),
tap(appId => {
this.appDataService.forceUpdate = true;
}),
switchMap(appId => from(
this.appDataService.getAppDetails(appId)
)),
Expand Down Expand Up @@ -144,7 +149,8 @@ export class DashboardConfigComponent implements OnInit, OnDestroy {
let count = 0;
this.appSubscription = this.app.pipe(first()).
subscribe(app => {
if (app.applicationBuilder.branding.enabled && (app.applicationBuilder.selectedTheme && app.applicationBuilder.selectedTheme !== 'Default')) {
if (app.applicationBuilder.branding?.enabled && (app.applicationBuilder.selectedTheme && app.applicationBuilder.selectedTheme !== 'Default'
&& app.applicationBuilder.selectedTheme !== 'Classic')) {
this.applyTheme = true;
this.renderer.addClass(this.document.body, 'dashboard-body-theme');
} else {
Expand Down Expand Up @@ -389,7 +395,8 @@ export class DashboardConfigComponent implements OnInit, OnDestroy {
dashboardType: 'group-template'
} : {
dashboardType: 'standard'
})
}),
templateType: dashboard.templateType
}
});
this.bsModalRef.content.onSave.subscribe((isReloadRequired: boolean) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ <h4 class="text-uppercase" style="margin:0; letter-spacing: 0.15em;">Edit Dashbo
</ng-select>
</div>
<div class="form-group" style="min-height: 50px;" *ngIf="dashboardType === 'group-template' else nonGroupTemplate">
<label for="group"><span>Group </span></label>
<label for="group"><span>Group/Asset/Type </span></label>
<!-- <input type="text" class="form-control" id="group" name="group" placeholder="e.g. 12345" [(ngModel)]="deviceId"> -->
<device-selector id="groupId" name="groupId" [isGroup]="true" [(value)]="deviceName" [placeHolder]="'Type your Group Name'" [required]="true"
(selectedDevice)= "getSelectedDevice($event)" (onBlurDevice)= "getSelectedDevice($event)"></device-selector>
<device-selector id="groupId" name="groupId" [isGroup]="true" [isTypeSupport]="true" [(value)]="deviceName" [placeHolder]="'Type your Group Name'" [required]="true"
(selectedDevice)= "getSelectedGroup($event)" (onBlurDevice)= "getSelectedGroup($event)" [isTypeSelected]="(templateType == 2)"
[placeHolderType]="'Enter your Asset/Device type'" (selectedType)= "getSelectedType($event)" (onBlurType)= "getSelectedType($event)"></device-selector>
</div>
<ng-template #nonGroupTemplate>
<div class="form-group" style="min-height: 50px;" >
Expand Down
Loading

0 comments on commit cf8f46f

Please sign in to comment.