Browse Source

Update paginator, update dialog, hero images, and footer

- Custom paginator: page number buttons (40px, rounded-4, primary active),
  centered pages, items-per-page outlined dropdown (77x40)
- Update dialog: extract to separate HTML/SCSS, match install dialog style
- Home component: add updateItem method and bind (updateClick) on cards
- Browse: reload installed items on 'updated' result from detail dialog
- Items page: add "Become a Creator" footer with divider, update paddings
- Export hero images: dashboards, solution templates (PNG), devices, widgets
- Update device library description from design
pull/15508/head
Igor Kulikov 6 months ago
parent
commit
126168a607
  1. 30
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.html
  2. 88
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.scss
  3. 35
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.ts
  4. 2
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.html
  5. 25
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.ts
  6. 10
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-items-page.component.html
  7. 30
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-items-page.component.scss
  8. 6
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-items-page.component.ts
  9. 64
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-update-dialog.component.html
  10. 57
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-update-dialog.component.scss
  11. 95
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-update-dialog.component.ts
  12. 102
      ui-ngx/src/assets/iot-hub/items-page-dashboards-hero.svg
  13. 258
      ui-ngx/src/assets/iot-hub/items-page-devices-hero.svg
  14. BIN
      ui-ngx/src/assets/iot-hub/items-page-solution-templates-hero.png
  15. 178
      ui-ngx/src/assets/iot-hub/items-page-widgets-hero.svg
  16. 8
      ui-ngx/src/assets/locale/locale.constant-en_US.json

30
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.html

@ -220,13 +220,29 @@
</div>
<!-- Pagination -->
<mat-paginator
[length]="totalElements"
[pageSize]="pageSize"
[pageIndex]="pageIndex"
[pageSizeOptions]="[12, 24, 48]"
(page)="onPageChange($event)">
</mat-paginator>
<div class="tb-iot-hub-pagination">
<div class="tb-iot-hub-pagination-pages">
<button mat-icon-button [disabled]="pageIndex === 0" (click)="goToPage(pageIndex - 1)">
<mat-icon>chevron_left</mat-icon>
</button>
@for (p of getPageNumbers(); track p) {
<button class="tb-iot-hub-page-btn" [class.active]="p === pageIndex" (click)="goToPage(p)">
{{ p + 1 }}
</button>
}
<button mat-icon-button [disabled]="pageIndex >= getTotalPages() - 1" (click)="goToPage(pageIndex + 1)">
<mat-icon>chevron_right</mat-icon>
</button>
</div>
<div class="tb-iot-hub-pagination-size">
<span>{{ 'iot-hub.items-per-page' | translate }}:</span>
<mat-select [value]="pageSize" (selectionChange)="onPageSizeChange($event.value)" class="tb-iot-hub-page-size-select">
@for (size of pageSizeOptions; track size) {
<mat-option [value]="size">{{ size }}</mat-option>
}
</mat-select>
</div>
</div>
}
</div>
</div>

88
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.scss

