Browse Source

feat(iot-hub): surface EntitiesLimitExceededException to caller

Re-throw EntitiesLimitExceededException from IoT Hub item install and
solution-template install paths instead of folding it into the generic
install error response, so the PE entity-limit error reaches the global
HTTP error handler.

In the device install wizard switch saveDevice/createDevice (and
overwrite) calls from ignoreErrors:true to false so the limit-exceeded
toast is shown when the backend rejects the create.
pull/15548/head
Igor Kulikov 5 months ago
parent
commit
8b016df3bf
  1. 4
      application/src/main/java/org/thingsboard/server/service/iot_hub/DefaultIotHubService.java
  2. 4
      application/src/main/java/org/thingsboard/server/service/solutions/DefaultSolutionService.java
  3. 8
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts

4
application/src/main/java/org/thingsboard/server/service/iot_hub/DefaultIotHubService.java

@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.iot_hub.IotHubInstalledItemDescriptor;
import org.thingsboard.server.common.data.iot_hub.RuleChainInstalledItemDescriptor;
import org.thingsboard.server.common.data.iot_hub.SolutionTemplateInstalledItemDescriptor;
import org.thingsboard.server.common.data.iot_hub.WidgetInstalledItemDescriptor;
import org.thingsboard.server.exception.EntitiesLimitExceededException;
import org.thingsboard.server.service.solutions.SolutionService;
import org.thingsboard.server.service.solutions.data.solution.SolutionInstallResponse;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -135,6 +136,9 @@ public class DefaultIotHubService implements IotHubService {
return InstallItemVersionResult.success(descriptor);
} catch (Exception e) {
log.error("[{}] Failed to install IoT Hub item version: {}", tenantId, versionId, e);
if (e instanceof EntitiesLimitExceededException el) {
throw el;
}
return InstallItemVersionResult.error(e.getMessage());
}
}

4
application/src/main/java/org/thingsboard/server/service/solutions/DefaultSolutionService.java

@ -93,6 +93,7 @@ import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.exception.EntitiesLimitExceededException;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
@ -409,6 +410,9 @@ public class DefaultSolutionService implements SolutionService {
} catch (Throwable e) {
log.error("[{}][{}] Failed to install solution template", tenantId, solutionId, e);
rollback(tenantId, solutionId, ctx, e);
if (e instanceof EntitiesLimitExceededException el) {
throw el;
}
return new SolutionInstallResponse(
new TenantSolutionTemplateInstructions(ctx.getSolutionInstructions()),
false,

8
ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts

@ -748,12 +748,12 @@ export class TbDeviceInstallDialogComponent extends DialogComponent<TbDeviceInst
return { id: result.id.id, name: result.name, url: `/profiles/deviceProfiles/${result.id.id}` };
}
case InstallStepType.DEVICE: {
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: true}));
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: false}));
const creds = await this.resolveCredentials(step, result.id.id);
return { id: result.id.id, name: result.name, url: `/entities/devices/${result.id.id}`, token: creds.credentialsId };
}
case InstallStepType.GATEWAY: {
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: true}));
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: false}));
const creds = await this.resolveCredentials(step, result.id.id);
const output = {
id: result.id.id,
@ -904,13 +904,13 @@ export class TbDeviceInstallDialogComponent extends DialogComponent<TbDeviceInst
}
case InstallStepType.DEVICE: {
template.id = { id: existing.id, entityType: 'DEVICE' };
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: true}));
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: false}));
const creds = await this.resolveCredentials(step, result.id.id);
return { id: result.id.id, name: result.name, url: `/entities/devices/${result.id.id}`, token: creds.credentialsId };
}
case InstallStepType.GATEWAY: {
template.id = { id: existing.id, entityType: 'DEVICE' };
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: true}));
const result = await firstValueFrom(this.deviceService.saveDevice(template, {ignoreErrors: false}));
const creds = await this.resolveCredentials(step, result.id.id);
const output: EntityStepOutput = {
id: result.id.id,

Loading…
Cancel
Save