UI: Add support name conflict strategy

This commit is contained in:
Vladyslav_Prykhodko 2025-10-10 18:35:41 +03:00
parent f1da967a7d
commit e8d888e22b
8 changed files with 81 additions and 22 deletions

View File

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { createDefaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
@ -23,6 +23,7 @@ import { PageData } from '@shared/models/page/page-data';
import { EntitySubtype } from '@shared/models/entity-type.models';
import { Asset, AssetInfo, AssetSearchQuery } from '@shared/models/asset.models';
import { BulkImportRequest, BulkImportResult } from '@shared/import-export/import-export.models';
import { SaveEntityParams } from '@shared/models/entity.models';
@Injectable({
providedIn: 'root'
@ -69,8 +70,10 @@ export class AssetService {
return this.http.get<AssetInfo>(`/api/asset/info/${assetId}`, defaultHttpOptionsFromConfig(config));
}
public saveAsset(asset: Asset, config?: RequestConfig): Observable<Asset> {
return this.http.post<Asset>('/api/asset', asset, defaultHttpOptionsFromConfig(config));
public saveAsset(asset: Asset, config?: RequestConfig): Observable<Asset>;
public saveAsset(asset: Asset, saveParams: SaveEntityParams, config?: RequestConfig): Observable<Asset>;
public saveAsset(asset: Asset, saveParamsOrConfig?: SaveEntityParams | RequestConfig, config?: RequestConfig): Observable<Asset> {
return this.http.post<Asset>('/api/asset', asset, createDefaultHttpOptions(saveParamsOrConfig, config));
}
public deleteAsset(assetId: string, config?: RequestConfig) {

View File

@ -15,12 +15,13 @@
///
import { Injectable } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { createDefaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data';
import { Customer } from '@shared/models/customer.model';
import { SaveEntityParams } from '@shared/models/entity.models';
@Injectable({
providedIn: 'root'
@ -40,8 +41,10 @@ export class CustomerService {
return this.http.get<Customer>(`/api/customer/${customerId}`, defaultHttpOptionsFromConfig(config));
}
public saveCustomer(customer: Customer, config?: RequestConfig): Observable<Customer> {
return this.http.post<Customer>('/api/customer', customer, defaultHttpOptionsFromConfig(config));
public saveCustomer(customer: Customer, config?: RequestConfig): Observable<Customer>;
public saveCustomer(customer: Customer, saveParams: SaveEntityParams, config?: RequestConfig): Observable<Customer>;
public saveCustomer(customer: Customer, saveParamsOrConfig?: SaveEntityParams | RequestConfig, config?: RequestConfig): Observable<Customer> {
return this.http.post<Customer>('/api/customer', customer, createDefaultHttpOptions(saveParamsOrConfig, config));
}
public deleteCustomer(customerId: string, config?: RequestConfig) {

View File

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { createDefaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable, ReplaySubject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
@ -28,13 +28,15 @@ import {
DeviceInfo,
DeviceInfoQuery,
DeviceSearchQuery,
PublishTelemetryCommand
PublishTelemetryCommand,
SaveDeviceParams
} from '@shared/models/device.models';
import { EntitySubtype } from '@shared/models/entity-type.models';
import { AuthService } from '@core/auth/auth.service';
import { BulkImportRequest, BulkImportResult } from '@shared/import-export/import-export.models';
import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models';
import { ResourcesService } from '@core/services/resources.service';
import { SaveEntityParams } from '@shared/models/entity.models';
@Injectable({
providedIn: 'root'
@ -87,15 +89,19 @@ export class DeviceService {
return this.http.get<DeviceInfo>(`/api/device/info/${deviceId}`, defaultHttpOptionsFromConfig(config));
}
public saveDevice(device: Device, config?: RequestConfig): Observable<Device> {
return this.http.post<Device>('/api/device', device, defaultHttpOptionsFromConfig(config));
public saveDevice(device: Device, config?: RequestConfig): Observable<Device>;
public saveDevice(device: Device, saveParams?: SaveDeviceParams, config?: RequestConfig): Observable<Device>;
public saveDevice(device: Device, saveParamsOrConfig?: SaveDeviceParams | RequestConfig, config?: RequestConfig): Observable<Device> {
return this.http.post<Device>('/api/device', device, createDefaultHttpOptions(saveParamsOrConfig, config));
}
public saveDeviceWithCredentials(device: Device, credentials: DeviceCredentials, config?: RequestConfig): Observable<Device> {
public saveDeviceWithCredentials(device: Device, credentials: DeviceCredentials, config?: RequestConfig): Observable<Device>;
public saveDeviceWithCredentials(device: Device, credentials: DeviceCredentials, saveParams: SaveEntityParams, config?: RequestConfig): Observable<Device>;
public saveDeviceWithCredentials(device: Device, credentials: DeviceCredentials, saveParamsOrConfig?: SaveEntityParams | RequestConfig, config?: RequestConfig): Observable<Device> {
return this.http.post<Device>('/api/device-with-credentials', {
device,
credentials
}, defaultHttpOptionsFromConfig(config));
}, createDefaultHttpOptions(saveParamsOrConfig, config));
}
public deleteDevice(deviceId: string, config?: RequestConfig) {

View File

@ -15,13 +15,14 @@
///
import { Injectable } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { createDefaultHttpOptions, defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data';
import { EntitySubtype } from '@app/shared/models/entity-type.models';
import { EntityView, EntityViewInfo, EntityViewSearchQuery } from '@app/shared/models/entity-view.models';
import { SaveEntityParams } from '@shared/models/entity.models';
@Injectable({
providedIn: 'root'
@ -51,8 +52,10 @@ export class EntityViewService {
return this.http.get<EntityViewInfo>(`/api/entityView/info/${entityViewId}`, defaultHttpOptionsFromConfig(config));
}
public saveEntityView(entityView: EntityView, config?: RequestConfig): Observable<EntityView> {
return this.http.post<EntityView>('/api/entityView', entityView, defaultHttpOptionsFromConfig(config));
public saveEntityView(entityView: EntityView, config?: RequestConfig): Observable<EntityView>;
public saveEntityView(entityView: EntityView, saveParams: SaveEntityParams, config?: RequestConfig): Observable<EntityView>;
public saveEntityView(entityView: EntityView, saveParamsOrConfig?: SaveEntityParams | RequestConfig, config?: RequestConfig): Observable<EntityView> {
return this.http.post<EntityView>('/api/entityView', entityView, createDefaultHttpOptions(saveParamsOrConfig, config));
}
public deleteEntityView(entityViewId: string, config?: RequestConfig) {

View File

@ -18,32 +18,56 @@ import { InterceptorHttpParams } from '../interceptors/interceptor-http-params';
import { HttpHeaders } from '@angular/common/http';
import { InterceptorConfig } from '../interceptors/interceptor-config';
export type QueryParams = { [param:string]: any };
export interface RequestConfig {
ignoreLoading?: boolean;
ignoreErrors?: boolean;
resendRequest?: boolean;
queryParams?: QueryParams;
}
export function hasRequestConfig(config?: any): boolean {
if (!config) {
return false;
}
return config.hasOwnProperty('ignoreLoading') || config.hasOwnProperty('ignoreErrors') || config.hasOwnProperty('resendRequest') || config.hasOwnProperty('queryParams');
}
export function createDefaultHttpOptions(queryParamsOrConfig?: QueryParams | RequestConfig, config?: RequestConfig) {
if (hasRequestConfig(queryParamsOrConfig)) {
return defaultHttpOptionsFromConfig(queryParamsOrConfig as RequestConfig);
}
const queryParams = queryParamsOrConfig as QueryParams;
const finalConfig = {
...config,
...(queryParams && { queryParams }),
};
return defaultHttpOptionsFromConfig(finalConfig);
}
export function defaultHttpOptionsFromConfig(config?: RequestConfig) {
if (!config) {
config = {};
}
return defaultHttpOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest);
return defaultHttpOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest, config.queryParams);
}
export function defaultHttpOptions(ignoreLoading: boolean = false,
ignoreErrors: boolean = false,
resendRequest: boolean = false) {
resendRequest: boolean = false,
queryParams?: QueryParams) {
return {
headers: new HttpHeaders({'Content-Type': 'application/json'}),
params: new InterceptorHttpParams(new InterceptorConfig(ignoreLoading, ignoreErrors, resendRequest))
params: new InterceptorHttpParams(new InterceptorConfig(ignoreLoading, ignoreErrors, resendRequest), queryParams)
};
}
export function defaultHttpUploadOptions(ignoreLoading: boolean = false,
ignoreErrors: boolean = false,
resendRequest: boolean = false) {
resendRequest: boolean = false,
queryParams?: QueryParams) {
return {
params: new InterceptorHttpParams(new InterceptorConfig(ignoreLoading, ignoreErrors, resendRequest))
params: new InterceptorHttpParams(new InterceptorConfig(ignoreLoading, ignoreErrors, resendRequest), queryParams)
};
}

View File

@ -20,7 +20,7 @@ import { InterceptorConfig } from './interceptor-config';
export class InterceptorHttpParams extends HttpParams {
constructor(
public interceptorConfig: InterceptorConfig,
params?: { [param: string]: string | string[] }
params?: { [param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>; }
) {
super({ fromObject: params });
}

View File

@ -22,7 +22,7 @@ import { DeviceCredentialsId } from '@shared/models/id/device-credentials-id';
import { EntitySearchQuery } from '@shared/models/relation.models';
import { DeviceProfileId } from '@shared/models/id/device-profile-id';
import { RuleChainId } from '@shared/models/id/rule-chain-id';
import { EntityInfoData, HasTenantId, HasVersion } from '@shared/models/entity.models';
import { EntityInfoData, HasTenantId, HasVersion, SaveEntityParams } from '@shared/models/entity.models';
import { FilterPredicateValue, KeyFilter } from '@shared/models/query/query.models';
import { TimeUnit } from '@shared/models/time/time.models';
import _moment from 'moment';
@ -739,6 +739,10 @@ export interface DeviceInfoFilter {
active?: boolean;
}
export interface SaveDeviceParams extends SaveEntityParams {
accessToken?: string;
}
export class DeviceInfoQuery {
pageLink: PageLink;

View File

@ -209,3 +209,19 @@ export interface EntityTestScriptResult {
}
export type VersionedEntity = EntityInfoData & HasVersion | RuleChainMetaData;
export enum NameConflictPolicy {
FAIL = 'FAIL',
UNIQUIFY = 'UNIQUIFY',
}
export enum UniquifyStrategy {
RANDOM = 'RANDOM',
INCREMENTAL = 'INCREMENTAL'
}
export interface SaveEntityParams {
nameConflictPolicy?: NameConflictPolicy;
uniquifyStrategy?: UniquifyStrategy;
uniquifySeparator?: string;
}