@ -54,7 +54,7 @@
// Left sidebar filters — Design: 280px wide, right border, own scroll
.tb-iot-hub-filters {
width: 280px;
width: 300px;
flex-shrink: 0;
border-right: 1px solid rgba(0, 0, 0, 0.12);
position: relative;
@ -88,7 +88,7 @@
background: transparent;
.mat-expansion-panel-header {
padding: 8px 16px 8px 40px;
padding: 8px 16px 8px 56px;
height: 40px;
min-height: 40px;
}
@ -105,7 +105,7 @@
mat-checkbox {
display: block;
padding: 0 0 0 28px;
padding: 0 0 0 44px;
&:hover {
background: rgba(0, 0, 0, 0.04);
@ -283,9 +283,85 @@
color: rgba(0, 0, 0, 0.2);
}
// Pagination
mat-paginator {
// Pagination — Design: centered page numbers, items per page on the right
.tb-iot-hub-pagination {
display: flex;
align-items: center;
padding: 24px 0 0;
flex-shrink: 0;
position: relative;
}
// Page buttons — Design: h-40, px-16 py-8, rounded-4, gap-1
.tb-iot-hub-pagination-pages {
display: flex;
align-items: center;
gap: 1px;
position: absolute;
left: 50%;
transform: translateX(-50%);
.mat-mdc-icon-button {
width: 40px;
height: 40px;
padding: 8px;
--mdc-icon-button-state-layer-size: 40px;
}
}
.tb-iot-hub-page-btn {
height: 40px;
min-width: 40px;
padding: 8px 16px;
border-radius: 4px;
border: none;
background: transparent;
color: rgba(0, 0, 0, 0.76);
font-size: 14px;
font-weight: 500;
line-height: 20px;
letter-spacing: 0.25px;
font-family: inherit;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s;
&:hover:not(.active) {
background: rgba(0, 0, 0, 0.04);
}
&.active {
background: $tb-primary-color;
color: white;
}
}
// Items per page — Design: gap-8, 14px Regular, right-aligned
.tb-iot-hub-pagination-size {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
margin-left: auto;
}
// Page size dropdown — Design: 77×40, border rgba(0,0,0,0.12), rounded-4, px-12 py-6
.tb-iot-hub-page-size-select {
width: 77px;
height: 40px;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 4px;
padding: 6px 12px;
::ng-deep .mat-mdc-select-trigger {
font-size: 14px;
}
}
// Responsive
@ -297,7 +373,7 @@ mat-paginator {
@media (max-width: 900px) {
.tb-iot-hub-filters {
width: 220px;
width: 240px;
}
.tb-iot-hub-card-grid {

35
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.ts

@ -82,6 +82,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy {
hasError = false;
textSearch = '';
pageSizeOptions = [12, 24, 48];
_activeType: ItemType = ItemType.WIDGET;
activeCategories = new Set<string>();
activeUseCases = new Set<string>();
@ -206,6 +207,38 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy {
this.loadItems();
}
getTotalPages(): number {
return Math.ceil(this.totalElements / this.pageSize);
}
getPageNumbers(): number[] {
const total = this.getTotalPages();
const pages: number[] = [];
const maxVisible = 5;
let start = Math.max(0, this.pageIndex - Math.floor(maxVisible / 2));
let end = Math.min(total, start + maxVisible);
if (end - start < maxVisible) {
start = Math.max(0, end - maxVisible);
}
for (let i = start; i < end; i++) {
pages.push(i);
}
return pages;
}
goToPage(page: number): void {
if (page >= 0 && page < this.getTotalPages()) {
this.pageIndex = page;
this.loadItems();
}
}
onPageSizeChange(size: number): void {
this.pageSize = size;
this.pageIndex = 0;
this.loadItems();
}
clearCategories(): void {
this.activeCategories.clear();
this.pageIndex = 0;
@ -389,7 +422,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy {
} as IotHubItemDetailDialogData
});
dialogRef.afterClosed().subscribe(result => {
if (result === 'installed' || result === 'deleted') {
if (result === 'installed' || result === 'updated' || result === 'deleted') {
this.reloadInstalledItems();
}
});

2
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.html

@ -97,6 +97,7 @@
(cardClick)="openItemDetail($event)"
(creatorClick)="navigateToCreator($event)"
(installClick)="installItem($event)"
(updateClick)="updateItem($event)"
(deleteClick)="deleteInstalledItem($event)">
</tb-iot-hub-item-card>
}
@ -143,6 +144,7 @@
(cardClick)="openItemDetail($event)"
(creatorClick)="navigateToCreator($event)"
(installClick)="installItem($event)"
(updateClick)="updateItem($event)"
(deleteClick)="deleteInstalledItem($event)">
</tb-iot-hub-item-card>
}

25
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.ts

@ -26,6 +26,7 @@ import { IotHubInstalledItem } from '@shared/models/iot-hub/iot-hub-installed-it
import { IotHubApiService } from '@core/http/iot-hub-api.service';
import { TbIotHubItemDetailDialogComponent, IotHubItemDetailDialogData } from './iot-hub-item-detail-dialog.component';
import { TbIotHubInstallDialogComponent, IotHubInstallDialogData } from './iot-hub-install-dialog.component';
import { TbIotHubUpdateDialogComponent, IotHubUpdateDialogData } from './iot-hub-update-dialog.component';
import { TbIotHubDeleteDialogComponent, IotHubDeleteDialogData } from './iot-hub-delete-dialog.component';
interface CategoryCard {
@ -246,6 +247,30 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
});
}
updateItem(item: MpItemVersionView): void {
const installedItem = this.findInstalledItem(item);
if (!installedItem) {
return;
}
const dialogRef = this.dialog.open(TbIotHubUpdateDialogComponent, {
panelClass: ['tb-dialog'],
autoFocus: false,
data: {
installedItemId: installedItem.id.id,
itemName: item.name,
itemType: item.type,
version: item.version,
versionId: item.id,
iotHubApiService: this.iotHubApiService
} as IotHubUpdateDialogData
});
dialogRef.afterClosed().subscribe(result => {
if (result === 'updated') {
this.reloadInstalledItems(item.type);
}
});
}
navigateToCreator(creatorId: string): void {
this.router.navigate(['/iot-hub/creator', creatorId]);
}

10
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-items-page.component.html

@ -48,4 +48,14 @@
[activeType]="config.type"
[hideTabs]="true">
</tb-iot-hub-browse>
<!-- Become a Creator footer -->
<div class="tb-iot-hub-items-divider"></div>
<div class="tb-iot-hub-items-footer">
<h2>{{ 'iot-hub.become-a-creator' | translate }}</h2>
<p>{{ 'iot-hub.become-creator-text' | translate }}</p>
<button mat-stroked-button color="primary" (click)="openSignup()">
{{ 'iot-hub.contribute' | translate }}
</button>
</div>
</div>

30
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-items-page.component.scss

@ -91,3 +91,33 @@ tb-iot-hub-browse {
margin-left: -40px;
margin-right: -40px;
}
// Footer divider
.tb-iot-hub-items-divider {
height: 1px;
background: rgba(0, 0, 0, 0.12);
margin-top: 48px;
margin-left: -40px;
margin-right: -40px;
}
// Become a Creator footer
.tb-iot-hub-items-footer {
text-align: center;
padding: 40px 0 0;
h2 {
font-size: 24px;
font-weight: 500;
line-height: 32px;
color: rgba(0, 0, 0, 0.87);
margin: 0 0 8px;
}
p {
font-size: 14px;
line-height: 20px;
color: rgba(0, 0, 0, 0.54);
margin: 0 0 32px;
}
}

6
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-items-page.component.ts

@ -39,14 +39,14 @@ const PAGE_CONFIGS: Record<string, ItemTypePageConfig> = {
type: ItemType.DASHBOARD,
titleKey: 'item.type-dashboard-plural',
descriptionKey: 'iot-hub.items-page-desc-dashboards',
image: 'assets/iot-hub/category-dashboards-img.svg',
image: 'assets/iot-hub/items-page-dashboards-hero.svg',
routeSegment: 'dashboards'
},
SOLUTION_TEMPLATE: {
type: ItemType.SOLUTION_TEMPLATE,
titleKey: 'item.type-solution-template-plural',
descriptionKey: 'iot-hub.items-page-desc-solution-templates',
image: 'assets/iot-hub/category-solution-templates-img.png',
image: 'assets/iot-hub/items-page-solution-templates-hero.png',
routeSegment: 'solution-templates'
},
CALCULATED_FIELD: {
@ -67,7 +67,7 @@ const PAGE_CONFIGS: Record<string, ItemTypePageConfig> = {
type: ItemType.DEVICE,
titleKey: 'iot-hub.device-library',
descriptionKey: 'iot-hub.items-page-desc-devices',
image: 'assets/iot-hub/category-device-library-img.svg',
image: 'assets/iot-hub/items-page-devices-hero.svg',
routeSegment: 'devices'
}
};

64
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-update-dialog.component.html

@ -0,0 +1,64 @@
<!--
Copyright © 2016-2026 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div class="tb-iot-hub-install-content">
@switch (state) {
@case ('confirm') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.update-confirm-title' | translate:{ name: data.itemName } }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.update-desc' | translate }}</p>
}
@case ('updating') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.update-confirm-title' | translate:{ name: data.itemName } }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.update-desc' | translate }}</p>
}
@case ('success') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.update-success-title' | translate }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.update-success-desc' | translate:{ name: data.itemName } }}</p>
}
@case ('error') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.update-error-title' | translate }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.update-error-message' | translate:{ name: data.itemName } }}</p>
<div class="tb-iot-hub-error-details">{{ errorMessage }}</div>
}
}
</div>
<mat-dialog-actions align="end">
@switch (state) {
@case ('confirm') {
<button mat-button (click)="cancel()">{{ 'action.cancel' | translate }}</button>
<button mat-flat-button color="primary" (click)="update()">{{ 'iot-hub.update' | translate }}</button>
}
@case ('updating') {
<button mat-button disabled>{{ 'action.cancel' | translate }}</button>
<button mat-flat-button color="primary" disabled>
<mat-spinner diameter="18" class="tb-iot-hub-inline-spinner"></mat-spinner>
{{ 'iot-hub.updating' | translate }}
</button>
}
@case ('success') {
<button mat-button (click)="close()">{{ (entityDetailsUrl ? 'action.cancel' : 'action.close') | translate }}</button>
@if (entityDetailsUrl) {
<button mat-flat-button color="primary" (click)="openEntityDetails()">
{{ 'iot-hub.open-details' | translate }}
</button>
}
}
@case ('error') {
<button mat-button (click)="close()">{{ 'action.close' | translate }}</button>
}
}
</mat-dialog-actions>

