@c8y/tutorial 1020.40.0 → 1021.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cumulocity.config.ts +7 -1
- package/package.json +11 -11
- package/src/__mocks/global-mocks/inventory.interceptor.ts +3 -0
- package/src/__mocks/mock.module.ts +15 -4
- package/src/__mocks/scoped-mocks/typeahead.ts +70 -0
- package/src/app/app.module.ts +0 -2
- package/src/dynamic-forms/json-schema-example/json-schema-example.component.ts +10 -8
- package/src/grids/server-grid-example/server-grid-example.component.ts +8 -4
- package/src/hooks/tabs/awesome/awesome.component.html +1 -1
- package/src/hooks/tabs/inline/inline-one.component.ts +13 -0
- package/src/hooks/tabs/inline/inline-two.component.ts +13 -0
- package/src/hooks/tabs/inline/inline.module.ts +26 -0
- package/src/hooks/tabs/outstanding/outstanding.component.html +13 -2
- package/src/hooks/tabs/outstanding/outstanding.component.ts +2 -1
- package/src/hooks/tabs/tab.ts +20 -4
- package/src/hooks/tabs/tabs.module.ts +18 -13
- package/src/i18n.ts +1 -1
- package/src/main.ts +5 -10
- package/src/selector/alarm-event-selector-example/alarm-event-selector.component.ts +5 -2
- package/src/selector/datapoint-selection-example/general-example/datapoint-selection-example.component.ts +2 -2
- package/src/typeahead/typeahead-example.component.html +45 -0
- package/src/typeahead/typeahead-example.component.ts +49 -0
- package/src/typeahead/typeahead-example.module.ts +19 -0
- package/src/dashboard-tabs/dashboard-tabs.component.ts +0 -95
- package/src/dashboard-tabs/dashboard-tabs.module.ts +0 -20
- package/src/dashboard-tabs/index.ts +0 -1
- /package/{src → public}/favicon.ico +0 -0
package/cumulocity.config.ts
CHANGED
|
@@ -729,6 +729,13 @@ export default {
|
|
|
729
729
|
path: './src/pagination/pagination-example.module.ts',
|
|
730
730
|
description: 'This is an example for pagination.',
|
|
731
731
|
scope: 'self'
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
name: 'Typeahead',
|
|
735
|
+
module: 'TypeaheadExampleModule',
|
|
736
|
+
path: './src/typeahead/typeahead-example.module.ts',
|
|
737
|
+
description: 'This is an example for the typeahead component.',
|
|
738
|
+
scope: 'self'
|
|
732
739
|
}
|
|
733
740
|
]
|
|
734
741
|
},
|
|
@@ -742,7 +749,6 @@ export default {
|
|
|
742
749
|
},
|
|
743
750
|
// The embedded.css is used by codex for iframe embeddings.
|
|
744
751
|
copy: [{ from: './node_modules/@c8y/style/embedded.css', to: './embedded.css' }],
|
|
745
|
-
brandingEntry: './src/branding/branding.less',
|
|
746
752
|
federation: [
|
|
747
753
|
'@angular/animations',
|
|
748
754
|
'@angular/cdk',
|
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c8y/tutorial",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1021.0.4",
|
|
4
4
|
"description": "This package is used to scaffold a tutorial for Cumulocity IoT Web SDK which explains a lot of concepts.",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@c8y/style": "
|
|
7
|
-
"@c8y/ngx-components": "
|
|
8
|
-
"@c8y/client": "
|
|
9
|
-
"@c8y/bootstrap": "
|
|
10
|
-
"@angular/cdk": "^
|
|
11
|
-
"ngx-bootstrap": "
|
|
6
|
+
"@c8y/style": "1021.0.4",
|
|
7
|
+
"@c8y/ngx-components": "1021.0.4",
|
|
8
|
+
"@c8y/client": "1021.0.4",
|
|
9
|
+
"@c8y/bootstrap": "1021.0.4",
|
|
10
|
+
"@angular/cdk": "^18.2.10",
|
|
11
|
+
"ngx-bootstrap": "18.0.0",
|
|
12
12
|
"leaflet": "1.9.4",
|
|
13
|
-
"rxjs": "^7.
|
|
13
|
+
"rxjs": "^7.8.1"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@c8y/options": "
|
|
17
|
-
"@c8y/devkit": "
|
|
16
|
+
"@c8y/options": "1021.0.4",
|
|
17
|
+
"@c8y/devkit": "1021.0.4"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@angular/common": ">=
|
|
20
|
+
"@angular/common": ">=18 <19"
|
|
21
21
|
},
|
|
22
22
|
"author": "Cumulocity GmbH"
|
|
23
23
|
}
|
|
@@ -94,6 +94,9 @@ export class InventoryInterceptor implements HttpInterceptor {
|
|
|
94
94
|
c8y_IsAssetType: () => ({
|
|
95
95
|
managedObjects: [generateAssetType()]
|
|
96
96
|
}),
|
|
97
|
+
c8yAssetTypesCacheInvalidator: () => ({
|
|
98
|
+
managedObjects: [generateRandomMo()]
|
|
99
|
+
}),
|
|
97
100
|
c8y_IsDeviceGroup: () => ({
|
|
98
101
|
managedObjects: [
|
|
99
102
|
...[...Array(5)].map(() => (Math.random() < 0.5 ? generateSubGroup() : generateAsset()))
|
|
@@ -10,14 +10,15 @@ import {
|
|
|
10
10
|
import { InventoryInterceptor } from './global-mocks/inventory.interceptor';
|
|
11
11
|
import { MeasurementsInterceptor } from './global-mocks/measurements.interceptor';
|
|
12
12
|
import { API_MOCK_CONFIG, ApiMockConfig } from './mock.model';
|
|
13
|
+
import { RealtimeSubjectServiceWithMocking } from './mock.realtime';
|
|
13
14
|
import { MockService } from './mock.service';
|
|
14
|
-
import { NamedContextDashboardInterceptor } from './scoped-mocks/named-context-dashboard';
|
|
15
15
|
import { ContextDashboardInterceptor } from './scoped-mocks/context-dashboard';
|
|
16
|
-
import { ServerSideDataGridInterceptor } from './scoped-mocks/server-side-data-grid';
|
|
17
16
|
import { DeviceDataGridInterceptor } from './scoped-mocks/device-data-grid';
|
|
18
|
-
import { ServiceDashboardInterceptor } from './scoped-mocks/service-dashboard';
|
|
19
|
-
import { RealtimeSubjectServiceWithMocking } from './mock.realtime';
|
|
20
17
|
import { ListsInterceptor } from './scoped-mocks/lists';
|
|
18
|
+
import { NamedContextDashboardInterceptor } from './scoped-mocks/named-context-dashboard';
|
|
19
|
+
import { ServerSideDataGridInterceptor } from './scoped-mocks/server-side-data-grid';
|
|
20
|
+
import { ServiceDashboardInterceptor } from './scoped-mocks/service-dashboard';
|
|
21
|
+
import { TypeaheadInterceptor } from './scoped-mocks/typeahead';
|
|
21
22
|
// import { BoilerplateInterceptor } from './scoped-mocks/boilerplate';
|
|
22
23
|
@NgModule({
|
|
23
24
|
imports: [CoreModule, CommonModule],
|
|
@@ -63,6 +64,16 @@ import { ListsInterceptor } from './scoped-mocks/lists';
|
|
|
63
64
|
} as ApiMockConfig,
|
|
64
65
|
multi: true
|
|
65
66
|
},
|
|
67
|
+
{
|
|
68
|
+
provide: API_MOCK_CONFIG,
|
|
69
|
+
useValue: {
|
|
70
|
+
id: 'typeahaed-interceptor',
|
|
71
|
+
path: 'typeahead',
|
|
72
|
+
mockService: TypeaheadInterceptor,
|
|
73
|
+
debug: true
|
|
74
|
+
} as ApiMockConfig,
|
|
75
|
+
multi: true
|
|
76
|
+
},
|
|
66
77
|
{
|
|
67
78
|
provide: API_MOCK_CONFIG,
|
|
68
79
|
useValue: {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { IFetchResponse } from '@c8y/client';
|
|
2
|
+
import { ApiCall, HttpHandler, HttpInterceptor } from '@c8y/ngx-components/api';
|
|
3
|
+
import { generateResponse, handleRequest } from '../utils/common';
|
|
4
|
+
import { Observable } from 'rxjs';
|
|
5
|
+
import { generateDevice } from '../utils/generators/managedObjects';
|
|
6
|
+
import { filterObjects } from '../utils/grid';
|
|
7
|
+
|
|
8
|
+
export class TypeaheadInterceptor implements HttpInterceptor {
|
|
9
|
+
intercept(req: ApiCall, next: HttpHandler): Observable<IFetchResponse> {
|
|
10
|
+
return handleRequest(req, next, 'inventory/managedObjects', {
|
|
11
|
+
POST: this.mockPOST.bind(this),
|
|
12
|
+
PUT: this.mockPUT.bind(this),
|
|
13
|
+
GET: this.mockGET.bind(this)
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
mockPOST(_requestDescriptor: string) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
mockPUT(_requestDescriptor: string) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private async mockGET(_requestDescriptor: string) {
|
|
26
|
+
// extra long timeout, to show the usage of c8yFor
|
|
27
|
+
await new Promise(r => setTimeout(r, 100));
|
|
28
|
+
|
|
29
|
+
const responseGenerators = this.getResponseGenerators();
|
|
30
|
+
|
|
31
|
+
for (const urlPart in responseGenerators) {
|
|
32
|
+
if (_requestDescriptor.includes(urlPart)) {
|
|
33
|
+
const pageSize = _requestDescriptor.match(/\"pageSize\"\:(\d+)/)
|
|
34
|
+
? parseInt(_requestDescriptor.match(/\"pageSize\"\:(\d+)/)[1])
|
|
35
|
+
: null;
|
|
36
|
+
|
|
37
|
+
const generatorResult = responseGenerators[urlPart](pageSize);
|
|
38
|
+
if (generatorResult) {
|
|
39
|
+
const filteredData = filterObjects(generatorResult.managedObjects, _requestDescriptor);
|
|
40
|
+
|
|
41
|
+
const currentPage = _requestDescriptor.match(/\"currentPage\"\:(\d+)/)
|
|
42
|
+
? parseInt(_requestDescriptor.match(/\"currentPage\"\:(\d+)/)[1])
|
|
43
|
+
: null;
|
|
44
|
+
|
|
45
|
+
return generateResponse(
|
|
46
|
+
() => ({
|
|
47
|
+
managedObjects: filteredData,
|
|
48
|
+
...(!!currentPage && currentPage !== 5 && { next: `currentPage=${currentPage + 1}` })
|
|
49
|
+
}),
|
|
50
|
+
{
|
|
51
|
+
totalPages: 30,
|
|
52
|
+
...(!!pageSize && { pageSize }),
|
|
53
|
+
...(!!currentPage && { currentPage }),
|
|
54
|
+
...(!!currentPage && currentPage !== 5 && { next: `currentPage=${currentPage + 1}` })
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private getResponseGenerators() {
|
|
64
|
+
return {
|
|
65
|
+
pageSize: pageSize => ({
|
|
66
|
+
managedObjects: [...[...Array(pageSize || 10)].map(() => generateDevice())]
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/app/app.module.ts
CHANGED
|
@@ -24,7 +24,6 @@ import { WidgetResolversModule } from '../widget-resolvers';
|
|
|
24
24
|
import { MockModule } from '../__mocks';
|
|
25
25
|
import { IntroductionModule } from '../provider-configuration';
|
|
26
26
|
import { TranslationsModule } from '../translations';
|
|
27
|
-
import { DashboardTabsModule } from '../dashboard-tabs';
|
|
28
27
|
import { BreadcrumbsNodeModule } from '../breadcrumbs/breadcrumbs.module';
|
|
29
28
|
import { AlarmsModule } from '@c8y/ngx-components/alarms';
|
|
30
29
|
|
|
@@ -61,7 +60,6 @@ import { AlarmsModule } from '@c8y/ngx-components/alarms';
|
|
|
61
60
|
}),
|
|
62
61
|
RedirectToLastRouteModule,
|
|
63
62
|
MockModule,
|
|
64
|
-
DashboardTabsModule,
|
|
65
63
|
BreadcrumbsNodeModule,
|
|
66
64
|
AlarmsModule.config({ hybrid: false })
|
|
67
65
|
],
|
|
@@ -77,18 +77,20 @@ const exampleSchema: object = {
|
|
|
77
77
|
export class JSONSchemaExampleComponent {
|
|
78
78
|
form = new FormGroup({});
|
|
79
79
|
model = {};
|
|
80
|
-
fields: FormlyFieldConfig[]
|
|
81
|
-
this.jsonschema.toFieldConfig(exampleSchema, {
|
|
82
|
-
map(mappedField: FormlyFieldConfig, _mapSource: JSONSchema7) {
|
|
83
|
-
return mappedField;
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
];
|
|
80
|
+
fields: FormlyFieldConfig[];
|
|
87
81
|
|
|
88
82
|
constructor(
|
|
89
83
|
public jsonschema: C8yJSONSchema,
|
|
90
84
|
private readonly changeDetectorRef: ChangeDetectorRef
|
|
91
|
-
) {
|
|
85
|
+
) {
|
|
86
|
+
this.fields = [
|
|
87
|
+
this.jsonschema.toFieldConfig(exampleSchema, {
|
|
88
|
+
map(mappedField: FormlyFieldConfig, _mapSource: JSONSchema7) {
|
|
89
|
+
return mappedField;
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
];
|
|
93
|
+
}
|
|
92
94
|
|
|
93
95
|
ngAfterViewChecked(): void {
|
|
94
96
|
this.changeDetectorRef.detectChanges();
|
|
@@ -66,18 +66,22 @@ export class ServerGridExampleComponent implements GridConfigContextProvider {
|
|
|
66
66
|
hover: true
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
columns: Column[]
|
|
70
|
-
pagination: Pagination
|
|
69
|
+
columns: Column[];
|
|
70
|
+
pagination: Pagination;
|
|
71
71
|
infiniteScroll: LoadMoreMode = 'auto';
|
|
72
72
|
serverSideDataCallback: any;
|
|
73
73
|
|
|
74
74
|
refresh: EventEmitter<any> = new EventEmitter<any>();
|
|
75
75
|
|
|
76
76
|
selectable = true;
|
|
77
|
-
actionControls: ActionControl[]
|
|
78
|
-
bulkActionControls: BulkActionControl[]
|
|
77
|
+
actionControls: ActionControl[];
|
|
78
|
+
bulkActionControls: BulkActionControl[];
|
|
79
79
|
|
|
80
80
|
constructor(private service: ServerGridExampleService) {
|
|
81
|
+
this.columns = this.service.getColumns();
|
|
82
|
+
this.pagination = this.service.getPagination();
|
|
83
|
+
this.actionControls = this.service.getActionControls();
|
|
84
|
+
this.bulkActionControls = this.service.getBulkActionControls();
|
|
81
85
|
// we're setting up `serverSideDataCallback` to execute a method from this component with bound `this`
|
|
82
86
|
this.serverSideDataCallback = this.onDataSourceModifier.bind(this);
|
|
83
87
|
// we're setting up `onRefreshClick` to be executed on refresh event
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!-- The c8y-title component will display the given string (here: "Awesome Tab") in the header as title -->
|
|
2
2
|
<c8y-title>Awesome tab</c8y-title>
|
|
3
|
-
<div class="card">
|
|
3
|
+
<div class="card m-t-24">
|
|
4
4
|
<div class="card-block">
|
|
5
5
|
<p>This is the second tab we added with the <code>hookTab</code>.</p>
|
|
6
6
|
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { HeaderModule } from '@c8y/ngx-components';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'tut-inline1',
|
|
6
|
+
template: `
|
|
7
|
+
<c8y-title>Inline 1 Component </c8y-title>
|
|
8
|
+
<p>Hello from inline tab 1</p>
|
|
9
|
+
`,
|
|
10
|
+
standalone: true,
|
|
11
|
+
imports: [HeaderModule]
|
|
12
|
+
})
|
|
13
|
+
export class InlineOne {}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { HeaderModule } from '@c8y/ngx-components';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'tut-inline2',
|
|
6
|
+
template: `
|
|
7
|
+
<c8y-title>Inline 2 Component </c8y-title>
|
|
8
|
+
<p>Hello from inline tab 2</p>
|
|
9
|
+
`,
|
|
10
|
+
standalone: true,
|
|
11
|
+
imports: [HeaderModule]
|
|
12
|
+
})
|
|
13
|
+
export class InlineTwo {}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { RouterModule, Routes } from '@angular/router';
|
|
4
|
+
import { InlineTwo } from './inline-two.component';
|
|
5
|
+
import { InlineOne } from './inline-one.component';
|
|
6
|
+
|
|
7
|
+
const routes: Routes = [
|
|
8
|
+
{
|
|
9
|
+
path: '',
|
|
10
|
+
redirectTo: 'inline1',
|
|
11
|
+
pathMatch: 'full'
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: 'inline1',
|
|
15
|
+
component: InlineOne
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
path: 'inline2',
|
|
19
|
+
component: InlineTwo
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
@NgModule({
|
|
24
|
+
imports: [CommonModule, RouterModule.forChild(routes)]
|
|
25
|
+
})
|
|
26
|
+
export class InlineModule {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!-- The c8y-title component will display the given string (here: "Outstanding Tab") in the header as title -->
|
|
2
2
|
<c8y-title>Outstanding tab</c8y-title>
|
|
3
|
-
<div class="card">
|
|
3
|
+
<div class="card m-t-24">
|
|
4
4
|
<div class="card-block">
|
|
5
5
|
<p>
|
|
6
6
|
This is the first tab we added with the
|
|
@@ -13,10 +13,21 @@
|
|
|
13
13
|
toggles the orientation for the whole application:
|
|
14
14
|
</p>
|
|
15
15
|
<button
|
|
16
|
-
class="btn btn-primary"
|
|
16
|
+
class="btn btn-primary m-t-16"
|
|
17
17
|
(click)="toggleOrientation()"
|
|
18
18
|
>
|
|
19
19
|
Toggle orientation
|
|
20
20
|
</button>
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
23
|
+
<div class="card">
|
|
24
|
+
<div class="p-relative">
|
|
25
|
+
<c8y-tabs-outlet
|
|
26
|
+
orientation="horizontal"
|
|
27
|
+
outletName="inline-example"
|
|
28
|
+
></c8y-tabs-outlet>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="p-16" style="min-height: 100px">
|
|
31
|
+
<router-outlet></router-outlet>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
|
+
import { RouterModule } from '@angular/router';
|
|
2
3
|
import { CoreModule, OptionsService, TabsService } from '@c8y/ngx-components';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -12,7 +13,7 @@ import { CoreModule, OptionsService, TabsService } from '@c8y/ngx-components';
|
|
|
12
13
|
selector: 'outstanding',
|
|
13
14
|
templateUrl: './outstanding.component.html',
|
|
14
15
|
standalone: true,
|
|
15
|
-
imports: [CoreModule]
|
|
16
|
+
imports: [CoreModule, RouterModule]
|
|
16
17
|
})
|
|
17
18
|
export class OutstandingComponent {
|
|
18
19
|
constructor(
|
package/src/hooks/tabs/tab.ts
CHANGED
|
@@ -7,8 +7,7 @@ export class ExampleTabFactory implements TabFactory {
|
|
|
7
7
|
// Inject the angular Router
|
|
8
8
|
constructor(public router: Router) {}
|
|
9
9
|
|
|
10
|
-
// Implement the get()-method
|
|
11
|
-
// implements the TabFactory interface incorrectly (!)
|
|
10
|
+
// Implement the get()-method which is called to receive the tabs on each navigation
|
|
12
11
|
get() {
|
|
13
12
|
const tabs: Tab[] = [];
|
|
14
13
|
/**
|
|
@@ -16,13 +15,12 @@ export class ExampleTabFactory implements TabFactory {
|
|
|
16
15
|
* - Awesome
|
|
17
16
|
* - Outstanding
|
|
18
17
|
* but these tabs should only displayed if the URL matches
|
|
19
|
-
* something like: .../apps/tutorial-application/#/world/
|
|
20
18
|
*/
|
|
21
19
|
if (this.router.url.match(/\/tabs/g)) {
|
|
22
20
|
/**
|
|
23
21
|
* mandatory for a Tab is the path (string) and the label (string)
|
|
24
22
|
* A click on the tab will load the given path and therefore angular loads the
|
|
25
|
-
* specified component
|
|
23
|
+
* specified component.
|
|
26
24
|
*/
|
|
27
25
|
tabs.push({
|
|
28
26
|
path: 'hooks/tabs/awesome',
|
|
@@ -39,6 +37,24 @@ export class ExampleTabFactory implements TabFactory {
|
|
|
39
37
|
} as Tab);
|
|
40
38
|
}
|
|
41
39
|
|
|
40
|
+
// We also define two more tabs for the "inline" tabs which
|
|
41
|
+
// are rendered into any <c8y-tabs-outlet outletName="inline-example"> component
|
|
42
|
+
tabs.push({
|
|
43
|
+
path: 'inline1',
|
|
44
|
+
priority: 1000,
|
|
45
|
+
label: 'Inline 1',
|
|
46
|
+
icon: 'diamond',
|
|
47
|
+
tabsOutlet: 'inline-example'
|
|
48
|
+
} as Tab);
|
|
49
|
+
|
|
50
|
+
tabs.push({
|
|
51
|
+
path: 'inline2',
|
|
52
|
+
priority: 1000,
|
|
53
|
+
label: 'Inline 2',
|
|
54
|
+
icon: 'diamond',
|
|
55
|
+
tabsOutlet: 'inline-example'
|
|
56
|
+
} as Tab);
|
|
57
|
+
|
|
42
58
|
return tabs;
|
|
43
59
|
}
|
|
44
60
|
}
|
|
@@ -3,20 +3,25 @@ import { NavigatorNode, hookNavigator, hookRoute, hookTab } from '@c8y/ngx-compo
|
|
|
3
3
|
import { ExampleTabFactory } from './tab';
|
|
4
4
|
|
|
5
5
|
export const hooks = [
|
|
6
|
+
// important
|
|
6
7
|
hookTab(ExampleTabFactory),
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
// /important
|
|
9
|
+
hookRoute([
|
|
10
|
+
{
|
|
11
|
+
path: 'hooks/tabs',
|
|
12
|
+
redirectTo: 'hooks/tabs/outstanding'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
path: 'hooks/tabs/outstanding',
|
|
16
|
+
loadComponent: () =>
|
|
17
|
+
import('./outstanding/outstanding.component').then(m => m.OutstandingComponent),
|
|
18
|
+
loadChildren: () => import('./inline/inline.module').then(m => m.InlineModule)
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
path: 'hooks/tabs/awesome',
|
|
22
|
+
loadComponent: () => import('./awesome/awesome.component').then(m => m.AwesomeComponent)
|
|
23
|
+
}
|
|
24
|
+
]),
|
|
20
25
|
hookNavigator(
|
|
21
26
|
new NavigatorNode({
|
|
22
27
|
priority: 50,
|
package/src/i18n.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import '@c8y/ngx-components/locales/de.po';
|
|
7
7
|
import '@c8y/ngx-components/locales/en.po';
|
|
8
|
+
import '@c8y/ngx-components/locales/en_US.po';
|
|
8
9
|
import '@c8y/ngx-components/locales/es.po';
|
|
9
10
|
import '@c8y/ngx-components/locales/fr.po';
|
|
10
11
|
import '@c8y/ngx-components/locales/ja_JP.po';
|
|
@@ -12,7 +13,6 @@ import '@c8y/ngx-components/locales/ko.po';
|
|
|
12
13
|
import '@c8y/ngx-components/locales/nl.po';
|
|
13
14
|
import '@c8y/ngx-components/locales/pl.po';
|
|
14
15
|
import '@c8y/ngx-components/locales/pt_BR.po';
|
|
15
|
-
import '@c8y/ngx-components/locales/ru.po';
|
|
16
16
|
import '@c8y/ngx-components/locales/zh_CN.po';
|
|
17
17
|
import '@c8y/ngx-components/locales/zh_TW.po';
|
|
18
18
|
// import './locales/de.po'; // <- adding additional strings to the german translation.
|
package/src/main.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import './i18n';
|
|
2
2
|
import { applyOptions, loadOptions } from '@c8y/bootstrap';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
console.log(`${HELLO_WORLD} from custom webpack config`);
|
|
7
|
-
|
|
8
|
-
const barHolder: HTMLElement = document.querySelector('body > .init-load');
|
|
9
|
-
export const removeProgress = () => barHolder && barHolder.parentNode.removeChild(barHolder);
|
|
4
|
+
const barHolder: HTMLElement | null = document.querySelector('body > .init-load');
|
|
5
|
+
export const removeProgress = () => barHolder?.parentNode?.removeChild(barHolder);
|
|
10
6
|
|
|
11
7
|
applicationSetup();
|
|
12
8
|
|
|
13
9
|
async function applicationSetup() {
|
|
14
|
-
|
|
10
|
+
await applyOptions({
|
|
15
11
|
...(await loadOptions())
|
|
16
12
|
});
|
|
17
13
|
|
|
@@ -19,7 +15,6 @@ async function applicationSetup() {
|
|
|
19
15
|
/* webpackPreload: true */
|
|
20
16
|
'./bootstrap'
|
|
21
17
|
);
|
|
22
|
-
const bootstrapApp = mod.bootstrap
|
|
23
|
-
|
|
24
|
-
return Promise.resolve(bootstrapApp(options)).then(removeProgress);
|
|
18
|
+
const bootstrapApp = mod.bootstrap;
|
|
19
|
+
return bootstrapApp().then(removeProgress);
|
|
25
20
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Component, Input } from '@angular/core';
|
|
2
2
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
|
3
3
|
import { CommonModule, CoreModule } from '@c8y/ngx-components';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
AlarmEventSelectorModule,
|
|
6
|
+
AlarmOrEvent,
|
|
7
|
+
AlarmEventSelectorModalOptions
|
|
8
|
+
} from '@c8y/ngx-components/alarm-event-selector';
|
|
6
9
|
import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
|
|
7
10
|
|
|
8
11
|
@Component({
|
|
@@ -2,9 +2,9 @@ import { Component, OnInit } from '@angular/core';
|
|
|
2
2
|
import { IManagedObject, InventoryService } from '@c8y/client';
|
|
3
3
|
import {
|
|
4
4
|
DatapointSelectorModule,
|
|
5
|
-
DatapointSelectorService
|
|
5
|
+
DatapointSelectorService,
|
|
6
|
+
KPIDetails
|
|
6
7
|
} from '@c8y/ngx-components/datapoint-selector';
|
|
7
|
-
import { KPIDetails } from '@c8y/ngx-components/datapoint-selector/datapoint-selection.model';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
9
|
import { CoreModule } from '@c8y/ngx-components';
|
|
10
10
|
import { AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<c8y-title>Typeahead</c8y-title>
|
|
2
|
+
|
|
3
|
+
<div class="row">
|
|
4
|
+
<div class="col-xs-6">
|
|
5
|
+
<c8y-typeahead
|
|
6
|
+
container="body"
|
|
7
|
+
name="selectedDevice"
|
|
8
|
+
[placeholder]="'Search for devices...'"
|
|
9
|
+
(onSearch)="setPipe($event)"
|
|
10
|
+
[allowFreeEntries]="true"
|
|
11
|
+
[(ngModel)]="selectedDevice"
|
|
12
|
+
>
|
|
13
|
+
<c8y-li
|
|
14
|
+
class="p-l-8 p-r-8 c8y-list__item--link"
|
|
15
|
+
*c8yFor="let device of devices; notFound: notFoundTemplate; pipe: filterPipe"
|
|
16
|
+
(click)="selectedDevice = device"
|
|
17
|
+
[active]="selectedDevice === device"
|
|
18
|
+
>
|
|
19
|
+
<c8y-highlight
|
|
20
|
+
[text]="device.name"
|
|
21
|
+
[pattern]="pattern"
|
|
22
|
+
></c8y-highlight>
|
|
23
|
+
</c8y-li>
|
|
24
|
+
<ng-template #notFoundTemplate>
|
|
25
|
+
<c8y-li
|
|
26
|
+
class="bg-level-2 p-8 sticky-bottom"
|
|
27
|
+
*ngIf="pattern.length > 0"
|
|
28
|
+
>
|
|
29
|
+
<span translate>No exact match found.</span>
|
|
30
|
+
<button
|
|
31
|
+
class="btn btn-default btn-sm m-l-8"
|
|
32
|
+
title="Add new device"
|
|
33
|
+
type="button"
|
|
34
|
+
translate
|
|
35
|
+
>
|
|
36
|
+
Add new device
|
|
37
|
+
</button>
|
|
38
|
+
</c8y-li>
|
|
39
|
+
</ng-template>
|
|
40
|
+
</c8y-typeahead>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="col-xs-6">
|
|
43
|
+
<pre>{{ selectedDevice | json }}</pre>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { CoreModule, ForOfFilterPipe } from '@c8y/ngx-components';
|
|
3
|
+
import { IManagedObject, InventoryService, IResultList } from '@c8y/client';
|
|
4
|
+
import { pipe } from 'rxjs';
|
|
5
|
+
import { map, tap } from 'rxjs/operators';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'tut-typeahead-example',
|
|
9
|
+
templateUrl: './typeahead-example.component.html',
|
|
10
|
+
standalone: true,
|
|
11
|
+
imports: [CoreModule]
|
|
12
|
+
})
|
|
13
|
+
export class TypeaheadExampleComponent {
|
|
14
|
+
devices: IResultList<IManagedObject>;
|
|
15
|
+
filterPipe: ForOfFilterPipe = pipe(tap());
|
|
16
|
+
pattern = '';
|
|
17
|
+
selectedDevice: IManagedObject;
|
|
18
|
+
|
|
19
|
+
constructor(private inventoryService: InventoryService) {}
|
|
20
|
+
|
|
21
|
+
ngOnInit(): void {
|
|
22
|
+
this.loadDevices();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async loadDevices() {
|
|
26
|
+
this.devices = await this.inventoryService.list({
|
|
27
|
+
pageSize: 10,
|
|
28
|
+
withTotalPages: true,
|
|
29
|
+
fragmentType: 'c8y_IsDevice',
|
|
30
|
+
currentPage: 1
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async reload() {
|
|
35
|
+
await this.loadDevices();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setPipe(filterStr: string) {
|
|
39
|
+
this.pattern = filterStr;
|
|
40
|
+
this.filterPipe = pipe(
|
|
41
|
+
map((data: []) => {
|
|
42
|
+
return data.filter(
|
|
43
|
+
(mo: IManagedObject) =>
|
|
44
|
+
mo.name && mo.name.toLowerCase().indexOf(filterStr.toLowerCase()) > -1
|
|
45
|
+
);
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { hookNavigator, hookRoute, NavigatorNode } from '@c8y/ngx-components';
|
|
3
|
+
|
|
4
|
+
@NgModule({
|
|
5
|
+
providers: [
|
|
6
|
+
hookRoute({
|
|
7
|
+
path: 'typeahead',
|
|
8
|
+
loadComponent: () =>
|
|
9
|
+
import('./typeahead-example.component').then(m => m.TypeaheadExampleComponent)
|
|
10
|
+
}),
|
|
11
|
+
hookNavigator(
|
|
12
|
+
new NavigatorNode({
|
|
13
|
+
label: 'Typeahead',
|
|
14
|
+
path: 'typeahead'
|
|
15
|
+
})
|
|
16
|
+
)
|
|
17
|
+
]
|
|
18
|
+
})
|
|
19
|
+
export class TypeaheadExampleModule {}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import { CoreModule, Tab, TabsService } from '@c8y/ngx-components';
|
|
3
|
-
import { Observable } from 'rxjs';
|
|
4
|
-
|
|
5
|
-
@Component({
|
|
6
|
-
selector: 'component1',
|
|
7
|
-
template: 'component1',
|
|
8
|
-
standalone: true
|
|
9
|
-
})
|
|
10
|
-
export class Component1 {
|
|
11
|
-
ngOnInit() {
|
|
12
|
-
console.log('Component 1 initialized');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
@Component({
|
|
16
|
-
selector: 'component2',
|
|
17
|
-
template: 'component2',
|
|
18
|
-
standalone: true
|
|
19
|
-
})
|
|
20
|
-
export class Component2 {
|
|
21
|
-
ngOnInit() {
|
|
22
|
-
console.log('Component 2 initialized');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
@Component({
|
|
26
|
-
selector: 'component3',
|
|
27
|
-
template: 'component3',
|
|
28
|
-
standalone: true
|
|
29
|
-
})
|
|
30
|
-
export class Component3 {
|
|
31
|
-
ngOnInit() {
|
|
32
|
-
console.log('Component 3 initialized');
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@Component({
|
|
37
|
-
selector: 'app-dashboard-tabs',
|
|
38
|
-
template: `<div>
|
|
39
|
-
<c8y-title>Dashboard Tabs</c8y-title>
|
|
40
|
-
<h1>Inline Tabs</h1>
|
|
41
|
-
<div>
|
|
42
|
-
<c8y-tabs-outlet
|
|
43
|
-
[tabs]="tabs$ | async"
|
|
44
|
-
[outletName]="'dashboardTabs'"
|
|
45
|
-
[orientation]="'vertical'"
|
|
46
|
-
>
|
|
47
|
-
</c8y-tabs-outlet>
|
|
48
|
-
<c8y-tab
|
|
49
|
-
[label]="'Tab1'"
|
|
50
|
-
[tabsOutlet]="'dashboardTabs'"
|
|
51
|
-
(onSelect)="selectTab('Tab1')"
|
|
52
|
-
[isActive]="selectedTab === 'Tab1'"
|
|
53
|
-
>
|
|
54
|
-
</c8y-tab>
|
|
55
|
-
<c8y-tab
|
|
56
|
-
[label]="'Tab2'"
|
|
57
|
-
[tabsOutlet]="'dashboardTabs'"
|
|
58
|
-
(onSelect)="selectTab('Tab2')"
|
|
59
|
-
[isActive]="selectedTab === 'Tab2'"
|
|
60
|
-
>
|
|
61
|
-
</c8y-tab>
|
|
62
|
-
<c8y-tab
|
|
63
|
-
[label]="'Tab3'"
|
|
64
|
-
[tabsOutlet]="'dashboardTabs'"
|
|
65
|
-
(onSelect)="selectTab('Tab3')"
|
|
66
|
-
[isActive]="selectedTab === 'Tab3'"
|
|
67
|
-
>
|
|
68
|
-
</c8y-tab>
|
|
69
|
-
|
|
70
|
-
<ng-container [ngSwitch]="selectedTab">
|
|
71
|
-
<component1 *ngSwitchCase="'Tab1'"></component1>
|
|
72
|
-
<component2 *ngSwitchCase="'Tab2'"></component2>
|
|
73
|
-
<component3 *ngSwitchCase="'Tab3'"></component3>
|
|
74
|
-
</ng-container>
|
|
75
|
-
</div>
|
|
76
|
-
</div>`,
|
|
77
|
-
standalone: true,
|
|
78
|
-
imports: [CoreModule, Component1, Component2, Component3]
|
|
79
|
-
})
|
|
80
|
-
export class DashboardTabsComponent {
|
|
81
|
-
tabs$: Observable<Tab[]>;
|
|
82
|
-
selectedTab: string;
|
|
83
|
-
|
|
84
|
-
constructor(private tabsService: TabsService) {}
|
|
85
|
-
|
|
86
|
-
ngOnInit() {
|
|
87
|
-
this.tabs$ = this.tabsService.items$;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
selectTab(selectedTab: string) {
|
|
91
|
-
this.selectedTab = selectedTab;
|
|
92
|
-
console.log(this.selectedTab);
|
|
93
|
-
this.tabsService.refresh();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { NgModule } from '@angular/core';
|
|
2
|
-
import { hookNavigator, hookRoute, NavigatorNode } from '@c8y/ngx-components';
|
|
3
|
-
|
|
4
|
-
@NgModule({
|
|
5
|
-
providers: [
|
|
6
|
-
hookRoute({
|
|
7
|
-
path: 'dashboard-tabs/dashboardTabs',
|
|
8
|
-
loadComponent: () => import('./dashboard-tabs.component').then(m => m.DashboardTabsComponent)
|
|
9
|
-
}),
|
|
10
|
-
hookNavigator(
|
|
11
|
-
new NavigatorNode({
|
|
12
|
-
path: 'dashboard-tabs/dashboardTabs',
|
|
13
|
-
label: 'Dashboard Tabs',
|
|
14
|
-
icon: 'rocket',
|
|
15
|
-
priority: 1000
|
|
16
|
-
})
|
|
17
|
-
)
|
|
18
|
-
]
|
|
19
|
-
})
|
|
20
|
-
export class DashboardTabsModule {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './dashboard-tabs.module';
|
|
File without changes
|