@c8y/ngx-components 1021.73.6 → 1021.74.1
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/branding/shared/data/store-branding.service.d.ts.map +1 -1
- package/core/date-time-picker/date-time-picker.component.d.ts +4 -1
- package/core/date-time-picker/date-time-picker.component.d.ts.map +1 -1
- package/esm2022/branding/shared/data/store-branding.service.mjs +13 -4
- package/esm2022/core/date-time-picker/date-time-picker.component.mjs +27 -14
- package/esm2022/remote-access/configurations/remote-access-configuration-list/remote-access-configuration-list.component.mjs +15 -10
- package/esm2022/remote-access/configurations/remote-access-pick-protocol-modal/remote-access-pick-protocol-modal.component.mjs +9 -12
- package/esm2022/remote-access/data/remote-access.service.mjs +12 -1
- package/fesm2022/c8y-ngx-components-branding-shared-data.mjs +12 -3
- package/fesm2022/c8y-ngx-components-branding-shared-data.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs +24 -20
- package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-data.mjs +11 -0
- package/fesm2022/c8y-ngx-components-remote-access-data.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +26 -13
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/locales/de.po +1 -1
- package/locales/es.po +5 -5
- package/locales/fr.po +1 -1
- package/locales/ko.po +2 -1
- package/locales/pl.po +1 -1
- package/locales/pt_BR.po +1 -1
- package/package.json +1 -1
- package/remote-access/configurations/remote-access-configuration-list/remote-access-configuration-list.component.d.ts +4 -2
- package/remote-access/configurations/remote-access-configuration-list/remote-access-configuration-list.component.d.ts.map +1 -1
- package/remote-access/configurations/remote-access-pick-protocol-modal/remote-access-pick-protocol-modal.component.d.ts +2 -3
- package/remote-access/configurations/remote-access-pick-protocol-modal/remote-access-pick-protocol-modal.component.d.ts.map +1 -1
- package/remote-access/data/remote-access.service.d.ts +8 -2
- package/remote-access/data/remote-access.service.d.ts.map +1 -1
|
@@ -5,6 +5,7 @@ import * as i2 from '@c8y/ngx-components';
|
|
|
5
5
|
import { Permissions, ContextRouteService, ViewContext } from '@c8y/ngx-components';
|
|
6
6
|
import { gettext } from '@c8y/ngx-components/gettext';
|
|
7
7
|
import { defer, shareReplay } from 'rxjs';
|
|
8
|
+
import { uniqWith, isEqual, intersectionWith } from 'lodash';
|
|
8
9
|
|
|
9
10
|
const CREDENTIALS_TYPES = {
|
|
10
11
|
NONE: {
|
|
@@ -124,6 +125,16 @@ class RemoteAccessService {
|
|
|
124
125
|
getProtocolProviders() {
|
|
125
126
|
return this.serviceRegistry.get('remoteAccessProtocolHook');
|
|
126
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Retrieves all supported protocol providers for a given device.
|
|
130
|
+
* Based on the declarations in the fragment c8y_RemoteAccessSupportedProtocols of the device managed object.
|
|
131
|
+
*/
|
|
132
|
+
getSupportedProtocolProvidersFor(device) {
|
|
133
|
+
const { c8y_RemoteAccessSupportedProtocols = [] } = device;
|
|
134
|
+
const uniqueInput = uniqWith(c8y_RemoteAccessSupportedProtocols.map(p => p.toUpperCase()), isEqual);
|
|
135
|
+
const supportedProviders = intersectionWith(this.getProtocolProviders(), uniqueInput, ({ protocolName }, protocol) => protocolName?.toUpperCase() === protocol);
|
|
136
|
+
return supportedProviders?.length > 0 ? supportedProviders : this.getProtocolProviders();
|
|
137
|
+
}
|
|
127
138
|
/**
|
|
128
139
|
* Creates a new configuration for a given device.
|
|
129
140
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"c8y-ngx-components-remote-access-data.mjs","sources":["../../remote-access/data/remote-access.service.ts","../../remote-access/data/c8y-ngx-components-remote-access-data.ts"],"sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivateFn } from '@angular/router';\nimport { FetchClient, IManagedObject } from '@c8y/client';\nimport {\n ContextRouteService,\n Permissions,\n ServiceRegistry,\n ViewContext\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { Observable, defer, shareReplay } from 'rxjs';\n\nexport interface RemoteAccessConfiguration {\n id: string;\n name: string;\n hostname: string;\n port: number;\n protocol: string;\n attrs?: any;\n credentials?: any;\n credentialsType?: string;\n}\n\nexport const CREDENTIALS_TYPES = {\n NONE: {\n name: 'NONE',\n value: 'NONE',\n label: gettext('No password')\n },\n USER_PASS: {\n name: 'USER_PASS',\n value: 'USER_PASS',\n label: gettext('Username and password')\n },\n PASS_ONLY: {\n name: 'PASS_ONLY',\n value: 'PASS_ONLY',\n label: gettext('Password only')\n },\n KEY_PAIR: {\n name: 'KEY_PAIR',\n value: 'KEY_PAIR',\n label: gettext('Public/private keys')\n },\n CERTIFICATE: {\n name: 'CERTIFICATE',\n value: 'CERTIFICATE',\n label: gettext('Certificate')\n }\n} as const;\n\nexport const canActivateRemoteAccess: CanActivateFn = (route: ActivatedRouteSnapshot) => {\n const permissions = inject(Permissions);\n const remoteAccessService = inject(RemoteAccessService);\n const contextRouteService = inject(ContextRouteService);\n if (!permissions.hasRole(Permissions.ROLE_REMOTE_ACCESS_ADMIN)) {\n return false;\n }\n\n const contextDetails = contextRouteService.getContextData(route);\n if (contextDetails.context !== ViewContext.Device) {\n return false;\n }\n\n const device = contextDetails.contextData as IManagedObject;\n if (!device || !Array.isArray(device.c8y_SupportedOperations)) {\n return false;\n }\n const supportedOperations: string[] = device.c8y_SupportedOperations;\n if (!supportedOperations.includes('c8y_RemoteAccessConnect')) {\n return false;\n }\n return remoteAccessService.isAvailable$();\n};\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RemoteAccessService {\n private cachedIsAvailable$: Observable<boolean>;\n readonly baseUrl = '/service/remoteaccess';\n constructor(\n private fetchClient: FetchClient,\n private serviceRegistry: ServiceRegistry\n ) {}\n\n /**\n * Verifies if the remote access service is available by sending a HEAD request to is's health endpoint.\n * @returns cached Observable that emits true if the service is available, false otherwise.\n */\n isAvailable$(): Observable<boolean> {\n if (!this.cachedIsAvailable$) {\n this.cachedIsAvailable$ = defer(() => this.healthEndpointAvailable()).pipe(shareReplay(1));\n }\n\n return this.cachedIsAvailable$;\n }\n\n /**\n * misses the leading ? for the query params\n */\n getAuthQueryParamsForWebsocketConnection() {\n const { headers } = this.fetchClient.getFetchOptions();\n const params = new URLSearchParams();\n\n if (headers) {\n const xsrfToken = headers['X-XSRF-TOKEN'];\n const auth = headers['Authorization'];\n\n if (xsrfToken) {\n params.append('XSRF-TOKEN', xsrfToken);\n }\n if (auth) {\n params.append('token', auth.replace('Bearer ', '').replace('Basic ', ''));\n }\n }\n\n const paramsString = params.toString();\n return paramsString;\n }\n\n /**\n * Returns the URI for the websocket connection to the remote access service.\n */\n getWebSocketUri<K extends string, I extends string>(deviceId: K, configurationId: I) {\n const authQueryParams = this.getAuthQueryParamsForWebsocketConnection();\n const protocol = window.location.protocol === 'http:' ? 'ws' : 'wss';\n const pathName =\n `${protocol}://${window.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}` as const;\n return authQueryParams ? (`${pathName}?${authQueryParams}` as const) : pathName;\n }\n\n /**\n * Retrieves all configurations for a given device.\n */\n async listConfigurations(deviceId: string): Promise<RemoteAccessConfiguration[]> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`\n );\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to fetch configurations for device ${deviceId}`);\n }\n\n /**\n * Deletes a configuration for a given device.\n */\n async deleteConfiguration(deviceId: string, configurationId: string) {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}`,\n { method: 'DELETE' }\n );\n\n if (response.ok) {\n return;\n }\n\n throw new Error(`Failed to delete configuration for device ${deviceId}`);\n }\n\n /**\n * Retrieves all available remote access protocol providers.\n */\n getProtocolProviders() {\n return this.serviceRegistry.get('remoteAccessProtocolHook');\n }\n\n /**\n * Creates a new configuration for a given device.\n */\n async addConfiguration(\n deviceId: string,\n configuration: Omit<RemoteAccessConfiguration, 'id'>\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to add configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Updates a configuration for a given device.\n */\n async updateConfiguration(\n deviceId: string,\n configuration: RemoteAccessConfiguration\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configuration.id}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to update configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Generates a SSH key pair for a given hostname.\n */\n async generateKeyPair(hostname: string): Promise<{ publicKey: string; privateKey: string }> {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/keypair/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ hostname })\n });\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to generate key pair for ${hostname}`);\n }\n\n private async healthEndpointAvailable(): Promise<boolean> {\n try {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/health`, {\n method: 'HEAD',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (response.ok) {\n return !!response.ok;\n }\n } catch (e) {\n return false;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"c8y-ngx-components-remote-access-data.mjs","sources":["../../remote-access/data/remote-access.service.ts","../../remote-access/data/c8y-ngx-components-remote-access-data.ts"],"sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivateFn } from '@angular/router';\nimport { FetchClient, IManagedObject } from '@c8y/client';\nimport {\n ContextRouteService,\n Permissions,\n ServiceRegistry,\n ViewContext\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { Observable, defer, shareReplay } from 'rxjs';\nimport { RemoteAccessProtocolProvider } from './remote-access-protocol-provider';\nimport { uniqWith, intersectionWith, isEqual } from 'lodash';\n\nexport interface RemoteAccessConfiguration {\n id: string;\n name: string;\n hostname: string;\n port: number;\n protocol: string;\n attrs?: any;\n credentials?: any;\n credentialsType?: string;\n}\n\nexport const CREDENTIALS_TYPES = {\n NONE: {\n name: 'NONE',\n value: 'NONE',\n label: gettext('No password')\n },\n USER_PASS: {\n name: 'USER_PASS',\n value: 'USER_PASS',\n label: gettext('Username and password')\n },\n PASS_ONLY: {\n name: 'PASS_ONLY',\n value: 'PASS_ONLY',\n label: gettext('Password only')\n },\n KEY_PAIR: {\n name: 'KEY_PAIR',\n value: 'KEY_PAIR',\n label: gettext('Public/private keys')\n },\n CERTIFICATE: {\n name: 'CERTIFICATE',\n value: 'CERTIFICATE',\n label: gettext('Certificate')\n }\n} as const;\n\nexport const canActivateRemoteAccess: CanActivateFn = (route: ActivatedRouteSnapshot) => {\n const permissions = inject(Permissions);\n const remoteAccessService = inject(RemoteAccessService);\n const contextRouteService = inject(ContextRouteService);\n if (!permissions.hasRole(Permissions.ROLE_REMOTE_ACCESS_ADMIN)) {\n return false;\n }\n\n const contextDetails = contextRouteService.getContextData(route);\n if (contextDetails.context !== ViewContext.Device) {\n return false;\n }\n\n const device = contextDetails.contextData as IManagedObject;\n if (!device || !Array.isArray(device.c8y_SupportedOperations)) {\n return false;\n }\n const supportedOperations: string[] = device.c8y_SupportedOperations;\n if (!supportedOperations.includes('c8y_RemoteAccessConnect')) {\n return false;\n }\n return remoteAccessService.isAvailable$();\n};\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RemoteAccessService {\n private cachedIsAvailable$: Observable<boolean>;\n readonly baseUrl = '/service/remoteaccess';\n constructor(\n private fetchClient: FetchClient,\n private serviceRegistry: ServiceRegistry\n ) {}\n\n /**\n * Verifies if the remote access service is available by sending a HEAD request to is's health endpoint.\n * @returns cached Observable that emits true if the service is available, false otherwise.\n */\n isAvailable$(): Observable<boolean> {\n if (!this.cachedIsAvailable$) {\n this.cachedIsAvailable$ = defer(() => this.healthEndpointAvailable()).pipe(shareReplay(1));\n }\n\n return this.cachedIsAvailable$;\n }\n\n /**\n * misses the leading ? for the query params\n */\n getAuthQueryParamsForWebsocketConnection() {\n const { headers } = this.fetchClient.getFetchOptions();\n const params = new URLSearchParams();\n\n if (headers) {\n const xsrfToken = headers['X-XSRF-TOKEN'];\n const auth = headers['Authorization'];\n\n if (xsrfToken) {\n params.append('XSRF-TOKEN', xsrfToken);\n }\n if (auth) {\n params.append('token', auth.replace('Bearer ', '').replace('Basic ', ''));\n }\n }\n\n const paramsString = params.toString();\n return paramsString;\n }\n\n /**\n * Returns the URI for the websocket connection to the remote access service.\n */\n getWebSocketUri<K extends string, I extends string>(deviceId: K, configurationId: I) {\n const authQueryParams = this.getAuthQueryParamsForWebsocketConnection();\n const protocol = window.location.protocol === 'http:' ? 'ws' : 'wss';\n const pathName =\n `${protocol}://${window.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}` as const;\n return authQueryParams ? (`${pathName}?${authQueryParams}` as const) : pathName;\n }\n\n /**\n * Retrieves all configurations for a given device.\n */\n async listConfigurations(deviceId: string): Promise<RemoteAccessConfiguration[]> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`\n );\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to fetch configurations for device ${deviceId}`);\n }\n\n /**\n * Deletes a configuration for a given device.\n */\n async deleteConfiguration(deviceId: string, configurationId: string) {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}`,\n { method: 'DELETE' }\n );\n\n if (response.ok) {\n return;\n }\n\n throw new Error(`Failed to delete configuration for device ${deviceId}`);\n }\n\n /**\n * Retrieves all available remote access protocol providers.\n */\n getProtocolProviders() {\n return this.serviceRegistry.get('remoteAccessProtocolHook');\n }\n\n /**\n * Retrieves all supported protocol providers for a given device.\n * Based on the declarations in the fragment c8y_RemoteAccessSupportedProtocols of the device managed object.\n */\n getSupportedProtocolProvidersFor(device: IManagedObject): RemoteAccessProtocolProvider[] {\n const { c8y_RemoteAccessSupportedProtocols = [] } = device;\n const uniqueInput = uniqWith(\n c8y_RemoteAccessSupportedProtocols.map(p => p.toUpperCase()),\n isEqual\n );\n const supportedProviders = intersectionWith(\n this.getProtocolProviders(),\n uniqueInput,\n ({ protocolName }, protocol) => protocolName?.toUpperCase() === protocol\n );\n return supportedProviders?.length > 0 ? supportedProviders : this.getProtocolProviders();\n }\n\n /**\n * Creates a new configuration for a given device.\n */\n async addConfiguration(\n deviceId: string,\n configuration: Omit<RemoteAccessConfiguration, 'id'>\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to add configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Updates a configuration for a given device.\n */\n async updateConfiguration(\n deviceId: string,\n configuration: RemoteAccessConfiguration\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configuration.id}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to update configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Generates a SSH key pair for a given hostname.\n */\n async generateKeyPair(hostname: string): Promise<{ publicKey: string; privateKey: string }> {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/keypair/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ hostname })\n });\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to generate key pair for ${hostname}`);\n }\n\n private async healthEndpointAvailable(): Promise<boolean> {\n try {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/health`, {\n method: 'HEAD',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (response.ok) {\n return !!response.ok;\n }\n } catch (e) {\n return false;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -26205,8 +26205,8 @@ class DateTimePickerComponent {
|
|
|
26205
26205
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
26206
26206
|
this.onTouched = () => { };
|
|
26207
26207
|
this.form = new FormGroup({});
|
|
26208
|
-
this.form.addControl('date', new FormControl(
|
|
26209
|
-
this.form.addControl('time', new FormControl(
|
|
26208
|
+
this.form.addControl('date', new FormControl(undefined));
|
|
26209
|
+
this.form.addControl('time', new FormControl(undefined));
|
|
26210
26210
|
this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
|
26211
26211
|
this.setDatetime(value);
|
|
26212
26212
|
this.previousValue = value;
|
|
@@ -26233,19 +26233,26 @@ class DateTimePickerComponent {
|
|
|
26233
26233
|
ngAfterViewInit() {
|
|
26234
26234
|
this.cd.detectChanges();
|
|
26235
26235
|
}
|
|
26236
|
+
onTimeChange(time) {
|
|
26237
|
+
this.form.get('time').setValue(time, { emitEvent: true });
|
|
26238
|
+
}
|
|
26239
|
+
get dateControl() {
|
|
26240
|
+
return this.form.get('date');
|
|
26241
|
+
}
|
|
26236
26242
|
/**
|
|
26237
26243
|
* Control Value Accessor - If form value changes by external factor, update date property and internal form with new value.
|
|
26238
26244
|
*/
|
|
26239
26245
|
writeValue(value) {
|
|
26240
26246
|
if (typeof value === 'string' && value.length) {
|
|
26241
26247
|
this.date = new Date(value);
|
|
26248
|
+
this.time = this.date;
|
|
26242
26249
|
this.form.setValue({
|
|
26243
26250
|
date: new Date(value),
|
|
26244
26251
|
time: this.date
|
|
26245
26252
|
}, { emitEvent: false });
|
|
26246
26253
|
}
|
|
26247
26254
|
else {
|
|
26248
|
-
|
|
26255
|
+
return;
|
|
26249
26256
|
}
|
|
26250
26257
|
this.previousValue = this.form.value;
|
|
26251
26258
|
}
|
|
@@ -26324,27 +26331,33 @@ class DateTimePickerComponent {
|
|
|
26324
26331
|
// if date input is cleared from a previous correct value, clear form value:
|
|
26325
26332
|
if (this.isInputCleared(dateTime)) {
|
|
26326
26333
|
this.form.get('date').setValue(undefined, { emitEvent: false });
|
|
26334
|
+
this.time = undefined;
|
|
26327
26335
|
this.form.get('time').setValue(undefined, { emitEvent: false });
|
|
26328
26336
|
this.onChange(null);
|
|
26329
26337
|
return;
|
|
26330
26338
|
}
|
|
26339
|
+
const validTime = this.verifyDate(dateTime.time);
|
|
26340
|
+
const validExistingTime = this.verifyDate(this.time);
|
|
26341
|
+
const validDate = this.verifyDate(dateTime.date);
|
|
26342
|
+
if (!validTime && !validExistingTime) {
|
|
26343
|
+
// Ensure dateTime.date exists before using getFullYear:
|
|
26344
|
+
if (dateTime.date) {
|
|
26345
|
+
dateTime.time = new Date(dateTime.date.getFullYear(), dateTime.date.getMonth(), dateTime.date.getDate(), 0, 0, 0);
|
|
26346
|
+
this.time = dateTime.time;
|
|
26347
|
+
}
|
|
26348
|
+
}
|
|
26331
26349
|
// if both date and time is invalid, do set form value to null and stop:
|
|
26332
|
-
if (!
|
|
26350
|
+
if (!validDate && !validTime) {
|
|
26333
26351
|
this.onChange(null);
|
|
26334
26352
|
return;
|
|
26335
26353
|
}
|
|
26336
26354
|
// If only time is provided, set Date to today:
|
|
26337
|
-
if (!
|
|
26355
|
+
if (!validDate && validTime) {
|
|
26338
26356
|
dateTime.date = new Date(dateTime.time);
|
|
26339
26357
|
}
|
|
26340
|
-
// If only date is provided, set time to 00:00:
|
|
26341
|
-
if (this.verifyDate(dateTime.date) && !this.verifyDate(dateTime.time)) {
|
|
26342
|
-
dateTime.time = new Date(dateTime.date.getFullYear(), dateTime.date.getMonth(), dateTime.date.getDate(), 0, 0, 0);
|
|
26343
|
-
this.form.get('time').setValue(dateTime.time, { emitEvent: false });
|
|
26344
|
-
}
|
|
26345
26358
|
// Merge date and time, and emit as new form value:
|
|
26346
26359
|
this.date = new Date(dateTime.date);
|
|
26347
|
-
this.date.setHours(
|
|
26360
|
+
this.date.setHours(this.time.getHours(), this.time.getMinutes());
|
|
26348
26361
|
this.form.get('date').setValue(dateTime.date, { emitEvent: false });
|
|
26349
26362
|
this.onChange(this.date.toISOString());
|
|
26350
26363
|
}
|
|
@@ -26367,7 +26380,7 @@ class DateTimePickerComponent {
|
|
|
26367
26380
|
useExisting: forwardRef(() => DateTimePickerComponent),
|
|
26368
26381
|
multi: true
|
|
26369
26382
|
}
|
|
26370
|
-
], viewQueries: [{ propertyName: "datepicker", first: true, predicate: BsDatepickerDirective, descendants: true }], ngImport: i0, template: "<div\n class=\"datetime-picker\"\n [ngSwitch]=\"dateType\"\n>\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'DateAndTime'\"\n [closeDatepicker]=\"datepicker\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n data-cy=\"bootstrap-date-input\"\n style=\"min-width: 120px\"\n [placeholder]=\"placeholder || defaultPlaceholder | translate\"\n bsDatepicker\n [outsideClick]=\"false\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n dateInputFormat: dateInputFormat,\n adaptivePosition: adaptivePosition\n }\"\n [formControl]=\"
|
|
26383
|
+
], viewQueries: [{ propertyName: "datepicker", first: true, predicate: BsDatepickerDirective, descendants: true }], ngImport: i0, template: "<div\n class=\"datetime-picker\"\n [ngSwitch]=\"dateType\"\n>\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'DateAndTime'\"\n [closeDatepicker]=\"datepicker\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n data-cy=\"bootstrap-date-input\"\n style=\"min-width: 120px\"\n [placeholder]=\"placeholder || defaultPlaceholder | translate\"\n bsDatepicker\n [outsideClick]=\"false\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n dateInputFormat: dateInputFormat,\n adaptivePosition: adaptivePosition\n }\"\n [formControl]=\"dateControl\"\n (blur)=\"onTouched()\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n />\n </div>\n <timepicker\n class=\"form-group {{ size ? 'form-group-' + size : '' }}\"\n [(ngModel)]=\"time\"\n (ngModelChange)=\"onTimeChange($event)\"\n [showSeconds]=\"config.showSeconds\"\n [showSpinners]=\"config.showSpinners\"\n [showMeridian]=\"config.showMeridian\"\n (wheel)=\"handleMouseWheel($event)\"\n ></timepicker>\n </div>\n\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'Date'\"\n [closeDatepicker]=\"datepicker\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n [placeholder]=\"placeholder || defaultPlaceholder | translate\"\n bsDatepicker\n [outsideClick]=\"false\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n dateInputFormat: dateInputFormat,\n adaptivePosition: adaptivePosition\n }\"\n [formControl]=\"dateControl\"\n (blur)=\"onTouched()\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n />\n </div>\n </div>\n\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'DateRange'\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'Select a date range' | translate }}\"\n [formControl]=\"dateControl\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n adaptivePosition: true,\n rangeInputFormat: dateInputFormat\n }\"\n bsDaterangepicker\n />\n </div>\n </div>\n\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'Time'\"\n >\n <timepicker\n class=\"form-group {{ size ? 'form-group-' + size : '' }}\"\n [(ngModel)]=\"time\"\n (ngModelChange)=\"onTimeChange($event)\"\n [showSeconds]=\"config.showSeconds\"\n [showSpinners]=\"config.showSpinners\"\n [showMeridian]=\"config.showMeridian\"\n [minutesPlaceholder]=\"'MM`MINUTES`' | translate\"\n [hoursPlaceholder]=\"'HH`HOURS`' | translate\"\n [secondsPlaceholder]=\"'SS`SECONDS`' | translate\"\n (wheel)=\"handleMouseWheel($event)\"\n ></timepicker>\n </div>\n\n <div *ngSwitchCase=\"'SingleDateRequired'\">\n <div class=\"form-group {{ size ? 'form-group-' + size : '' }}\">\n <c8y-date-picker (onDateSelected)=\"onDateSelected.emit($event)\"></c8y-date-picker>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: CloseDatePickerDirective, selector: "[closeDatepicker]", inputs: ["closeDatepicker"] }, { kind: "ngmodule", type: BsDatepickerModule }, { kind: "directive", type: i2.BsDatepickerDirective, selector: "[bsDatepicker]", inputs: ["placement", "triggers", "outsideClick", "container", "outsideEsc", "isDisabled", "minDate", "maxDate", "minMode", "daysDisabled", "datesDisabled", "datesEnabled", "dateCustomClasses", "dateTooltipTexts", "isOpen", "bsValue", "bsConfig"], outputs: ["onShown", "onHidden", "bsValueChange"], exportAs: ["bsDatepicker"] }, { kind: "directive", type: i2.BsDatepickerInputDirective, selector: "input[bsDatepicker]" }, { kind: "directive", type: i2.BsDaterangepickerDirective, selector: "[bsDaterangepicker]", inputs: ["placement", "triggers", "outsideClick", "container", "outsideEsc", "isOpen", "bsValue", "bsConfig", "isDisabled", "minDate", "maxDate", "dateCustomClasses", "daysDisabled", "datesDisabled", "datesEnabled"], outputs: ["onShown", "onHidden", "bsValueChange"], exportAs: ["bsDaterangepicker"] }, { kind: "directive", type: i2.BsDaterangepickerInputDirective, selector: "input[bsDaterangepicker]" }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i2$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TimepickerModule }, { kind: "component", type: i4$1.TimepickerComponent, selector: "timepicker", inputs: ["hourStep", "minuteStep", "secondsStep", "readonlyInput", "disabled", "mousewheel", "arrowkeys", "showSpinners", "showMeridian", "showMinutes", "showSeconds", "meridians", "min", "max", "hoursPlaceholder", "minutesPlaceholder", "secondsPlaceholder"], outputs: ["isValid", "meridianChange"] }, { kind: "component", type: DatePickerComponent, selector: "c8y-date-picker", inputs: ["placeholder", "dateInputFormat"], outputs: ["onDateSelected"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
|
|
26371
26384
|
}
|
|
26372
26385
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DateTimePickerComponent, decorators: [{
|
|
26373
26386
|
type: Component,
|
|
@@ -26392,7 +26405,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
26392
26405
|
TimepickerModule,
|
|
26393
26406
|
DatePickerComponent,
|
|
26394
26407
|
C8yTranslatePipe
|
|
26395
|
-
], template: "<div\n class=\"datetime-picker\"\n [ngSwitch]=\"dateType\"\n>\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'DateAndTime'\"\n [closeDatepicker]=\"datepicker\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n data-cy=\"bootstrap-date-input\"\n style=\"min-width: 120px\"\n [placeholder]=\"placeholder || defaultPlaceholder | translate\"\n bsDatepicker\n [outsideClick]=\"false\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n dateInputFormat: dateInputFormat,\n adaptivePosition: adaptivePosition\n }\"\n [formControl]=\"
|
|
26408
|
+
], template: "<div\n class=\"datetime-picker\"\n [ngSwitch]=\"dateType\"\n>\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'DateAndTime'\"\n [closeDatepicker]=\"datepicker\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n data-cy=\"bootstrap-date-input\"\n style=\"min-width: 120px\"\n [placeholder]=\"placeholder || defaultPlaceholder | translate\"\n bsDatepicker\n [outsideClick]=\"false\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n dateInputFormat: dateInputFormat,\n adaptivePosition: adaptivePosition\n }\"\n [formControl]=\"dateControl\"\n (blur)=\"onTouched()\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n />\n </div>\n <timepicker\n class=\"form-group {{ size ? 'form-group-' + size : '' }}\"\n [(ngModel)]=\"time\"\n (ngModelChange)=\"onTimeChange($event)\"\n [showSeconds]=\"config.showSeconds\"\n [showSpinners]=\"config.showSpinners\"\n [showMeridian]=\"config.showMeridian\"\n (wheel)=\"handleMouseWheel($event)\"\n ></timepicker>\n </div>\n\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'Date'\"\n [closeDatepicker]=\"datepicker\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n [placeholder]=\"placeholder || defaultPlaceholder | translate\"\n bsDatepicker\n [outsideClick]=\"false\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n dateInputFormat: dateInputFormat,\n adaptivePosition: adaptivePosition\n }\"\n [formControl]=\"dateControl\"\n (blur)=\"onTouched()\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n />\n </div>\n </div>\n\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'DateRange'\"\n >\n <div class=\"form-group datepicker {{ size ? 'form-group-' + size : '' }}\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'Select a date range' | translate }}\"\n [formControl]=\"dateControl\"\n [bsConfig]=\"{\n customTodayClass: 'today',\n adaptivePosition: true,\n rangeInputFormat: dateInputFormat\n }\"\n bsDaterangepicker\n />\n </div>\n </div>\n\n <div\n class=\"d-contents\"\n *ngSwitchCase=\"'Time'\"\n >\n <timepicker\n class=\"form-group {{ size ? 'form-group-' + size : '' }}\"\n [(ngModel)]=\"time\"\n (ngModelChange)=\"onTimeChange($event)\"\n [showSeconds]=\"config.showSeconds\"\n [showSpinners]=\"config.showSpinners\"\n [showMeridian]=\"config.showMeridian\"\n [minutesPlaceholder]=\"'MM`MINUTES`' | translate\"\n [hoursPlaceholder]=\"'HH`HOURS`' | translate\"\n [secondsPlaceholder]=\"'SS`SECONDS`' | translate\"\n (wheel)=\"handleMouseWheel($event)\"\n ></timepicker>\n </div>\n\n <div *ngSwitchCase=\"'SingleDateRequired'\">\n <div class=\"form-group {{ size ? 'form-group-' + size : '' }}\">\n <c8y-date-picker (onDateSelected)=\"onDateSelected.emit($event)\"></c8y-date-picker>\n </div>\n </div>\n</div>\n" }]
|
|
26396
26409
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: DateFormatService }], propDecorators: { _minDate: [{
|
|
26397
26410
|
type: Input,
|
|
26398
26411
|
args: ['minDate']
|