57
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-update-dialog.component.scss

@ -0,0 +1,57 @@
/**
* Copyright © 2016-2026 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.tb-iot-hub-install-content {
display: flex;
flex-direction: column;
gap: 20px;
padding: 24px;
}
.tb-iot-hub-install-title {
font-size: 20px;
font-weight: 600;
line-height: 24px;
letter-spacing: 0.1px;
color: rgba(0, 0, 0, 0.87);
margin: 0;
}
.tb-iot-hub-install-desc {
color: rgba(0, 0, 0, 0.54);
font-size: 14px;
line-height: 20px;
letter-spacing: 0.2px;
margin: 0;
}
.tb-iot-hub-inline-spinner {
display: inline-block;
margin-right: 8px;
}
.tb-iot-hub-error-details {
max-height: 200px;
overflow-y: auto;
padding: 12px;
background: #f5f5f5;
border-radius: 4px;
font-family: monospace;
font-size: 12px;
color: rgba(0, 0, 0, 0.7);
white-space: pre-wrap;
word-break: break-word;
}

95
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-update-dialog.component.ts

@ -43,99 +43,8 @@ export type UpdateState = 'confirm' | 'updating' | 'success' | 'error';
@Component({
selector: 'tb-iot-hub-update-dialog',
standalone: false,
template: `
@switch (state) {
@case ('confirm') {
<h2 mat-dialog-title>{{ 'iot-hub.update-item-title' | translate }}</h2>
<mat-dialog-content>
<p>{{ 'iot-hub.update-confirm' | translate:{ name: data.itemName, version: data.version } }}</p>
<p class="tb-iot-hub-install-meta">{{ 'iot-hub.install-type' | translate:{ type: getTypeLabel() } }}</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="cancel()">{{ 'action.cancel' | translate }}</button>
<button mat-raised-button color="primary" (click)="update()">{{ 'iot-hub.update' | translate }}</button>
</mat-dialog-actions>
}
@case ('updating') {
<h2 mat-dialog-title>{{ 'iot-hub.update-item-title' | translate }}</h2>
<mat-dialog-content>
<p>{{ 'iot-hub.update-confirm' | translate:{ name: data.itemName, version: data.version } }}</p>
<p class="tb-iot-hub-install-meta">{{ 'iot-hub.install-type' | translate:{ type: getTypeLabel() } }}</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button disabled>{{ 'action.cancel' | translate }}</button>
<button mat-raised-button color="primary" disabled>
<mat-spinner diameter="18" class="tb-iot-hub-inline-spinner"></mat-spinner>
{{ 'iot-hub.updating' | translate }}
</button>
</mat-dialog-actions>
}
@case ('success') {
<h2 mat-dialog-title>
<mat-icon class="tb-iot-hub-result-icon tb-iot-hub-success-icon">check_circle</mat-icon>
{{ 'iot-hub.update-success-title' | translate }}
</h2>
<mat-dialog-content>
<p>{{ 'iot-hub.update-success-message' | translate:{ name: data.itemName, version: data.version } }}</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="close()">{{ 'action.close' | translate }}</button>
@if (entityDetailsUrl) {
<button mat-raised-button color="primary" (click)="openEntityDetails()">
{{ 'iot-hub.open-item-type-details' | translate:{ type: getTypeLabel() } }}
</button>
}
</mat-dialog-actions>
}
@case ('error') {
<h2 mat-dialog-title>
<mat-icon class="tb-iot-hub-result-icon tb-iot-hub-error-icon">error</mat-icon>
{{ 'iot-hub.update-error-title' | translate }}
</h2>
<mat-dialog-content>
<p>{{ 'iot-hub.update-error-message' | translate:{ name: data.itemName } }}</p>
<div class="tb-iot-hub-error-details">{{ errorMessage }}</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="close()">{{ 'action.close' | translate }}</button>
</mat-dialog-actions>
}
}
`,
styles: [`
.tb-iot-hub-install-meta {
margin: 4px 0;
color: rgba(0, 0, 0, 0.54);
font-size: 14px;
}
.tb-iot-hub-inline-spinner {
display: inline-block;
margin-right: 8px;
}
.tb-iot-hub-result-icon {
vertical-align: middle;
margin-right: 8px;
}
.tb-iot-hub-success-icon {
color: #2e7d32;
}
.tb-iot-hub-error-icon {
color: #c62828;
}
.tb-iot-hub-error-details {
max-height: 200px;
overflow-y: auto;
padding: 12px;
background: #f5f5f5;
border-radius: 4px;
font-family: monospace;
font-size: 12px;
color: rgba(0, 0, 0, 0.7);
white-space: pre-wrap;
word-break: break-word;
margin-top: 8px;
}
`]
templateUrl: './iot-hub-update-dialog.component.html',
styleUrls: ['./iot-hub-update-dialog.component.scss']
})
export class TbIotHubUpdateDialogComponent {

102
ui-ngx/src/assets/iot-hub/items-page-dashboards-hero.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 95 KiB

258
ui-ngx/src/assets/iot-hub/items-page-devices-hero.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 178 KiB

BIN
ui-ngx/src/assets/iot-hub/items-page-solution-templates-hero.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

178
ui-ngx/src/assets/iot-hub/items-page-widgets-hero.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 74 KiB

8
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3703,12 +3703,13 @@
"and-devices": "& Devices",
"search-placeholder": "Search in IoT Hub...",
"search": "Search...",
"items-per-page": "Items per page",
"items-page-desc-widgets": "Jumpstart your IoT journey with pre-configured widgets designed for your industry. Deploy proven architectures instantly and focus your energy on what matters: your unique business logic.",
"items-page-desc-dashboards": "Browse ready-to-use dashboards for monitoring, analytics, and device management. Deploy complete dashboard layouts instantly.",
"items-page-desc-dashboards": "Explore dashboards to find pre-built visualization templates and interactive UI layouts you can deploy in minutes to bring your IoT data to life.",
"items-page-desc-solution-templates": "Complete IoT solution packages with dashboards, rule chains, and device configurations. Get started with proven architectures.",
"items-page-desc-calculated-fields": "Use pre-configured Calculated Fields to automate complex metrics like fuel efficiency or power factor. Skip the manual logic and keep your dashboards clean and actionable.",
"items-page-desc-rule-chains": "From sophisticated data processing to seamless API integrations, Rule Chain templates provide the architectural foundation you need to scale without building from scratch.",
"items-page-desc-devices": "Browse device configurations, profiles, and connectivity templates for sensors, gateways, and controllers.",
"items-page-desc-devices": "Explore the device library to find pre-configured connectivity templates you can deploy in minutes to connect your hardware instantly.",
"device-library": "Device Library",
"popular-widgets": "Popular Widgets",
"popular-dashboards": "Popular Dashboards",
@ -3792,6 +3793,9 @@
"update": "Update",
"update-item-title": "Update Item",
"update-confirm": "Update '{{name}}' to version {{version}}?",
"update-confirm-title": "Update '{{name}}'?",
"update-desc": "Updating this will replace the current version with the latest and reconfigure the associated resources within your tenant",
"update-success-desc": "'{{name}}' has been updated successfully",
"updating": "Updating...",
"update-success-title": "Update Successful",
"update-success-message": "'{{name}}' has been updated to version {{version}}.",

Loading…
Cancel
Save