@c8y/tutorial 1023.97.7 → 1024.0.0
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 -7
- package/package.json +14 -12
- package/src/app/app.config.ts +2 -1
- package/src/dashboard/custom-dashboard/custom-dashboard.component.html +46 -29
- package/src/dashboard/custom-dashboard/custom-dashboard.component.ts +1 -0
- package/src/dashboard/responsive-layout-dashboard/responsive-layout-dashboard.component.html +99 -0
- package/src/dashboard/responsive-layout-dashboard/responsive-layout-dashboard.component.ts +26 -0
- package/src/dashboard/responsive-layout-dashboard/responsive-layout-dashboard.module.ts +24 -0
- package/src/grids/device-grid-example/device-grid-example-configuration-strategy.ts +2 -2
- package/src/grids/server-grid-example/server-grid-example.service.ts +1 -2
- package/src/grids/server-grid-example/void-configuration-strategy.ts +2 -2
- package/src/grids/tree-grid-example/server-tree-grid-example.service.ts +1 -2
- package/src/hooks/query-param-bottom-drawer/example-button.component.ts +12 -1
- package/src/hooks/query-param-bottom-drawer/example-component.ts +12 -5
- package/src/hooks/query-param-modal/example-button.component.ts +12 -1
- package/src/hooks/query-param-modal/example-component.ts +15 -4
- package/src/input-group/input-group-editable-example.component.ts +76 -0
- package/tsconfig.app.json +1 -0
- package/src/branding/branding.less +0 -78
- package/src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.component.less +0 -16
- package/src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.component.ts +0 -15
- package/src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.module.ts +0 -26
package/cumulocity.config.ts
CHANGED
|
@@ -114,6 +114,13 @@ export default {
|
|
|
114
114
|
description: 'An introduction to custom dashboards.',
|
|
115
115
|
scope: 'self'
|
|
116
116
|
},
|
|
117
|
+
{
|
|
118
|
+
name: 'Responsive layout dashboard module',
|
|
119
|
+
module: 'ResponsiveLayoutDashboardModule',
|
|
120
|
+
path: './src/dashboard/responsive-layout-dashboard/responsive-layout-dashboard.module.ts',
|
|
121
|
+
description: 'Demonstrates the viewport-filling responsive layout mode of c8y-dashboard.',
|
|
122
|
+
scope: 'self'
|
|
123
|
+
},
|
|
117
124
|
{
|
|
118
125
|
name: 'Dashboard module with example of dynamic component usage',
|
|
119
126
|
module: 'WidgetGuideDashboardModule',
|
|
@@ -177,13 +184,6 @@ export default {
|
|
|
177
184
|
description: 'A sample for component styles using CSS.',
|
|
178
185
|
scope: 'self'
|
|
179
186
|
},
|
|
180
|
-
{
|
|
181
|
-
name: 'LESS Component styles Example',
|
|
182
|
-
module: 'LeanerStyleSheetsExampleModule',
|
|
183
|
-
path: './src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.module.ts',
|
|
184
|
-
description: 'A sample for component styles using LESS.',
|
|
185
|
-
scope: 'self'
|
|
186
|
-
},
|
|
187
187
|
{
|
|
188
188
|
name: 'SCSS Component styles Example',
|
|
189
189
|
module: 'SyntacticallyAwesomeStyleSheetsExampleModule',
|
package/package.json
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c8y/tutorial",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1024.0.0",
|
|
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
|
-
"@angular/animations": "^
|
|
7
|
-
"@angular/cdk": "^
|
|
8
|
-
"@c8y/bootstrap": "
|
|
9
|
-
"@c8y/client": "
|
|
10
|
-
"@c8y/ngx-components": "
|
|
11
|
-
"@c8y/style": "
|
|
6
|
+
"@angular/animations": "^21.2.0",
|
|
7
|
+
"@angular/cdk": "^21.2.0",
|
|
8
|
+
"@c8y/bootstrap": "1024.0.0",
|
|
9
|
+
"@c8y/client": "1024.0.0",
|
|
10
|
+
"@c8y/ngx-components": "1024.0.0",
|
|
11
|
+
"@c8y/style": "1024.0.0",
|
|
12
|
+
"gridstack": "^12.4.2",
|
|
12
13
|
"leaflet": "1.9.4",
|
|
13
14
|
"monaco-editor": "~0.53.0",
|
|
14
|
-
"ngx-bootstrap": "
|
|
15
|
-
"rxjs": "7.8.2"
|
|
15
|
+
"ngx-bootstrap": "21.0.1",
|
|
16
|
+
"rxjs": "7.8.2",
|
|
17
|
+
"zone.js": "~0.15.1"
|
|
16
18
|
},
|
|
17
19
|
"devDependencies": {
|
|
18
|
-
"@c8y/devkit": "
|
|
19
|
-
"@c8y/options": "
|
|
20
|
+
"@c8y/devkit": "1024.0.0",
|
|
21
|
+
"@c8y/options": "1024.0.0"
|
|
20
22
|
},
|
|
21
23
|
"peerDependencies": {
|
|
22
|
-
"@angular/common": ">=
|
|
24
|
+
"@angular/common": ">=21 <22"
|
|
23
25
|
},
|
|
24
26
|
"author": "Cumulocity GmbH",
|
|
25
27
|
"license": "Apache-2.0"
|
package/src/app/app.config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
|
|
1
|
+
import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core';
|
|
2
2
|
import { provideAnimations } from '@angular/platform-browser/animations';
|
|
3
3
|
import { CoreModule, RouterModule, VersionModule } from '@c8y/ngx-components';
|
|
4
4
|
import { provideHelloSample } from '../hello';
|
|
@@ -30,6 +30,7 @@ import { configureWidgetProviders } from '@c8y/ngx-components/widgets/widget-pro
|
|
|
30
30
|
|
|
31
31
|
export const appConfig: ApplicationConfig = {
|
|
32
32
|
providers: [
|
|
33
|
+
provideZoneChangeDetection(),
|
|
33
34
|
provideAnimations(),
|
|
34
35
|
importProvidersFrom(RouterModule.forRoot()),
|
|
35
36
|
importProvidersFrom(CoreModule.forRoot()),
|
|
@@ -11,6 +11,17 @@
|
|
|
11
11
|
{{ 'Add random' }}
|
|
12
12
|
</button>
|
|
13
13
|
</c8y-action-bar-item>
|
|
14
|
+
<c8y-action-bar-item [placement]="'right'">
|
|
15
|
+
<button
|
|
16
|
+
class="btn btn-link"
|
|
17
|
+
title="{{ 'Toggle layout' }}"
|
|
18
|
+
type="button"
|
|
19
|
+
(click)="layout = layout === 'grid' ? 'custom' : 'grid'"
|
|
20
|
+
>
|
|
21
|
+
<i [c8yIcon]="layout === 'grid' ? 'cogs' : 'th'"></i>
|
|
22
|
+
{{ layout === 'grid' ? 'Switch to custom layout' : 'Switch to grid layout' }}
|
|
23
|
+
</button>
|
|
24
|
+
</c8y-action-bar-item>
|
|
14
25
|
<c8y-action-bar-item [placement]="'right'">
|
|
15
26
|
<button
|
|
16
27
|
class="btn btn-link"
|
|
@@ -24,33 +35,37 @@
|
|
|
24
35
|
|
|
25
36
|
<c8y-help src="/docs/cockpit/working-with-dashboards/#working-with-dashboards"></c8y-help>
|
|
26
37
|
|
|
27
|
-
<c8y-dashboard
|
|
38
|
+
<c8y-dashboard
|
|
39
|
+
[layout]="layout"
|
|
40
|
+
(dashboardChange)="dashboardChange($event)"
|
|
41
|
+
>
|
|
28
42
|
<!-- Simple widgets represented by widgets array property from CustomDashboardComponent class-->
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
@for (widget of widgets; track widget) {
|
|
44
|
+
<c8y-dashboard-child
|
|
45
|
+
[class]="{
|
|
46
|
+
'panel-title-hidden': true
|
|
47
|
+
}"
|
|
48
|
+
title="dynamic"
|
|
49
|
+
[isFrozen]="isFrozen"
|
|
50
|
+
[data]="widget"
|
|
51
|
+
[width]="widget.width"
|
|
52
|
+
[height]="widget.height"
|
|
53
|
+
#current
|
|
54
|
+
>
|
|
55
|
+
<div class="card-block">
|
|
56
|
+
Simple widget with content only
|
|
57
|
+
<br />
|
|
58
|
+
x: {{ current.x }}
|
|
59
|
+
<br />
|
|
60
|
+
y: {{ current.y }}
|
|
61
|
+
<br />
|
|
62
|
+
width: {{ current.width }}
|
|
63
|
+
<br />
|
|
64
|
+
height: {{ current.height }}
|
|
65
|
+
<br />
|
|
66
|
+
</div>
|
|
67
|
+
</c8y-dashboard-child>
|
|
68
|
+
}
|
|
54
69
|
|
|
55
70
|
<!-- Dashboard child with title and widget classes applied-->
|
|
56
71
|
<c8y-dashboard-child
|
|
@@ -129,9 +144,11 @@
|
|
|
129
144
|
[width]="8"
|
|
130
145
|
[height]="2"
|
|
131
146
|
>
|
|
132
|
-
|
|
133
|
-
<
|
|
134
|
-
|
|
147
|
+
@if (showTitle) {
|
|
148
|
+
<c8y-dashboard-child-title>
|
|
149
|
+
<span>Widget title</span>
|
|
150
|
+
</c8y-dashboard-child-title>
|
|
151
|
+
}
|
|
135
152
|
<c8y-dashboard-child-action>
|
|
136
153
|
<a
|
|
137
154
|
href=""
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<c8y-title>Responsive layout dashboard</c8y-title>
|
|
2
|
+
|
|
3
|
+
<c8y-action-bar-item [placement]="'right'">
|
|
4
|
+
<button
|
|
5
|
+
class="btn btn-link"
|
|
6
|
+
title="{{ isFrozen ? 'Enable edit mode' : 'Disable edit mode' }}"
|
|
7
|
+
type="button"
|
|
8
|
+
(click)="toggleEdit()"
|
|
9
|
+
>
|
|
10
|
+
<i [c8yIcon]="isFrozen ? 'unlock' : 'lock'"></i>
|
|
11
|
+
{{ isFrozen ? 'Enable edit mode' : 'Disable edit mode' }}
|
|
12
|
+
</button>
|
|
13
|
+
</c8y-action-bar-item>
|
|
14
|
+
|
|
15
|
+
<!--
|
|
16
|
+
layout="custom" — enables the configurable layout mode.
|
|
17
|
+
alignViewHeight="true" — each row scales so all rows fill the viewport height.
|
|
18
|
+
[rows]="4" — the grid has 4 rows; each row is 25% of the viewport height.
|
|
19
|
+
[columns]="12" — 12-column grid; a widget with width=6 spans 50% of the width.
|
|
20
|
+
|
|
21
|
+
Enable edit mode above to see the size-preset picker on each widget.
|
|
22
|
+
-->
|
|
23
|
+
<c8y-dashboard
|
|
24
|
+
class="fit-h"
|
|
25
|
+
layout="custom"
|
|
26
|
+
[columns]="columns"
|
|
27
|
+
[rows]="rows"
|
|
28
|
+
[alignViewHeight]="true"
|
|
29
|
+
>
|
|
30
|
+
<!-- Row 1 — full-width banner -->
|
|
31
|
+
<c8y-dashboard-child
|
|
32
|
+
[class]="{ 'panel-title-hidden': true }"
|
|
33
|
+
[isFrozen]="isFrozen"
|
|
34
|
+
[x]="0"
|
|
35
|
+
[y]="0"
|
|
36
|
+
[width]="12"
|
|
37
|
+
[height]="1"
|
|
38
|
+
>
|
|
39
|
+
<div class="card-block d-flex a-i-center j-c-between">
|
|
40
|
+
<span>Overview — 100% width × 25% viewport height</span>
|
|
41
|
+
</div>
|
|
42
|
+
</c8y-dashboard-child>
|
|
43
|
+
|
|
44
|
+
<!-- Row 2 — two equal columns -->
|
|
45
|
+
<c8y-dashboard-child
|
|
46
|
+
[class]="{ 'panel-title-hidden': true }"
|
|
47
|
+
[isFrozen]="isFrozen"
|
|
48
|
+
[x]="0"
|
|
49
|
+
[y]="1"
|
|
50
|
+
[width]="6"
|
|
51
|
+
[height]="1"
|
|
52
|
+
>
|
|
53
|
+
<div class="card-block d-flex a-i-center j-c-center">50% width × 25% height</div>
|
|
54
|
+
</c8y-dashboard-child>
|
|
55
|
+
|
|
56
|
+
<c8y-dashboard-child
|
|
57
|
+
[class]="{ 'panel-title-hidden': true }"
|
|
58
|
+
[isFrozen]="isFrozen"
|
|
59
|
+
[x]="6"
|
|
60
|
+
[y]="1"
|
|
61
|
+
[width]="6"
|
|
62
|
+
[height]="1"
|
|
63
|
+
>
|
|
64
|
+
<div class="card-block d-flex a-i-center j-c-center">50% width × 25% height</div>
|
|
65
|
+
</c8y-dashboard-child>
|
|
66
|
+
|
|
67
|
+
<!-- Rows 3–4 — a wide chart alongside a narrow sidebar -->
|
|
68
|
+
<c8y-dashboard-child
|
|
69
|
+
[class]="{ 'panel-title-border': true }"
|
|
70
|
+
[isFrozen]="isFrozen"
|
|
71
|
+
[x]="0"
|
|
72
|
+
[y]="2"
|
|
73
|
+
[width]="8"
|
|
74
|
+
[height]="2"
|
|
75
|
+
>
|
|
76
|
+
<c8y-dashboard-child-title>
|
|
77
|
+
<span>Chart — 67% wide × 50% height</span>
|
|
78
|
+
</c8y-dashboard-child-title>
|
|
79
|
+
<div class="card-block">
|
|
80
|
+
Width: 8 of 12 columns = 67% | Height: 2 of 4 rows = 50%
|
|
81
|
+
</div>
|
|
82
|
+
</c8y-dashboard-child>
|
|
83
|
+
|
|
84
|
+
<c8y-dashboard-child
|
|
85
|
+
[class]="{ 'panel-title-border': true }"
|
|
86
|
+
[isFrozen]="isFrozen"
|
|
87
|
+
[x]="8"
|
|
88
|
+
[y]="2"
|
|
89
|
+
[width]="4"
|
|
90
|
+
[height]="2"
|
|
91
|
+
>
|
|
92
|
+
<c8y-dashboard-child-title>
|
|
93
|
+
<span>Sidebar — 33% wide × 50% height</span>
|
|
94
|
+
</c8y-dashboard-child-title>
|
|
95
|
+
<div class="card-block">
|
|
96
|
+
Width: 4 of 12 columns = 33% | Height: 2 of 4 rows = 50%
|
|
97
|
+
</div>
|
|
98
|
+
</c8y-dashboard-child>
|
|
99
|
+
</c8y-dashboard>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { CoreModule } from '@c8y/ngx-components';
|
|
3
|
+
import { CommonModule } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Demonstrates the "custom" layout mode of c8y-dashboard with alignViewHeight enabled.
|
|
7
|
+
*
|
|
8
|
+
* With rows=4 and alignViewHeight=true each row automatically scales to exactly
|
|
9
|
+
* one quarter of the visible viewport height, so the grid always fills the screen
|
|
10
|
+
* regardless of window size.
|
|
11
|
+
*/
|
|
12
|
+
@Component({
|
|
13
|
+
selector: 'tut-responsive-layout-dashboard',
|
|
14
|
+
templateUrl: './responsive-layout-dashboard.component.html',
|
|
15
|
+
standalone: true,
|
|
16
|
+
imports: [CommonModule, CoreModule]
|
|
17
|
+
})
|
|
18
|
+
export class ResponsiveLayoutDashboardComponent {
|
|
19
|
+
isFrozen = true;
|
|
20
|
+
readonly rows = 4;
|
|
21
|
+
readonly columns = 12;
|
|
22
|
+
|
|
23
|
+
toggleEdit() {
|
|
24
|
+
this.isFrozen = !this.isFrozen;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { NavigatorNode, hookNavigator, hookRoute } from '@c8y/ngx-components';
|
|
3
|
+
|
|
4
|
+
@NgModule({
|
|
5
|
+
providers: [
|
|
6
|
+
hookRoute({
|
|
7
|
+
path: 'dashboards/responsive-layout',
|
|
8
|
+
loadComponent: () =>
|
|
9
|
+
import('./responsive-layout-dashboard.component').then(
|
|
10
|
+
m => m.ResponsiveLayoutDashboardComponent
|
|
11
|
+
)
|
|
12
|
+
}),
|
|
13
|
+
hookNavigator(
|
|
14
|
+
new NavigatorNode({
|
|
15
|
+
label: 'Responsive layout dashboard',
|
|
16
|
+
path: '/dashboards/responsive-layout',
|
|
17
|
+
icon: 'cogs',
|
|
18
|
+
priority: 2,
|
|
19
|
+
parent: 'Dashboards'
|
|
20
|
+
})
|
|
21
|
+
)
|
|
22
|
+
]
|
|
23
|
+
})
|
|
24
|
+
export class ResponsiveLayoutDashboardModule {}
|
|
@@ -34,11 +34,11 @@ export class DeviceGridExampleConfigurationStrategy extends AbstractConfiguratio
|
|
|
34
34
|
: null;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
saveConfig$(config: GridConfig, ctx?: GridConfigContext): Observable<
|
|
37
|
+
saveConfig$(config: GridConfig, ctx?: GridConfigContext): Observable<void> {
|
|
38
38
|
const context = this.retrieveContext(ctx);
|
|
39
39
|
if (context?.key) {
|
|
40
40
|
localStorage.setItem(context.key, JSON.stringify(config));
|
|
41
41
|
}
|
|
42
|
-
return of(
|
|
42
|
+
return of(undefined);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
-
import { transform } from 'lodash-es';
|
|
3
2
|
|
|
4
3
|
import { IManagedObject, InventoryService, QueriesUtil } from '@c8y/client';
|
|
5
4
|
import {
|
|
@@ -10,7 +9,7 @@ import {
|
|
|
10
9
|
Pagination
|
|
11
10
|
} from '@c8y/ngx-components';
|
|
12
11
|
|
|
13
|
-
import { assign, get, identity } from 'lodash-es';
|
|
12
|
+
import { assign, get, identity, transform } from 'lodash-es';
|
|
14
13
|
import { LastUpdatedDataGridColumn } from './last-updated-data-grid-column/last-updated.data-grid-column';
|
|
15
14
|
import { TypeDataGridColumn } from './type-data-grid-column/type.data-grid-column';
|
|
16
15
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
-
import { transform } from 'lodash-es';
|
|
3
2
|
|
|
4
3
|
import { IManagedObject, InventoryService, QueriesUtil } from '@c8y/client';
|
|
5
4
|
import {
|
|
@@ -10,7 +9,7 @@ import {
|
|
|
10
9
|
Pagination
|
|
11
10
|
} from '@c8y/ngx-components';
|
|
12
11
|
|
|
13
|
-
import { assign, get, identity } from 'lodash-es';
|
|
12
|
+
import { assign, get, identity, transform } from 'lodash-es';
|
|
14
13
|
|
|
15
14
|
/** Model for custom type filtering form. */
|
|
16
15
|
export interface TypeFilteringModel {
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
2
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
3
|
+
import { CoreModule } from '@c8y/ngx-components';
|
|
3
4
|
|
|
4
5
|
@Component({
|
|
5
6
|
selector: 'app-example-button',
|
|
6
|
-
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [CoreModule],
|
|
9
|
+
template: `
|
|
10
|
+
<c8y-title>Query Param Bottom Drawer</c8y-title>
|
|
11
|
+
<div class="card">
|
|
12
|
+
<div class="card-block">
|
|
13
|
+
<p>Click the button to add a query parameter. The bottom drawer will open automatically.</p>
|
|
14
|
+
<button class="btn btn-primary" (click)="addQueryParam()">Add query param</button>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
`
|
|
7
18
|
})
|
|
8
19
|
export class ExampleButtonComponent {
|
|
9
20
|
constructor(
|
|
@@ -3,12 +3,19 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|
|
3
3
|
|
|
4
4
|
@Component({
|
|
5
5
|
selector: 'app-example-component',
|
|
6
|
-
template:
|
|
6
|
+
template: `
|
|
7
|
+
<div class="p-24">
|
|
8
|
+
<h4 class="m-b-16">Query Param Bottom Drawer</h4>
|
|
9
|
+
<p>This drawer was opened via <code>hookQueryParamBottomDrawer</code>.</p>
|
|
10
|
+
<p class="text-muted">
|
|
11
|
+
The URL contains <code>?showExampleComponent=true</code>. Closing this drawer will remove
|
|
12
|
+
the query parameter.
|
|
13
|
+
</p>
|
|
14
|
+
</div>
|
|
7
15
|
<div class="text-center card-footer p-24 separator">
|
|
8
|
-
<button class="btn btn-default"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</div>`
|
|
16
|
+
<button class="btn btn-default" type="button" (click)="close()">Close</button>
|
|
17
|
+
</div>
|
|
18
|
+
`
|
|
12
19
|
})
|
|
13
20
|
export class ExampleComponent {
|
|
14
21
|
shouldClose: Promise<boolean>;
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { Component } from '@angular/core';
|
|
2
2
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
3
|
+
import { CoreModule } from '@c8y/ngx-components';
|
|
3
4
|
|
|
4
5
|
@Component({
|
|
5
6
|
selector: 'app-example-button',
|
|
6
|
-
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [CoreModule],
|
|
9
|
+
template: `
|
|
10
|
+
<c8y-title>Query Param Modal</c8y-title>
|
|
11
|
+
<div class="card">
|
|
12
|
+
<div class="card-block">
|
|
13
|
+
<p>Click the button to add a query parameter. The modal will open automatically.</p>
|
|
14
|
+
<button class="btn btn-primary" (click)="addQueryParam()">Add query param</button>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
`
|
|
7
18
|
})
|
|
8
19
|
export class ExampleButtonComponent {
|
|
9
20
|
constructor(
|
|
@@ -3,10 +3,21 @@ import { BsModalRef } from 'ngx-bootstrap/modal';
|
|
|
3
3
|
|
|
4
4
|
@Component({
|
|
5
5
|
selector: 'app-example-component',
|
|
6
|
-
template:
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
</
|
|
6
|
+
template: `
|
|
7
|
+
<div class="modal-header">
|
|
8
|
+
<h4 class="modal-title">Query Param Modal</h4>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="modal-body">
|
|
11
|
+
<p>This modal was opened via <code>hookQueryParamModal</code>.</p>
|
|
12
|
+
<p class="text-muted">
|
|
13
|
+
The URL contains <code>?showExampleModalComponent=true</code>. Closing this modal will
|
|
14
|
+
remove the query parameter.
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="modal-footer">
|
|
18
|
+
<button class="btn btn-default" type="button" (click)="cancel()">Close</button>
|
|
19
|
+
</div>
|
|
20
|
+
`
|
|
10
21
|
})
|
|
11
22
|
export class ExampleComponent {
|
|
12
23
|
private readonly bsModalRef = inject(BsModalRef);
|
|
@@ -199,6 +199,73 @@ import { Observable, map, timer } from 'rxjs';
|
|
|
199
199
|
></c8y-input-group-editable>
|
|
200
200
|
</div>
|
|
201
201
|
</div>
|
|
202
|
+
|
|
203
|
+
<hr />
|
|
204
|
+
|
|
205
|
+
<!-- MULTILINE -->
|
|
206
|
+
<h4 class="text-medium m-b-24">Multiline</h4>
|
|
207
|
+
<div class="row m-b-24">
|
|
208
|
+
<div class="col-sm-4">
|
|
209
|
+
<p class="text-label-small">Auto-grow (no max-height)</p>
|
|
210
|
+
<c8y-input-group-editable
|
|
211
|
+
[multiline]="true"
|
|
212
|
+
ariaLabel="Notes"
|
|
213
|
+
[(ngModel)]="multilineModel"
|
|
214
|
+
></c8y-input-group-editable>
|
|
215
|
+
<p class="text-muted m-t-4">
|
|
216
|
+
<small>Use <kbd>Ctrl+Enter</kbd> to save, <kbd>Escape</kbd> to cancel.</small>
|
|
217
|
+
</p>
|
|
218
|
+
</div>
|
|
219
|
+
<div class="col-sm-4">
|
|
220
|
+
<p class="text-label-small">With maxHeight="150px"</p>
|
|
221
|
+
<c8y-input-group-editable
|
|
222
|
+
[multiline]="true"
|
|
223
|
+
maxHeight="150px"
|
|
224
|
+
ariaLabel="Description with max height"
|
|
225
|
+
[(ngModel)]="multilineMaxHeightModel"
|
|
226
|
+
></c8y-input-group-editable>
|
|
227
|
+
<p class="text-muted m-t-4">
|
|
228
|
+
<small>Scrolls once content exceeds 150 px.</small>
|
|
229
|
+
</p>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<hr />
|
|
234
|
+
|
|
235
|
+
<!-- FORM-OWNED SAVE (noSaveButton) -->
|
|
236
|
+
<h4 class="text-medium m-b-24">Form-owned save</h4>
|
|
237
|
+
<div class="row m-b-24">
|
|
238
|
+
<div class="col-sm-4">
|
|
239
|
+
<p class="text-label-small">Single-line ([noSaveButton]="true")</p>
|
|
240
|
+
<c8y-input-group-editable
|
|
241
|
+
placeholder="e.g. My app"
|
|
242
|
+
[noSaveButton]="true"
|
|
243
|
+
formGroupClass="m-b-0"
|
|
244
|
+
ariaLabel="Application name"
|
|
245
|
+
[(ngModel)]="noSaveButtonSingle"
|
|
246
|
+
></c8y-input-group-editable>
|
|
247
|
+
<small class="text-muted">Value: {{ noSaveButtonSingle }}</small>
|
|
248
|
+
<p class="text-muted m-t-4">
|
|
249
|
+
<small
|
|
250
|
+
>Buttons hidden. Value updates on every keystroke. <kbd>Escape</kbd> reverts.</small
|
|
251
|
+
>
|
|
252
|
+
</p>
|
|
253
|
+
</div>
|
|
254
|
+
<div class="col-sm-4">
|
|
255
|
+
<p class="text-label-small">Multiline ([noSaveButton]="true")</p>
|
|
256
|
+
<c8y-input-group-editable
|
|
257
|
+
placeholder="e.g. Describe this item"
|
|
258
|
+
[multiline]="true"
|
|
259
|
+
[noSaveButton]="true"
|
|
260
|
+
formGroupClass="m-b-0"
|
|
261
|
+
ariaLabel="Description"
|
|
262
|
+
[(ngModel)]="noSaveButtonMulti"
|
|
263
|
+
></c8y-input-group-editable>
|
|
264
|
+
<p class="text-muted m-t-4">
|
|
265
|
+
<small>Use <kbd>Escape</kbd> to revert.</small>
|
|
266
|
+
</p>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
202
269
|
</div>
|
|
203
270
|
`,
|
|
204
271
|
standalone: true,
|
|
@@ -238,6 +305,15 @@ export class InputGroupEditableExampleComponent {
|
|
|
238
305
|
// Disabled state
|
|
239
306
|
disabledModel = 'Read-only value';
|
|
240
307
|
|
|
308
|
+
// Multiline
|
|
309
|
+
multilineModel = 'Edit this multiline value';
|
|
310
|
+
multilineMaxHeightModel =
|
|
311
|
+
'Edit this value\nAdd more lines to see scrolling kick in once the height cap is reached';
|
|
312
|
+
|
|
313
|
+
// Form-owned save (noSaveButton)
|
|
314
|
+
noSaveButtonSingle = 'My Application';
|
|
315
|
+
noSaveButtonMulti = 'Edit me — no Save button.\nEscape to revert.';
|
|
316
|
+
|
|
241
317
|
// Async validation — simulates a server-side uniqueness check
|
|
242
318
|
readonly asyncFormControl = new FormControl('available', { nonNullable: true });
|
|
243
319
|
|
package/tsconfig.app.json
CHANGED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
@import '~@c8y/style/extend.less';
|
|
2
|
-
|
|
3
|
-
// // to hide the Cumulocity IoT logo on top of navigator
|
|
4
|
-
// // set @extending to true
|
|
5
|
-
@extending: false;
|
|
6
|
-
|
|
7
|
-
// Replace and uncomment each variable as you need them
|
|
8
|
-
|
|
9
|
-
/* COLORS */
|
|
10
|
-
// @brand-color: #53cd61; // main color
|
|
11
|
-
// @brand-primary: @brand-color;
|
|
12
|
-
// @brand-complementary: #a8b3b5;
|
|
13
|
-
// @brand-primary-light: lighten(@brand-primary, 20%);
|
|
14
|
-
// // status colors
|
|
15
|
-
// @status-success: #5cb85c;
|
|
16
|
-
// @status-info: @brand-color;
|
|
17
|
-
// @status-warning: #f0ad4e;
|
|
18
|
-
// @status-danger: #d9534f;
|
|
19
|
-
// @danger: #d90000;
|
|
20
|
-
// @warning: #fdc000;
|
|
21
|
-
// @status-warning-dark: #ff8000;
|
|
22
|
-
// @success: #5cb85c;
|
|
23
|
-
// grays
|
|
24
|
-
// @text-color: #444;
|
|
25
|
-
// @gray-30: #3b4748;
|
|
26
|
-
// @gray-40: #49595b;
|
|
27
|
-
// @gray-40: #6d7a7c;
|
|
28
|
-
// // @gray: #8a9596;
|
|
29
|
-
// @gray-80: #cacece;
|
|
30
|
-
// @gray-90: #f8f8f8;
|
|
31
|
-
// @gray-100: #fcfcfc;
|
|
32
|
-
// @text-muted: @gray-50;
|
|
33
|
-
|
|
34
|
-
// @body-background-color: #f8f8f8; // page background color - always use a light background
|
|
35
|
-
|
|
36
|
-
/* HEADER */
|
|
37
|
-
// @headerColor: white;
|
|
38
|
-
// @header-text-color: @gray-40;
|
|
39
|
-
// @header-text-color-hover: @brand-primary;
|
|
40
|
-
// @header-color-active: darken(@gray-40, 15%);
|
|
41
|
-
|
|
42
|
-
/* NAVIGATOR */
|
|
43
|
-
// @navColor: @gray-10;
|
|
44
|
-
// @navColorHeader: @gray-10;
|
|
45
|
-
// @navigator-header-color: white;
|
|
46
|
-
// @navigator-text-color: @gray-100;
|
|
47
|
-
// @navigator-separator-color: fade(white, 5%);
|
|
48
|
-
// @navigator-font-family: @headings-font-family;
|
|
49
|
-
// @navigator-font-size: 13px;
|
|
50
|
-
// @navigator-color-active: white;
|
|
51
|
-
// @navigator-active-bg: @brand-primary;
|
|
52
|
-
// when set adds a vertical gradient in the navigator background
|
|
53
|
-
// @grad-top: "";
|
|
54
|
-
// @grad-bottom: "";
|
|
55
|
-
|
|
56
|
-
/* TYPOGRAPHY */
|
|
57
|
-
// @font-family-sans-serif: "Lato",Arial, Verdana, sans-serif;
|
|
58
|
-
// @font-family-base: @font-family-sans-serif;
|
|
59
|
-
// @headings-font-family: "Roboto",Arial, Verdana, sans-serif;
|
|
60
|
-
|
|
61
|
-
/* BUTTONS */
|
|
62
|
-
// @component-border-radius-base-base: 2px;
|
|
63
|
-
// @component-border-radius-base-large: @component-border-radius-base-base;
|
|
64
|
-
// @component-border-radius-base-small: @component-border-radius-base-base;
|
|
65
|
-
// @btn-shadow: none;
|
|
66
|
-
|
|
67
|
-
/* COMPONENTS */
|
|
68
|
-
// @spinner-color: lighten(@brand-primary, 30%);
|
|
69
|
-
// @link-color: #337ab7;
|
|
70
|
-
// @link-color-hover: darken(@link-color, 15%);
|
|
71
|
-
// @form-control-border-color-focus: #66afe9;
|
|
72
|
-
|
|
73
|
-
// @body-background-pattern: "";
|
|
74
|
-
// @darker-header: @gray-30;
|
|
75
|
-
// @appswitcher-background: none;
|
|
76
|
-
// @component-background-hover: fade(black, 1.5%);
|
|
77
|
-
// @header-app-name: @header-text-color;
|
|
78
|
-
// @image-path: 'img/';
|
package/src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.component.less
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
@background-color: #e6f7ff;
|
|
2
|
-
@border-color: #91d5ff;
|
|
3
|
-
|
|
4
|
-
.less-example {
|
|
5
|
-
background-color: @background-color;
|
|
6
|
-
padding: 15px;
|
|
7
|
-
border: 1px solid @border-color;
|
|
8
|
-
|
|
9
|
-
h5 {
|
|
10
|
-
color: darken(@border-color, 30%);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
p {
|
|
14
|
-
color: darken(@background-color, 50%);
|
|
15
|
-
}
|
|
16
|
-
}
|
package/src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.component.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import { HeaderModule } from '@c8y/ngx-components';
|
|
3
|
-
|
|
4
|
-
@Component({
|
|
5
|
-
selector: 'tut-leaner-style-sheets-example',
|
|
6
|
-
template: `<c8y-title>LESS component styles</c8y-title>
|
|
7
|
-
<div class="less-example">
|
|
8
|
-
<h5>LESS Styles</h5>
|
|
9
|
-
<p>This is styled with LESS</p>
|
|
10
|
-
</div>`,
|
|
11
|
-
styleUrls: ['./leaner-style-sheets-example.component.less'],
|
|
12
|
-
standalone: true,
|
|
13
|
-
imports: [HeaderModule]
|
|
14
|
-
})
|
|
15
|
-
export class LeanerStyleSheetsExampleComponent {}
|
package/src/component-styles/leaner-style-sheets-example/leaner-style-sheets-example.module.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { NgModule } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import { NavigatorNode, hookNavigator, hookRoute } from '@c8y/ngx-components';
|
|
4
|
-
|
|
5
|
-
@NgModule({
|
|
6
|
-
imports: [CommonModule],
|
|
7
|
-
providers: [
|
|
8
|
-
hookRoute({
|
|
9
|
-
path: 'component-styles/less',
|
|
10
|
-
loadComponent: () =>
|
|
11
|
-
import('./leaner-style-sheets-example.component').then(
|
|
12
|
-
m => m.LeanerStyleSheetsExampleComponent
|
|
13
|
-
)
|
|
14
|
-
}),
|
|
15
|
-
hookNavigator(
|
|
16
|
-
new NavigatorNode({
|
|
17
|
-
path: '/component-styles/less',
|
|
18
|
-
label: 'LESS',
|
|
19
|
-
icon: 'c8y-css',
|
|
20
|
-
priority: 79,
|
|
21
|
-
parent: 'Component styles'
|
|
22
|
-
})
|
|
23
|
-
)
|
|
24
|
-
]
|
|
25
|
-
})
|
|
26
|
-
export class LeanerStyleSheetsExampleModule {}
|