@c8y/tutorial 1021.80.1 → 1022.3.2
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 +23 -1
- package/package.json +13 -12
- package/src/__mocks/index.ts +168 -1
- package/src/app/app.config.ts +59 -0
- package/src/bootstrap.ts +13 -9
- package/src/bottom-drawer/bottom-drawer-content-example.component.html +28 -0
- package/src/bottom-drawer/bottom-drawer-content-example.component.ts +33 -0
- package/src/bottom-drawer/bottom-drawer-example.component.html +7 -0
- package/src/bottom-drawer/bottom-drawer-example.component.ts +33 -0
- package/src/bottom-drawer/bottom-drawer.providers.ts +17 -0
- package/src/breadcrumbs/index.ts +13 -1
- package/src/client-interceptor/index.ts +16 -1
- package/src/component-styles/syntactically-awesome-style-sheets-example/syntactically-awesome-style-sheets-example.component.scss +4 -2
- package/src/countdown/countdown-example.module.ts +1 -1
- package/src/dashboard/widget-guide-context-dashboard/widget-guide-context-dashboard.component.ts +1 -9
- package/src/date-time-range/date-time-range-example.component.ts +0 -1
- package/src/dynamic-forms/index.ts +13 -1
- package/src/grids/index.ts +13 -1
- package/src/grids/server-grid-example/last-updated-data-grid-column/last-updated.cell-renderer.component.ts +2 -1
- package/src/grids/server-grid-example/server-grid-example.component.html +2 -1
- package/src/grids/tree-grid-example/client-tree-grid-example.component.html +18 -0
- package/src/grids/tree-grid-example/client-tree-grid-example.component.ts +169 -0
- package/src/grids/tree-grid-example/client-tree-grid.data.ts +147 -0
- package/src/grids/tree-grid-example/server-tree-grid-example.component.html +30 -0
- package/src/grids/tree-grid-example/server-tree-grid-example.component.ts +156 -0
- package/src/grids/tree-grid-example/server-tree-grid-example.service.ts +255 -0
- package/src/grids/tree-grid-example/tree-grid-example-tab.factory.ts +31 -0
- package/src/grids/tree-grid-example/tree-grid-example.module.ts +36 -0
- package/src/hello/index.ts +18 -1
- package/src/hooks/action/logout-action/logout-action.component.ts +3 -4
- package/src/hooks/generic-wizard/minimal-setup/minimal-setup.component.ts +4 -1
- package/src/hooks/generic-wizard/minimal-setup/multiple-entries-one.component.ts +9 -2
- package/src/hooks/generic-wizard/minimal-setup/multiple-entries-two.component.ts +9 -2
- package/src/hooks/generic-wizard/wizard.module.ts +9 -2
- package/src/hooks/index.ts +13 -1
- package/src/hooks/navigator/index.ts +12 -1
- package/src/hooks/route/index.ts +42 -1
- package/src/hooks/stepper/basic-view/basic-view.component.ts +11 -2
- package/src/hooks/stepper/stepper-hook.module.ts +7 -2
- package/src/hooks/stepper/steps/step1.component.ts +26 -3
- package/src/hooks/stepper/steps/step2.component.ts +4 -1
- package/src/hooks/widget-config/additional-config/additional-config.component.ts +16 -0
- package/src/hooks/widget-config/basic-view/basic-edit.component.html +18 -0
- package/src/hooks/widget-config/basic-view/basic-edit.component.ts +31 -0
- package/src/hooks/widget-config/widget-config.providers.ts +59 -0
- package/src/i18n.ts +3 -0
- package/src/lazy/index.ts +38 -1
- package/src/lazy-widget/index.ts +26 -1
- package/src/list/index.ts +13 -1
- package/src/main.ts +7 -10
- package/src/maps/{map-examples.module.ts → index.ts} +4 -9
- package/src/provider-configuration/index.ts +0 -2
- package/src/provider-configuration/introduction-example/{introduction.module.ts → index.ts} +5 -7
- package/src/redirect-to-last-route/index.ts +16 -1
- package/src/redirect-to-last-route/redirect-to-last-route-guard.service.ts +11 -2
- package/src/selector/alarm-event-selector-example/alarm-event-selector.module.ts +1 -1
- package/src/selector/asset-selector-example/general-example/asset-selector-example.component.ts +1 -2
- package/src/translations/index.ts +13 -1
- package/src/user-menu/index.ts +23 -1
- package/src/widget/demo-widget-config.component.ts +11 -3
- package/src/widget/demo-widget.component.ts +6 -2
- package/src/widget/index.ts +41 -1
- package/src/widget-resolvers/alternative-event.resolver.ts +8 -2
- package/src/widget-resolvers/index.ts +47 -1
- package/src/widget-resolvers/widget-resolvers-config/widget-resolvers-config.component.ts +7 -3
- package/src/widget-resolvers/widget-resolvers.component.ts +5 -1
- package/src/__mocks/mock.module.ts +0 -173
- package/src/app/app.module.ts +0 -76
- package/src/breadcrumbs/breadcrumbs.module.ts +0 -14
- package/src/client-interceptor/client-interceptor.module.ts +0 -12
- package/src/dynamic-forms/dynamic-forms.module.ts +0 -16
- package/src/grids/grids.module.ts +0 -17
- package/src/hello/hello.module.ts +0 -20
- package/src/hooks/hooks.module.ts +0 -19
- package/src/hooks/navigator/navigator.module.ts +0 -21
- package/src/hooks/route/route.module.ts +0 -51
- package/src/lazy/lazy-routing.module.ts +0 -21
- package/src/lazy/lazy.hooks.ts +0 -24
- package/src/lazy-widget/lazy-widget.module.ts +0 -30
- package/src/list/lists.module.ts +0 -17
- package/src/redirect-to-last-route/redirect-to-last-route.module.ts +0 -20
- package/src/translations/translations.module.ts +0 -18
- package/src/user-menu/user-menu.module.ts +0 -13
- package/src/user-menu/user-menu.ts +0 -26
- package/src/widget/demo-widget.module.ts +0 -55
- package/src/widget-resolvers/widget-resolvers.module.ts +0 -52
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { transform } from 'lodash-es';
|
|
3
|
+
|
|
4
|
+
import { IManagedObject, InventoryService, QueriesUtil } from '@c8y/client';
|
|
5
|
+
import {
|
|
6
|
+
ActionControl,
|
|
7
|
+
BuiltInActionType,
|
|
8
|
+
BulkActionControl,
|
|
9
|
+
Column,
|
|
10
|
+
Pagination
|
|
11
|
+
} from '@c8y/ngx-components';
|
|
12
|
+
|
|
13
|
+
import { assign, get, identity } from 'lodash-es';
|
|
14
|
+
|
|
15
|
+
/** Model for custom type filtering form. */
|
|
16
|
+
export interface TypeFilteringModel {
|
|
17
|
+
group?: boolean;
|
|
18
|
+
device?: boolean;
|
|
19
|
+
smartRule?: boolean;
|
|
20
|
+
dashboard?: boolean;
|
|
21
|
+
file?: boolean;
|
|
22
|
+
application?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* This is the example service for a data grid:
|
|
27
|
+
* provides the list of columns, initial pagination object, actions;
|
|
28
|
+
* as well as performs the query for data based on the current grid setup.
|
|
29
|
+
*/
|
|
30
|
+
@Injectable()
|
|
31
|
+
export class ServerTreeGridExampleService {
|
|
32
|
+
/** This will be used to build the inventory queries. */
|
|
33
|
+
protected queriesUtil: QueriesUtil;
|
|
34
|
+
|
|
35
|
+
constructor(protected inventoryService: InventoryService) {
|
|
36
|
+
this.queriesUtil = new QueriesUtil();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns a list of columns.
|
|
41
|
+
* We define 2 columns with inline objects (they display simple properties
|
|
42
|
+
* and use default header, cell and filtring form).
|
|
43
|
+
* The last column is defined via a class instance (it displays a value based on
|
|
44
|
+
* several properties of the row item and has custom header, cell and filtering form).
|
|
45
|
+
*/
|
|
46
|
+
getColumns(): Column[] {
|
|
47
|
+
const columns = [
|
|
48
|
+
{
|
|
49
|
+
name: 'id',
|
|
50
|
+
header: 'ID',
|
|
51
|
+
path: 'id',
|
|
52
|
+
filterable: true,
|
|
53
|
+
sortable: true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'name',
|
|
57
|
+
header: 'Name',
|
|
58
|
+
path: 'name',
|
|
59
|
+
filterable: true,
|
|
60
|
+
sortable: true
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
return columns;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Returns initial pagination object. */
|
|
68
|
+
getPagination(): Pagination {
|
|
69
|
+
return {
|
|
70
|
+
pageSize: 10,
|
|
71
|
+
currentPage: 1
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Returns initial child node pagination object. */
|
|
76
|
+
getChildNodePagination(): Pagination {
|
|
77
|
+
return {
|
|
78
|
+
pageSize: 2,
|
|
79
|
+
currentPage: 1
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Returns an array of individual row actions. */
|
|
84
|
+
getActionControls(): ActionControl[] {
|
|
85
|
+
return [
|
|
86
|
+
{ type: BuiltInActionType.Edit, callback: item => console.dir(item) },
|
|
87
|
+
{ type: BuiltInActionType.Export, callback: item => console.dir(item) },
|
|
88
|
+
{ type: BuiltInActionType.Delete, callback: item => console.dir(item) },
|
|
89
|
+
{
|
|
90
|
+
type: 'customAction',
|
|
91
|
+
icon: 'online',
|
|
92
|
+
text: 'Custom action',
|
|
93
|
+
callback: item => console.dir(item)
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Returns an array of bulk row actions. */
|
|
99
|
+
getBulkActionControls(): BulkActionControl[] {
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
type: BuiltInActionType.Export,
|
|
103
|
+
callback: selectedItemIds => console.dir(selectedItemIds)
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
type: BuiltInActionType.Delete,
|
|
107
|
+
callback: selectedItemIds => console.dir(selectedItemIds)
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'customAction',
|
|
111
|
+
icon: 'online',
|
|
112
|
+
iconClasses: 'm-r-4',
|
|
113
|
+
text: 'Custom action',
|
|
114
|
+
showIf: selectedItemIds => selectedItemIds?.every(id => Number.parseInt(id) % 2 === 0),
|
|
115
|
+
callback: selectedItemIds => console.dir(selectedItemIds)
|
|
116
|
+
}
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Returns data for current columns and pagination setup. */
|
|
121
|
+
async getData(columns: Column[], pagination: Pagination) {
|
|
122
|
+
// build filters based on columns and pagination
|
|
123
|
+
const filters = this.getFilters(columns, pagination);
|
|
124
|
+
// execute inventory query for the list of managed objects
|
|
125
|
+
return this.inventoryService.list(filters);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Returns the number of items matching current columns and pagination setup. */
|
|
129
|
+
async getCount(columns: Column[], pagination: Pagination) {
|
|
130
|
+
const filters = {
|
|
131
|
+
...this.getFilters(columns, pagination),
|
|
132
|
+
withTotalElements: true
|
|
133
|
+
};
|
|
134
|
+
return (await this.inventoryService.list(filters)).paging.totalElements;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Returns the total number of items (with no filters). */
|
|
138
|
+
async getTotal(): Promise<number> {
|
|
139
|
+
const filters = {
|
|
140
|
+
withTotalElements: true
|
|
141
|
+
};
|
|
142
|
+
return (await this.inventoryService.list(filters)).paging.totalElements;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async getChildDevices(parentId: string, pagination: Pagination) {
|
|
146
|
+
const filters = {
|
|
147
|
+
...this.getFilters([], pagination),
|
|
148
|
+
withChildren: false,
|
|
149
|
+
withChildrenCount: true
|
|
150
|
+
};
|
|
151
|
+
return this.inventoryService.childDevicesList(parentId, filters);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Returns an icon and label representing the type of the managed object. */
|
|
155
|
+
getTypeIconAndLabel(mo: IManagedObject): { icon: string; label: string } {
|
|
156
|
+
let icon = 'question';
|
|
157
|
+
let label = 'Other';
|
|
158
|
+
|
|
159
|
+
if (mo.type === 'c8y_DeviceGroup') {
|
|
160
|
+
icon = 'c8y-group';
|
|
161
|
+
label = 'Group';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (mo.c8y_IsDevice !== undefined) {
|
|
165
|
+
icon = 'exchange';
|
|
166
|
+
label = 'Device';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (mo.type === 'c8y_SmartRule' || mo.type === 'c8y_PrivateSmartRule') {
|
|
170
|
+
icon = 'c8y-smart-rules';
|
|
171
|
+
label = 'Smart rule';
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (mo.c8y_Dashboard !== undefined) {
|
|
175
|
+
icon = 'th';
|
|
176
|
+
label = 'Dashboard';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (mo.c8y_IsBinary !== undefined) {
|
|
180
|
+
icon = 'file';
|
|
181
|
+
label = 'File';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (mo.type && mo.type.startsWith('c8y_Application')) {
|
|
185
|
+
icon = 'c8y-atom';
|
|
186
|
+
label = 'Application';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return { icon, label };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Returns filters for given columns and pagination setup. */
|
|
193
|
+
private getFilters(columns: Column[], pagination: Pagination) {
|
|
194
|
+
return {
|
|
195
|
+
query: this.getQueryString(columns),
|
|
196
|
+
pageSize: pagination.pageSize,
|
|
197
|
+
currentPage: pagination.currentPage,
|
|
198
|
+
withChildren: false,
|
|
199
|
+
withChildrenCount: true,
|
|
200
|
+
withTotalPages: true
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Returns a query string based on columns setup. */
|
|
205
|
+
private getQueryString(columns: Column[]): string {
|
|
206
|
+
const fullQuery = this.getQueryObj(columns);
|
|
207
|
+
return this.queriesUtil.buildQuery(fullQuery);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Returns a query object based on columns setup. */
|
|
211
|
+
private getQueryObj(columns: Column[], defaultFilter = {}): any {
|
|
212
|
+
return transform(columns, (query, column) => this.addColumnQuery(query, column), {
|
|
213
|
+
__filter: {},
|
|
214
|
+
__orderby: [],
|
|
215
|
+
...defaultFilter
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Extends given query with a part based on the setup of given column. */
|
|
220
|
+
private addColumnQuery(query: any, column: Column): void {
|
|
221
|
+
// when a column is marked as filterable
|
|
222
|
+
if (column.filterable) {
|
|
223
|
+
// in the case of default filtering form, `filterPredicate` will contain the string entered by a user
|
|
224
|
+
if (column.filterPredicate) {
|
|
225
|
+
// so we use it as the expected value, * allow to search for it anywhere in the property
|
|
226
|
+
query.__filter[column.path] = `*${column.filterPredicate}*`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// in the case of custom filtering form, we're storing the query in `externalFilterQuery.query`
|
|
230
|
+
if (column.externalFilterQuery) {
|
|
231
|
+
const getFilter = column.filteringConfig.getFilter || identity;
|
|
232
|
+
const queryObj = getFilter(column.externalFilterQuery);
|
|
233
|
+
|
|
234
|
+
if (queryObj.__or) {
|
|
235
|
+
query.__filter.__and = query.__filter.__and || [];
|
|
236
|
+
query.__filter.__and.push(queryObj);
|
|
237
|
+
} else if (queryObj.__and && get(query, '__filter.__and')) {
|
|
238
|
+
queryObj.__and.map(obj => query.__filter.__and.push(obj));
|
|
239
|
+
} else {
|
|
240
|
+
assign(query.__filter, queryObj);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// when a column is sortable and has a specified sorting order
|
|
246
|
+
if (column.sortable && column.sortOrder) {
|
|
247
|
+
// add sorting condition for the configured column `path`
|
|
248
|
+
query.__orderby.push({
|
|
249
|
+
[column.path]: column.sortOrder === 'asc' ? 1 : -1
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return query;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Router } from '@angular/router';
|
|
3
|
+
import { Tab, TabFactory } from '@c8y/ngx-components';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class TreeGridTabFactory implements TabFactory {
|
|
7
|
+
constructor(public router: Router) {}
|
|
8
|
+
get() {
|
|
9
|
+
const tabs: Tab[] = [];
|
|
10
|
+
if (this.router.url.match(/grids\/tree-grid-example/g)) {
|
|
11
|
+
tabs.push(
|
|
12
|
+
{
|
|
13
|
+
path: 'grids/tree-grid-example/server',
|
|
14
|
+
label: 'Server side data',
|
|
15
|
+
icon: 'server',
|
|
16
|
+
priority: 1050,
|
|
17
|
+
orientation: 'horizontal'
|
|
18
|
+
} as Tab,
|
|
19
|
+
{
|
|
20
|
+
path: 'grids/tree-grid-example/client',
|
|
21
|
+
label: 'Client side data',
|
|
22
|
+
icon: 'house',
|
|
23
|
+
priority: 1000,
|
|
24
|
+
orientation: 'horizontal'
|
|
25
|
+
} as Tab
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return tabs;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
CommonModule,
|
|
4
|
+
hookNavigator,
|
|
5
|
+
hookRoute,
|
|
6
|
+
hookTab,
|
|
7
|
+
NavigatorNode
|
|
8
|
+
} from '@c8y/ngx-components';
|
|
9
|
+
import { TreeGridTabFactory } from './tree-grid-example-tab.factory';
|
|
10
|
+
|
|
11
|
+
@NgModule({
|
|
12
|
+
imports: [CommonModule],
|
|
13
|
+
providers: [
|
|
14
|
+
hookRoute({
|
|
15
|
+
path: 'grids/tree-grid-example/server',
|
|
16
|
+
loadComponent: () =>
|
|
17
|
+
import('./server-tree-grid-example.component').then(m => m.ServerTreeGridExampleComponent)
|
|
18
|
+
}),
|
|
19
|
+
hookRoute({
|
|
20
|
+
path: 'grids/tree-grid-example/client',
|
|
21
|
+
loadComponent: () =>
|
|
22
|
+
import('./client-tree-grid-example.component').then(m => m.ClientGridExampleComponent)
|
|
23
|
+
}),
|
|
24
|
+
hookNavigator(
|
|
25
|
+
new NavigatorNode({
|
|
26
|
+
priority: 20,
|
|
27
|
+
path: 'grids/tree-grid-example/server',
|
|
28
|
+
icon: 'tree-structure',
|
|
29
|
+
label: 'Tree grid',
|
|
30
|
+
parent: 'Data grid examples'
|
|
31
|
+
})
|
|
32
|
+
),
|
|
33
|
+
hookTab(TreeGridTabFactory)
|
|
34
|
+
]
|
|
35
|
+
})
|
|
36
|
+
export class TreeGridExampleModule {}
|
package/src/hello/index.ts
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { hookRoute } from '@c8y/ngx-components';
|
|
2
|
+
import { HelloComponent } from './hello.component';
|
|
3
|
+
|
|
4
|
+
export function provideHelloSample() {
|
|
5
|
+
return [
|
|
6
|
+
hookRoute([
|
|
7
|
+
{
|
|
8
|
+
path: '',
|
|
9
|
+
redirectTo: 'hello',
|
|
10
|
+
pathMatch: 'full'
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
path: 'hello',
|
|
14
|
+
component: HelloComponent
|
|
15
|
+
}
|
|
16
|
+
])
|
|
17
|
+
];
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
2
|
// eslint-disable-next-line
|
|
3
|
-
import { CoreModule,
|
|
3
|
+
import { CoreModule, SimplifiedAuthService } from '@c8y/ngx-components';
|
|
4
4
|
|
|
5
5
|
@Component({
|
|
6
6
|
selector: 'app-logout-action',
|
|
@@ -11,12 +11,11 @@ import { CoreModule, LoginService } from '@c8y/ngx-components';
|
|
|
11
11
|
imports: [CoreModule]
|
|
12
12
|
})
|
|
13
13
|
export class LogoutActionComponent {
|
|
14
|
-
|
|
15
|
-
// constructor(private loginService: LoginService) {}
|
|
14
|
+
constructor(private _authService: SimplifiedAuthService) {}
|
|
16
15
|
|
|
17
16
|
logout() {
|
|
18
17
|
console.log('Logout action triggered!');
|
|
19
18
|
// Uncomment to see the effect.
|
|
20
|
-
// this.
|
|
19
|
+
// this._authService.logout();
|
|
21
20
|
}
|
|
22
21
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
|
+
import { WizardHeaderComponent, WizardBodyComponent } from '@c8y/ngx-components';
|
|
2
3
|
|
|
3
4
|
@Component({
|
|
4
5
|
selector: 'container-component',
|
|
5
6
|
template: `
|
|
6
7
|
<c8y-wizard-header> New header </c8y-wizard-header>
|
|
7
8
|
<c8y-wizard-body> New body </c8y-wizard-body>
|
|
8
|
-
|
|
9
|
+
`,
|
|
10
|
+
standalone: true,
|
|
11
|
+
imports: [WizardHeaderComponent, WizardBodyComponent]
|
|
9
12
|
})
|
|
10
13
|
export class MinimalSetupComponent {
|
|
11
14
|
// In this case cancel method is not required, because it is the default button when the <c8y-wizard-footer> tag is missing.
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
WizardComponent,
|
|
4
|
+
WizardHeaderComponent,
|
|
5
|
+
WizardBodyComponent,
|
|
6
|
+
WizardFooterComponent
|
|
7
|
+
} from '@c8y/ngx-components';
|
|
3
8
|
|
|
4
9
|
@Component({
|
|
5
10
|
selector: 'multiple-entries-one-component',
|
|
@@ -10,7 +15,9 @@ import { WizardComponent } from '@c8y/ngx-components';
|
|
|
10
15
|
<button class="btn btn-default" title="{{ 'Back' }}" (click)="back()">Back</button>
|
|
11
16
|
<button class="btn btn-default" title="{{ 'Cancel' }}" (click)="cancel()">Cancel</button>
|
|
12
17
|
</c8y-wizard-footer>
|
|
13
|
-
|
|
18
|
+
`,
|
|
19
|
+
standalone: true,
|
|
20
|
+
imports: [WizardHeaderComponent, WizardBodyComponent, WizardFooterComponent]
|
|
14
21
|
})
|
|
15
22
|
export class MultipleEntriesOne {
|
|
16
23
|
constructor(private wizardComponent: WizardComponent) {}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
WizardComponent,
|
|
4
|
+
WizardHeaderComponent,
|
|
5
|
+
WizardBodyComponent,
|
|
6
|
+
WizardFooterComponent
|
|
7
|
+
} from '@c8y/ngx-components';
|
|
3
8
|
|
|
4
9
|
@Component({
|
|
5
10
|
selector: 'multiple-entries-two-component',
|
|
@@ -10,7 +15,9 @@ import { WizardComponent } from '@c8y/ngx-components';
|
|
|
10
15
|
<button class="btn btn-default" title="{{ 'Back' }}" (click)="back()">Back</button>
|
|
11
16
|
<button class="btn btn-default" title="{{ 'Cancel' }}" (click)="cancel()">Cancel</button>
|
|
12
17
|
</c8y-wizard-footer>
|
|
13
|
-
|
|
18
|
+
`,
|
|
19
|
+
standalone: true,
|
|
20
|
+
imports: [WizardHeaderComponent, WizardBodyComponent, WizardFooterComponent]
|
|
14
21
|
})
|
|
15
22
|
export class MultipleEntriesTwo {
|
|
16
23
|
constructor(private wizardComponent: WizardComponent) {}
|
|
@@ -21,8 +21,15 @@ const routes: Routes = [
|
|
|
21
21
|
];
|
|
22
22
|
|
|
23
23
|
@NgModule({
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
imports: [
|
|
25
|
+
RouterModule.forChild(routes),
|
|
26
|
+
CoreModule,
|
|
27
|
+
FormsModule,
|
|
28
|
+
ReactiveFormsModule,
|
|
29
|
+
MinimalSetupComponent,
|
|
30
|
+
MultipleEntriesOne,
|
|
31
|
+
MultipleEntriesTwo
|
|
32
|
+
],
|
|
26
33
|
/**
|
|
27
34
|
* Adding the hooks to the providers:
|
|
28
35
|
*/
|
package/src/hooks/index.ts
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { hookNavigator, NavigatorNode } from '@c8y/ngx-components';
|
|
2
|
+
|
|
3
|
+
export function provideHooksSample() {
|
|
4
|
+
return [
|
|
5
|
+
hookNavigator(
|
|
6
|
+
new NavigatorNode({
|
|
7
|
+
priority: 90,
|
|
8
|
+
icon: 'u-turn',
|
|
9
|
+
label: 'Hooks'
|
|
10
|
+
})
|
|
11
|
+
)
|
|
12
|
+
];
|
|
13
|
+
}
|
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { hookNavigator } from '@c8y/ngx-components';
|
|
2
|
+
import { ExampleNavigationFactory } from './navigator';
|
|
3
|
+
|
|
4
|
+
export function provideHooksNavigatorSample() {
|
|
5
|
+
/**
|
|
6
|
+
* Use our predefined InjectionTokens and provide your own classes to extend behavior
|
|
7
|
+
* and functionality of existing ones. Implement your own NavigationNodes, Tabs, Actions and Breadcrumbs.
|
|
8
|
+
* Note: Hooks should always be implemented in the module where they are used, so that
|
|
9
|
+
* a module can act standalone and has no dependencies on other modules.
|
|
10
|
+
*/
|
|
11
|
+
return [hookNavigator(ExampleNavigationFactory)];
|
|
12
|
+
}
|
package/src/hooks/route/index.ts
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
import { hookRoute, ViewContext } from '@c8y/ngx-components';
|
|
2
|
+
import { RandomGuard } from './random.guard';
|
|
3
|
+
|
|
4
|
+
export function provideRouteSample() {
|
|
5
|
+
return [
|
|
6
|
+
/**
|
|
7
|
+
* Route hooks allow you to use routes as child routes on a ViewContext. If used with a context
|
|
8
|
+
* the particular data is resolved automatically and the page is extended by a tab. Contexts
|
|
9
|
+
* are currently Application, Device, Group, Tenant and User. Note: All components used here
|
|
10
|
+
* needs to be used as EntryComponent!
|
|
11
|
+
* This example will add a device tab with all the context information as well as a randomly
|
|
12
|
+
* guarded context tab.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
hookRoute([
|
|
16
|
+
{
|
|
17
|
+
path: 'context',
|
|
18
|
+
context: ViewContext.Device,
|
|
19
|
+
loadComponent: () =>
|
|
20
|
+
import('./device/device-tab-context.component').then(m => m.DeviceTabContextComponent),
|
|
21
|
+
label: 'Context',
|
|
22
|
+
priority: 1000,
|
|
23
|
+
icon: 'bell'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
path: 'info',
|
|
27
|
+
context: ViewContext.Device,
|
|
28
|
+
loadComponent: () =>
|
|
29
|
+
import('./device/device-info.component').then(m => m.DeviceInfoComponent),
|
|
30
|
+
label: 'Info',
|
|
31
|
+
priority: 0,
|
|
32
|
+
icon: 'info',
|
|
33
|
+
/**
|
|
34
|
+
* An example of an route guard which randomly activates
|
|
35
|
+
* the child route. See Guards documentation from Angular
|
|
36
|
+
* for more details.
|
|
37
|
+
*/
|
|
38
|
+
canActivate: [RandomGuard]
|
|
39
|
+
}
|
|
40
|
+
])
|
|
41
|
+
];
|
|
42
|
+
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { Component, OnInit } from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SetupStep,
|
|
4
|
+
StepperService,
|
|
5
|
+
Steppers,
|
|
6
|
+
TitleComponent,
|
|
7
|
+
StepperOutletComponent
|
|
8
|
+
} from '@c8y/ngx-components';
|
|
3
9
|
import { firstValueFrom } from 'rxjs';
|
|
10
|
+
import { NgIf } from '@angular/common';
|
|
4
11
|
|
|
5
12
|
/**
|
|
6
13
|
* This is a standard angular component.
|
|
@@ -21,7 +28,9 @@ import { firstValueFrom } from 'rxjs';
|
|
|
21
28
|
</div>
|
|
22
29
|
</div>
|
|
23
30
|
</div>
|
|
24
|
-
|
|
31
|
+
`,
|
|
32
|
+
standalone: true,
|
|
33
|
+
imports: [TitleComponent, NgIf, StepperOutletComponent]
|
|
25
34
|
})
|
|
26
35
|
export class BasicViewComponent implements OnInit {
|
|
27
36
|
readonly stepperId = Steppers.SETUP;
|
|
@@ -13,8 +13,13 @@ const routes: Routes = [
|
|
|
13
13
|
];
|
|
14
14
|
|
|
15
15
|
@NgModule({
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
imports: [
|
|
17
|
+
RouterModule.forChild(routes),
|
|
18
|
+
CoreModule,
|
|
19
|
+
BasicViewComponent,
|
|
20
|
+
Step1Component,
|
|
21
|
+
Step2Component
|
|
22
|
+
],
|
|
18
23
|
/**
|
|
19
24
|
* Adding the hooks to the providers:
|
|
20
25
|
*/
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { CdkStep } from '@angular/cdk/stepper';
|
|
2
2
|
import { Component, OnInit } from '@angular/core';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
FormBuilder,
|
|
5
|
+
FormGroup,
|
|
6
|
+
Validators,
|
|
7
|
+
FormsModule,
|
|
8
|
+
ReactiveFormsModule
|
|
9
|
+
} from '@angular/forms';
|
|
10
|
+
import {
|
|
11
|
+
C8yStepper,
|
|
12
|
+
FormGroupComponent,
|
|
13
|
+
RequiredInputPlaceholderDirective,
|
|
14
|
+
MessagesComponent,
|
|
15
|
+
MessageDirective,
|
|
16
|
+
C8yStepperButtons
|
|
17
|
+
} from '@c8y/ngx-components';
|
|
5
18
|
|
|
6
19
|
@Component({
|
|
7
20
|
selector: 'tut-step-1-device',
|
|
@@ -22,7 +35,17 @@ import { C8yStepper } from '@c8y/ngx-components';
|
|
|
22
35
|
(onNext)="goToNextStep($event)"
|
|
23
36
|
></c8y-stepper-buttons>
|
|
24
37
|
</div>
|
|
25
|
-
|
|
38
|
+
`,
|
|
39
|
+
standalone: true,
|
|
40
|
+
imports: [
|
|
41
|
+
FormGroupComponent,
|
|
42
|
+
FormsModule,
|
|
43
|
+
ReactiveFormsModule,
|
|
44
|
+
RequiredInputPlaceholderDirective,
|
|
45
|
+
MessagesComponent,
|
|
46
|
+
MessageDirective,
|
|
47
|
+
C8yStepperButtons
|
|
48
|
+
]
|
|
26
49
|
})
|
|
27
50
|
export class Step1Component implements OnInit {
|
|
28
51
|
formGroupStepOne: FormGroup;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
|
+
import { C8yStepperButtons } from '@c8y/ngx-components';
|
|
2
3
|
|
|
3
4
|
@Component({
|
|
4
5
|
selector: 'tut-step-2-device',
|
|
@@ -10,7 +11,9 @@ import { Component } from '@angular/core';
|
|
|
10
11
|
[showButtons]="{ next: false, cancel: false, back: true, custom: false }"
|
|
11
12
|
[labels]="{ back: 'Got it!' }"
|
|
12
13
|
></c8y-stepper-buttons>
|
|
13
|
-
|
|
14
|
+
`,
|
|
15
|
+
standalone: true,
|
|
16
|
+
imports: [C8yStepperButtons]
|
|
14
17
|
})
|
|
15
18
|
export class Step2Component {
|
|
16
19
|
close() {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { CoreModule } from '@c8y/ngx-components';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This is a standard angular component.
|
|
6
|
+
* Obviously it does not do anything.
|
|
7
|
+
*/
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'tut-additional-config-component',
|
|
10
|
+
template: 'Any additional configuration can be done here.',
|
|
11
|
+
standalone: true,
|
|
12
|
+
imports: [CoreModule]
|
|
13
|
+
})
|
|
14
|
+
export class AdditionalConfigComponent {
|
|
15
|
+
editComponent = false;
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<div class="card">
|
|
2
|
+
<div class="card-block">
|
|
3
|
+
<c8y-widget-config-section
|
|
4
|
+
*ngFor="let section of widgetConfigService.currentSections$ | async; let i = index"
|
|
5
|
+
[section]="section"
|
|
6
|
+
></c8y-widget-config-section>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="card-block">
|
|
10
|
+
<label>The configuration is:</label>
|
|
11
|
+
<code>
|
|
12
|
+
<pre>
|
|
13
|
+
{{ widgetConfigService.currentConfig$ | async | json }}
|
|
14
|
+
</pre
|
|
15
|
+
>
|
|
16
|
+
</code>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|