feat(ui): kube app list ui styling EE-3464 (#7247)

* feat(ui): apply app datatable changes EE-3464
pull/7266/head
Ali 2022-07-13 21:21:26 +12:00 committed by GitHub
parent ad7055ee01
commit 0da4e3ae63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 784 additions and 652 deletions

View File

@ -1,4 +1,4 @@
<div class="col-xs-12 form-section-title"> Secrets </div> <div class="col-xs-12 text-[13px] !px-0 !py-1"> Secrets </div>
<table style="width: 50%"> <table style="width: 50%">
<tbody> <tbody>
<tr> <tr>

View File

@ -1,289 +1,330 @@
<div class="datatable"> <div class="datatable">
<rd-widget> <!-- toolbar header actions and settings -->
<rd-widget-body classes="no-padding"> <div ng-if="$ctrl.isPrimary" class="toolBar !flex-col gap-1">
<div ng-if="$ctrl.isPrimary" class="toolBar"> <div class="toolBar vertical-center !gap-x-5 !gap-y-1 flex-wrap !p-0 w-full">
<div class="toolBarTitle"> <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px"></i> {{ $ctrl.titleText }} </div> <div class="toolBarTitle vertical-center">
<span class="small text-muted" style="float: left; margin-top: 5px" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem"> <pr-icon icon="'box'" feather="true" class-name="'icon-nested-blue'" mode="'primary'"></pr-icon>
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px"></i> Applications
System resources are hidden, this can be changed in the table settings.
</span>
<div class="settings" data-cy="k8sApp-tableSettings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Table settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader"> Table settings </div>
<div class="menuContent">
<div>
<div class="md-checkbox" ng-if="$ctrl.isAdmin">
<input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
<label for="applications_setting_show_system">Show system resources</label>
</div>
<div class="md-checkbox">
<input
id="setting_auto_refresh"
type="checkbox"
ng-model="$ctrl.settings.repeater.autoRefresh"
ng-change="$ctrl.onSettingsRepeaterChange()"
data-cy="k8sApp-autoRefreshCheckbox"
/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate"> Refresh rate </label>
<select
id="settings_refresh_rate"
ng-model="$ctrl.settings.repeater.refreshRate"
ng-change="$ctrl.onSettingsRepeaterChange()"
class="small-select"
data-cy="k8sApp-refreshRateDropdown"
>
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div ng-if="$ctrl.isPrimary" class="actionBar"> <div class="searchBar vertical-center">
<button <pr-icon icon="'search'" feather="true"></pr-icon>
type="button"
class="btn btn-sm btn-danger"
ng-disabled="$ctrl.state.selectedItemCount === 0"
ng-click="$ctrl.removeAction($ctrl.state.selectedItems)"
data-cy="k8sApp-removeAppButton"
>
<i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove
</button>
<button type="button" class="btn btn-sm btn-primary" ui-sref="kubernetes.applications.new" data-cy="k8sApp-addApplicationButton">
<i class="fa fa-plus space-right" aria-hidden="true"></i>Add application with form
</button>
<button type="button" class="btn btn-sm btn-primary" ui-sref="kubernetes.deploy" data-cy="k8sApp-deployFromManifestButton">
<i class="fa fa-plus space-right" aria-hidden="true"></i>Create from manifest
</button>
</div>
<div ng-if="$ctrl.isPrimary" class="searchBar">
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
<input <input
type="text" type="text"
class="searchInput" class="searchInput"
ng-model="$ctrl.state.textFilter" ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()" ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..." placeholder="Search for an application..."
auto-focus auto-focus
ng-model-options="{ debounce: 300 }" ng-model-options="{ debounce: 300 }"
data-cy="k8sApp-searchApplicationsInput" data-cy="k8sApp-searchApplicationsInput"
/> />
</div> </div>
<div class="table-responsive"> <div class="actionBar !gap-3 !mr-0" ng-if="!$ctrl.offlineMode">
<table class="table table-hover nowrap-cells" data-cy="k8sApp-appTable"> <button
<thead ng-class="{ 'secondary-heading': !$ctrl.isPrimary }"> ng-if="$ctrl.isPrimary"
<tr> type="button"
<th class="datatable-wide"> class="btn btn-sm btn-dangerlight h-fit vertical-center !ml-0"
<span ng-if="$ctrl.isPrimary"> ng-disabled="$ctrl.state.selectedItemCount === 0"
<span class="md-checkbox"> ng-click="$ctrl.removeAction($ctrl.state.selectedItems)"
<input id="select_all" type="checkbox" ng-model="$ctrl.state.selectAll" ng-change="$ctrl.selectAll()" data-cy="k8sApp-selectAllCheckbox" /> data-cy="k8sApp-removeAppButton"
<label for="select_all"></label> >
</span> <pr-icon icon="'trash-2'" feather="true"></pr-icon>
<a ng-click="$ctrl.expandAll()"> Remove
<i ng-class="{ 'fas fa-angle-down': $ctrl.state.expandAll, 'fas fa-angle-right': !$ctrl.state.expandAll }" aria-hidden="true"></i> </button>
</a> <button
</span> ng-if="$ctrl.isPrimary"
</th> type="button"
<th> class="btn btn-sm btn-secondary h-fit vertical-center !ml-0"
<a ng-click="$ctrl.changeOrderBy('Name')"> ui-sref="kubernetes.applications.new"
Name data-cy="k8sApp-addApplicationButton"
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && !$ctrl.state.reverseOrder"></i> >
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"></i> <pr-icon icon="'plus'" feather="true" class-name="'!h-3'"></pr-icon>Add with form
</a> </button>
</th> <button
<th> ng-if="$ctrl.isPrimary"
<a ng-click="$ctrl.changeOrderBy('StackName')"> type="button"
Stack class="btn btn-sm btn-primary h-fit vertical-center !ml-0"
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'StackName' && !$ctrl.state.reverseOrder"></i> ui-sref="kubernetes.deploy"
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'StackName' && $ctrl.state.reverseOrder"></i> data-cy="k8sApp-deployFromManifestButton"
</a> >
</th> <pr-icon icon="'plus'" feather="true" class-name="'!h-3'"></pr-icon>Create from manifest
<th> </button>
<a ng-click="$ctrl.changeOrderBy('ResourcePool')"> </div>
Namespace <div class="settings" data-cy="k8sApp-tableSettings">
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'ResourcePool' && !$ctrl.state.reverseOrder"></i> <span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'ResourcePool' && $ctrl.state.reverseOrder"></i> <span uib-dropdown-toggle aria-label="Settings">
</a> <pr-icon icon="'more-vertical'" feather="true" class-name="'!mr-0 !h-4'"></pr-icon>
</th> </span>
<th> <div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<a ng-click="$ctrl.changeOrderBy('Image')"> <div class="tableMenu">
Image <div class="menuHeader"> Table settings </div>
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Image' && !$ctrl.state.reverseOrder"></i> <div class="menuContent">
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Image' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.filters.state.open">
<a ng-click="$ctrl.changeOrderBy('ApplicationType')">
Application Type
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'ApplicationType' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'ApplicationType' && $ctrl.state.reverseOrder"></i>
</a>
<div> <div>
<span uib-dropdown-toggle class="table-filter" ng-if="!$ctrl.filters.state.enabled">Filter <i class="fa fa-filter" aria-hidden="true"></i></span> <div class="md-checkbox" ng-if="$ctrl.isAdmin">
<span uib-dropdown-toggle class="table-filter filter-active" ng-if="$ctrl.filters.state.enabled">Filter <i class="fa fa-check" aria-hidden="true"></i></span> <input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
</div> <label for="applications_setting_show_system">Show system resources</label>
<div class="dropdown-menu" uib-dropdown-menu> </div>
<div class="tableMenu"> <div class="md-checkbox">
<div class="menuHeader"> Filter by application type </div> <input
<div class="menuContent"> id="setting_auto_refresh"
<div class="md-checkbox" ng-repeat="filter in $ctrl.filters.state.values track by $index"> type="checkbox"
<input id="filter_state_{{ $index }}" type="checkbox" ng-model="filter.display" ng-change="$ctrl.onStateFilterChange()" /> ng-model="$ctrl.settings.repeater.autoRefresh"
<label for="filter_state_{{ $index }}">{{ filter.type | kubernetesApplicationTypeText }}</label> ng-change="$ctrl.onSettingsRepeaterChange()"
</div> data-cy="k8sApp-autoRefreshCheckbox"
</div> />
<div> <label for="setting_auto_refresh">Auto refresh</label>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.filters.state.open = false;">Close</a> </div>
</div> <div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate"> Refresh rate </label>
<select
id="settings_refresh_rate"
ng-model="$ctrl.settings.repeater.refreshRate"
ng-change="$ctrl.onSettingsRepeaterChange()"
class="small-select"
data-cy="k8sApp-refreshRateDropdown"
>
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
</span>
</div> </div>
</div> </div>
</th> </div>
<th> Status </th> <div>
<th> Published </th> <a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton">Close</a>
<th> </div>
<a ng-click="$ctrl.changeOrderBy('CreationDate')"> </div>
Created </div>
<i class="fa fa-sort-numeric-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'CreationDate' && !$ctrl.state.reverseOrder"></i> </span>
<i class="fa fa-sort-numeric-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'CreationDate' && $ctrl.state.reverseOrder"></i>
</a>
</th>
</tr>
</thead>
<tbody>
<tr
ng-click="$ctrl.expandItem(item, !$ctrl.isItemExpanded(item))"
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.applyFilters | filter:$ctrl.state.textFilter | filter:$ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
ng-class="{ active: item.Checked, interactive: $ctrl.isExpandable(item), 'secondary-body': !$ctrl.isPrimary }"
pagination-id="$ctrl.tableKey"
>
<td>
<span ng-if="$ctrl.isPrimary" class="md-checkbox">
<input
id="select_{{ $index }}"
type="checkbox"
ng-model="item.Checked"
ng-click="$ctrl.selectItem(item, $event); $event.stopPropagation()"
ng-disabled="$ctrl.isSystemNamespace(item)"
/>
<label for="select_{{ $index }}"></label>
</span>
<a ng-if="$ctrl.isExpandable(item)">
<i ng-class="{ 'fas fa-angle-down': $ctrl.isItemExpanded(item), 'fas fa-angle-right': !$ctrl.isItemExpanded(item) }" class="space-right" aria-hidden="true"></i>
</a>
</td>
<td>
<a ng-if="item.KubernetesApplications" ui-sref="kubernetes.helm({ name: item.Name, namespace: item.ResourcePool })" ng-click="$event.stopPropagation()"
>{{ item.Name }}
</a>
<a
ng-if="!item.KubernetesApplications"
ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool })"
ng-click="$event.stopPropagation()"
>{{ item.Name }}
</a>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item)">system</span>
<span class="label label-primary image-tag label-margins" ng-if="!$ctrl.isSystemNamespace(item) && $ctrl.isExternalApplication(item)">external</span>
</td>
<td>{{ item.StackName || '-' }}</td>
<td>
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: item.ResourcePool })" ng-click="$event.stopPropagation()">{{ item.ResourcePool }}</a>
</td>
<td title="{{ item.Image }}"
>{{ item.Image | truncate: 64 }} <span ng-if="item.Containers.length > 1">+ {{ item.Containers.length - 1 }}</span></td
>
<td>{{ item.ApplicationType | kubernetesApplicationTypeText }}</td>
<td ng-if="item.ApplicationType !== $ctrl.KubernetesApplicationTypes.POD">
<status-indicator ok="(item.TotalPodsCount > 0 && item.TotalPodsCount === item.RunningPodsCount) || item.Status === 'Ready'"></status-indicator>
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.REPLICATED">Replicated</span>
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.GLOBAL">Global</span>
<span ng-if="item.RunningPodsCount >= 0 && item.TotalPodsCount >= 0">
<code>{{ item.RunningPodsCount }}</code> / <code>{{ item.TotalPodsCount }}</code>
</span>
<span ng-if="item.KubernetesApplications">{{ item.Status }}</span>
</td>
<td ng-if="item.ApplicationType === $ctrl.KubernetesApplicationTypes.POD">
{{ item.Pods[0].Status }}
</td>
<td>
<span>
{{ item.Services.length === 0 ? 'No' : 'Yes' }}
</span>
</td>
<td>{{ item.CreationDate | getisodate }} {{ item.ApplicationOwner ? 'by ' + item.ApplicationOwner : '' }}</td>
</tr>
<tr dir-paginate-end ng-show="$ctrl.isExpandable(item) && $ctrl.isItemExpanded(item)" ng-class="{ 'secondary-body': $ctrl.isPrimary && !item.KubernetesApplications }">
<td></td>
<td colspan="8" class="datatable-padding-vertical">
<span ng-if="item.KubernetesApplications">
<kubernetes-applications-datatable
dataset="item.KubernetesApplications"
table-key="{{ item.Id }}_table"
settings-key="{{ $ctrl.tableKey }}"
order-by="Name"
remove-action="$ctrl.removeAction"
refresh-callback="$ctrl.refreshCallback"
on-publishing-mode-click="($ctrl.onPublishingModeClick)"
is-primary="false"
>
</kubernetes-applications-datatable>
</span>
<span ng-if="!item.KubernetesApplications">
<kubernetes-applications-datatable-url
ng-if="$ctrl.getPublishedUrl(item)"
published-url="{{ $ctrl.getPublishedUrl(item) }}"
></kubernetes-applications-datatable-url>
<kubernetes-applications-datatable-details
ng-if="$ctrl.hasConfigurationSecrets(item)"
configurations="item.Configurations"
></kubernetes-applications-datatable-details>
</span>
</td>
</tr>
<tr ng-if="!$ctrl.dataset">
<td colspan="8" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="8" class="text-center text-muted">No application available.</td>
</tr>
</tbody>
</table>
</div> </div>
<div ng-if="$ctrl.isPrimary" class="footer" ng-if="$ctrl.dataset"> </div>
<div class="infoBar" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div> <div class="flex flex-row w-full">
<div class="paginationControls"> <span class="small text-muted mt-1" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<form class="form-inline"> <pr-icon icon="'info'" feather="true" class-name="'icon'"></pr-icon>
<span class="limitSelector"> System resources are hidden, this can be changed in the table settings.
<span style="margin-right: 5px"> Items per page </span> </span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()" data-cy="component-paginationSelect"> </div>
<option value="0">All</option> </div>
<option value="10">10</option> <!-- data table content -->
<option value="25">25</option> <div class="table-responsive">
<option value="50">50</option> <table class="table table-hover table-filters nowrap-cells" data-cy="k8sApp-appTable">
<option value="100">100</option> <thead ng-class="{ 'secondary-heading': !$ctrl.isPrimary }">
</select> <tr role="row">
<th role="columnheader" class="datatable-wide dropdown">
<div ng-if="$ctrl.isPrimary" class="flex no-wrap min-w-max">
<span class="md-checkbox vertical-center">
<input id="select_all" type="checkbox" ng-model="$ctrl.state.selectAll" ng-change="$ctrl.selectAll()" data-cy="k8sApp-selectAllCheckbox" />
<label for="select_all"></label>
</span>
<div class="cursor-pointer vertical-center" ng-click="$ctrl.expandAll()">
<pr-icon ng-if="$ctrl.state.expandAll" icon="'chevron-down'" feather="true" class-name="'icon'"></pr-icon>
<pr-icon ng-if="!$ctrl.state.expandAll" icon="'chevron-right'" feather="true" class-name="'icon'"></pr-icon>
</div>
</div>
</th>
<th>
<table-column-header
col-title="'Name'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'Name'"
is-sorted-desc="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('Name')"
></table-column-header>
</th>
<th>
<table-column-header
col-title="'Stack'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'StackName'"
is-sorted-desc="$ctrl.state.orderBy === 'StackName' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('StackName')"
></table-column-header>
</th>
<th>
<table-column-header
col-title="'Namespace'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'ResourcePool'"
is-sorted-desc="$ctrl.state.orderBy === 'ResourcePool' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('ResourcePool')"
></table-column-header>
</th>
<th>
<table-column-header
col-title="'Image'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'Image'"
is-sorted-desc="$ctrl.state.orderBy === 'Image' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('Image')"
></table-column-header>
</th>
<th uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.filters.state.open">
<div class="flex flex-row no-wrap gap-2">
<table-column-header
col-title="'Application Type'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'ApplicationType'"
is-sorted-desc="$ctrl.state.orderBy === 'ApplicationType' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('ApplicationType')"
></table-column-header>
<div class="flex flex-row no-wrap gap-1 items-center" uib-dropdown-toggle>
<span class="table-filter">Filters</span>
<pr-icon ng-if="!$ctrl.filters.state.enabled" icon="'filter'" class-name="'icon'" feather="true"></pr-icon>
<pr-icon ng-if="$ctrl.filters.state.enabled" icon="'check'" class-name="'icon'" feather="true"></pr-icon>
</div>
<div class="dropdown-menu" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader"> Filter by application type </div>
<div class="menuContent">
<div class="md-checkbox" ng-repeat="filter in $ctrl.filters.state.values track by $index">
<input id="filter_state_{{ $index }}" type="checkbox" ng-model="filter.display" ng-change="$ctrl.onStateFilterChange()" />
<label for="filter_state_{{ $index }}">{{ filter.type | kubernetesApplicationTypeText }}</label>
</div>
</div>
<div>
<a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.filters.state.open = false;">Close</a>
</div>
</div>
</div>
</div>
</th>
<th>
<table-column-header col-title="'Status'" can-sort="false"></table-column-header>
<!-- Status -->
</th>
<th>
<table-column-header col-title="'Published'" can-sort="false"></table-column-header>
<!-- Published -->
</th>
<th>
<table-column-header
col-title="'Created'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'CreationDate'"
is-sorted-desc="$ctrl.state.orderBy === 'CreationDate' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('CreationDate')"
></table-column-header>
</th>
</tr>
</thead>
<tbody>
<tr
ng-click="$ctrl.expandItem(item, !$ctrl.isItemExpanded(item))"
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.applyFilters | filter:$ctrl.state.textFilter | filter:$ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
ng-class="{ active: item.Checked, interactive: $ctrl.isExpandable(item), 'secondary-body': !$ctrl.isPrimary }"
pagination-id="$ctrl.tableKey"
>
<td class="h-[50px]">
<span ng-if="$ctrl.isPrimary" class="md-checkbox vertical-center">
<input
id="select_{{ $index }}"
type="checkbox"
ng-model="item.Checked"
ng-click="$ctrl.selectItem(item, $event); $event.stopPropagation()"
ng-disabled="$ctrl.isSystemNamespace(item)"
/>
<label for="select_{{ $index }}"></label>
</span> </span>
<dir-pagination-controls max-size="5" pagination-id="$ctrl.tableKey"></dir-pagination-controls> <div ng-if="$ctrl.isExpandable(item)" class="vertical-center">
</form> <pr-icon ng-if="$ctrl.isItemExpanded(item)" icon="'chevron-down'" feather="true" class-name="'icon'"></pr-icon>
</div> <pr-icon ng-if="!$ctrl.isItemExpanded(item)" icon="'chevron-right'" feather="true" class-name="'icon'"></pr-icon>
</div> </div>
</rd-widget-body> </td>
</rd-widget> <td>
<a ng-if="item.KubernetesApplications" ui-sref="kubernetes.helm({ name: item.Name, namespace: item.ResourcePool })" ng-click="$event.stopPropagation()"
>{{ item.Name }}
</a>
<a
ng-if="!item.KubernetesApplications"
ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool })"
ng-click="$event.stopPropagation()"
>{{ item.Name }}
</a>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item)">system</span>
<span class="label label-primary image-tag label-margins" ng-if="!$ctrl.isSystemNamespace(item) && $ctrl.isExternalApplication(item)">external</span>
</td>
<td>{{ item.StackName || '-' }}</td>
<td>
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: item.ResourcePool })" ng-click="$event.stopPropagation()">{{ item.ResourcePool }}</a>
</td>
<td title="{{ item.Image }}"
>{{ item.Image | truncate: 64 }} <span ng-if="item.Containers.length > 1">+ {{ item.Containers.length - 1 }}</span></td
>
<td>{{ item.ApplicationType | kubernetesApplicationTypeText }}</td>
<td ng-if="item.ApplicationType !== $ctrl.KubernetesApplicationTypes.POD">
<status-indicator ok="(item.TotalPodsCount > 0 && item.TotalPodsCount === item.RunningPodsCount) || item.Status === 'Ready'"></status-indicator>
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.REPLICATED">Replicated</span>
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.GLOBAL">Global</span>
<span ng-if="item.RunningPodsCount >= 0 && item.TotalPodsCount >= 0"
><code>{{ item.RunningPodsCount }}</code> / <code>{{ item.TotalPodsCount }}</code></span
>
<span ng-if="item.KubernetesApplications">{{ item.Status }}</span>
</td>
<td ng-if="item.ApplicationType === $ctrl.KubernetesApplicationTypes.POD">
{{ item.Pods[0].Status }}
</td>
<td>
<span>
{{ item.Services.length === 0 ? 'No' : 'Yes' }}
</span>
</td>
<td>{{ item.CreationDate | getisodate }} {{ item.ApplicationOwner ? 'by ' + item.ApplicationOwner : '' }}</td>
</tr>
<tr dir-paginate-end ng-show="$ctrl.isExpandable(item) && $ctrl.isItemExpanded(item)" ng-class="{ 'secondary-body': $ctrl.isPrimary && !item.KubernetesApplications }">
<td></td>
<td colspan="8" class="datatable-padding-vertical">
<span ng-if="item.KubernetesApplications">
<kubernetes-applications-datatable
dataset="item.KubernetesApplications"
table-key="{{ item.Id }}_table"
settings-key="{{ $ctrl.tableKey }}"
order-by="Name"
remove-action="$ctrl.removeAction"
refresh-callback="$ctrl.refreshCallback"
on-publishing-mode-click="($ctrl.onPublishingModeClick)"
is-primary="false"
>
</kubernetes-applications-datatable>
</span>
<span ng-if="!item.KubernetesApplications">
<kubernetes-applications-datatable-url ng-if="$ctrl.getPublishedUrl(item)" published-url="{{ $ctrl.getPublishedUrl(item) }}"></kubernetes-applications-datatable-url>
<kubernetes-applications-datatable-details
ng-if="$ctrl.hasConfigurationSecrets(item)"
configurations="item.Configurations"
></kubernetes-applications-datatable-details>
</span>
</td>
</tr>
<tr ng-if="!$ctrl.dataset">
<td colspan="8" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="8" class="text-center text-muted">No application available.</td>
</tr>
</tbody>
</table>
</div>
<div ng-if="$ctrl.isPrimary" class="footer pl-5" ng-if="$ctrl.dataset">
<div class="infoBar !ml-0" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div>
<div class="paginationControls">
<form class="form-inline">
<span class="limitSelector">
<span class="mr-1"> Items per page </span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()" data-cy="component-paginationSelect">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</span>
<dir-pagination-controls max-size="5" pagination-id="$ctrl.tableKey"></dir-pagination-controls>
</form>
</div>
</div>
</div> </div>

View File

@ -1,250 +1,280 @@
<div class="datatable"> <div class="datatable">
<rd-widget> <!-- table title and action menu -->
<rd-widget-body classes="no-padding"> <div class="toolBar !flex-col gap-1">
<div class="toolBar"> <div class="toolBar vertical-center !gap-x-5 !gap-y-1 flex-wrap !p-0 w-full">
<div class="toolBarTitle"> <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px"></i> {{ $ctrl.titleText }} </div> <!-- title -->
<span class="small text-muted" style="float: left; margin-top: 5px" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem"> <div class="toolBarTitle vertical-center">
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px"></i> <pr-icon icon="'repeat'" feather="true" class-name="'icon-nested-blue'" mode="'primary'"></pr-icon>
System resources are hidden, this can be changed in the table settings. Port mappings
</span>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Table settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader"> Table settings </div>
<div class="menuContent">
<div>
<div class="md-checkbox" ng-if="$ctrl.isAdmin">
<input id="ports_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
<label for="ports_setting_show_system">Show system resources</label>
</div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()" />
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate"> Refresh rate </label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="searchBar"> <div class="searchBar vertical-center">
<i class="fa fa-search searchIcon" aria-hidden="true"></i> <pr-icon icon="'search'" feather="true" class-name="'icon !h-3'"></pr-icon>
<input <input
type="text" type="text"
class="searchInput" class="searchInput"
ng-model="$ctrl.state.textFilter" ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()" ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..." placeholder="Search for a port mapping..."
auto-focus auto-focus
ng-model-options="{ debounce: 300 }" ng-model-options="{ debounce: 300 }"
/> />
</div> </div>
<div class="table-responsive"> <!-- actions -->
<table class="table table-hover nowrap-cells"> <div data-cy="k8sApp-tableSettings" class="settings">
<thead> <span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<tr> <span uib-dropdown-toggle aria-label="Settings">
<th> <pr-icon icon="'more-vertical'" feather="true" class-name="'icon !mr-0 !h-4'"></pr-icon>
<a ng-click="$ctrl.expandAll()" ng-if="$ctrl.hasExpandableItems()"> </span>
<i ng-class="{ 'fas fa-angle-down': $ctrl.state.expandAll, 'fas fa-angle-right': !$ctrl.state.expandAll }" aria-hidden="true"></i> <div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
</a> <div class="tableMenu">
</th> <div class="menuHeader"> Table settings </div>
<th> <div class="menuContent">
<a ng-click="$ctrl.changeOrderBy('Name')"> <div>
Application <div class="md-checkbox" ng-if="$ctrl.isAdmin">
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && !$ctrl.state.reverseOrder"></i> <input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"></i> <label for="applications_setting_show_system">Show system resources</label>
</a> </div>
</th> <div class="md-checkbox">
<th> Publishing mode </th> <input
<th> id="setting_auto_refresh"
<a ng-click="$ctrl.changeOrderBy('TargetPort')"> type="checkbox"
Exposed port ng-model="$ctrl.settings.repeater.autoRefresh"
<i class="fa fa-sort-numeric-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'TargetPort' && !$ctrl.state.reverseOrder"></i> ng-change="$ctrl.onSettingsRepeaterChange()"
<i class="fa fa-sort-numeric-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'TargetPort' && $ctrl.state.reverseOrder"></i> data-cy="k8sApp-autoRefreshCheckbox"
</a> />
</th> <label for="setting_auto_refresh">Auto refresh</label>
<th> </div>
<a ng-click="$ctrl.changeOrderBy('Port')"> <div ng-if="$ctrl.settings.repeater.autoRefresh">
Container port <label for="settings_refresh_rate"> Refresh rate </label>
<i class="fa fa-sort-numeric-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Port' && !$ctrl.state.reverseOrder"></i> <select
<i class="fa fa-sort-numeric-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Port' && $ctrl.state.reverseOrder"></i> id="settings_refresh_rate"
</a> ng-model="$ctrl.settings.repeater.refreshRate"
</th> ng-change="$ctrl.onSettingsRepeaterChange()"
<th> HTTP route </th> class="small-select"
</tr> data-cy="k8sApp-refreshRateDropdown"
</thead> >
<tbody> <option value="10">10s</option>
<!-- main rows --> <option value="30">30s</option>
<!-- dir-paginate-start track by $index --> <option value="60">1min</option>
<tr <option value="120">2min</option>
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))" <option value="300">5min</option>
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }" </select>
ng-click="$ctrl.expandItem(item, !item.Expanded)" <span>
pagination-id="$ctrl.tableKey" <pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
>
<!-- expandable -->
<td>
<a ng-if="$ctrl.itemCanExpand(item)">
<i ng-class="{ 'fas fa-angle-down': item.Expanded, 'fas fa-angle-right': !item.Expanded }" class="space-right" aria-hidden="true"></i>
</a>
</td>
<!-- Application -->
<td>
<a ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool })">{{ item.Name }}</a>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item)">system</span>
<span class="label label-primary image-tag label-margins" ng-if="!$ctrl.isSystemNamespace(item) && $ctrl.isExternalApplication(item)">external</span>
</td>
<!-- Publishing mode -->
<td>
<!-- LB -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.LOAD_BALANCER">
<span> <i class="fa fa-project-diagram" aria-hidden="true" style="margin-right: 2px"></i> LoadBalancer </span>
<span class="text-muted small" style="margin-left: 5px">
<span ng-if="item.LoadBalancerIPAddress">{{ item.LoadBalancerIPAddress }}</span>
<span ng-if="!item.LoadBalancerIPAddress">pending</span>
</span>
</span>
<!-- Internal -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.CLUSTER_IP">
<i class="fa fa-list-alt" aria-hidden="true" style="margin-right: 2px"></i> ClusterIP
</span>
<!-- Cluster -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.NODE_PORT"> <i class="fa fa-list" aria-hidden="true" style="margin-right: 2px"></i> NodePort </span>
</td>
<!-- Exposed port -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)">
{{ item.Ports[0].Port }}
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ item.Ports[0].Port }}" target="_blank" style="margin-left: 5px">
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access
</a>
</span>
</td>
<!-- Container port -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)"> {{ item.Ports[0].TargetPort }}/{{ item.Ports[0].Protocol }} </span>
</td>
<!-- HTTP route -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)">
<span ng-if="!$ctrl.portHasIngressRules(item.Ports[0])">-</span>
<span ng-if="$ctrl.portHasIngressRules(item.Ports[0])">
<span
ng-if="!$ctrl.ruleCanBeDisplayed(item.Ports[0].IngressRules[0])"
class="text-muted"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Ingress controller IP address not available yet"
style="cursor: pointer"
>pending
</span> </span>
<span ng-if="$ctrl.ruleCanBeDisplayed(item.Ports[0].IngressRules[0])"> </div>
<a ng-href="{{ $ctrl.buildIngressRuleURL(item.Ports[0].IngressRules[0]) }}" target="_blank"> </div>
{{ $ctrl.buildIngressRuleURL(item.Ports[0].IngressRules[0]) | stripprotocol }} </div>
</a> <div>
</span> <a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton">Close</a>
</span> </div>
</span> </div>
</td> </div>
</tr> </span>
<!-- sub rows --> </div>
<tr ng-show="item.Expanded" ng-repeat-start="port in item.Ports" ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"> </div>
<td ng-if="!$ctrl.portHasIngressRules(port)"></td> <!-- info text -->
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td> <div class="flex flex-row w-full">
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td> <span class="small text-muted mt-1" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<td ng-if="!$ctrl.portHasIngressRules(port)"> <pr-icon icon="'info'" feather="true" class-name="'icon'"></pr-icon>
{{ port.Port }} System resources are hidden, this can be changed in the table settings.
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ port.Port }}" target="_blank" style="margin-left: 5px"> </span>
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access </div>
</a> </div>
</td> <!-- table -->
<td ng-if="!$ctrl.portHasIngressRules(port)">{{ port.TargetPort }}/{{ port.Protocol }}</td> <div class="table-responsive">
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td> <table class="table table-hover nowrap-cells">
</tr> <thead>
<tr <tr>
ng-show="item.Expanded" <th>
ng-repeat-end <div class="cursor-pointer vertical-center" ng-click="$ctrl.expandAll()" ng-if="$ctrl.hasExpandableItems()" class="flex no-wrap min-w-max">
ng-repeat="rule in port.IngressRules" <pr-icon ng-if="$ctrl.state.expandAll" icon="'chevron-down'" feather="true" class-name="'icon'"></pr-icon>
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }" <pr-icon ng-if="!$ctrl.state.expandAll" icon="'chevron-right'" feather="true" class-name="'icon'"></pr-icon>
> </div>
<td></td> </th>
<td>-</td> <th>
<td>-</td> <table-column-header
<td> col-title="'Application'"
{{ port.Port }} can-sort="true"
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ port.Port }}" target="_blank" style="margin-left: 5px"> is-sorted="$ctrl.state.orderBy === 'Name'"
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access is-sorted-desc="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"
</a> ng-click="$ctrl.changeOrderBy('Name')"
</td> ></table-column-header>
<td>{{ port.TargetPort }}/{{ port.Protocol }}</td> </th>
<td> <th>
<table-column-header col-title="'Publishing mode'" can-sort="false"></table-column-header>
</th>
<th>
<table-column-header
col-title="'Exposed port'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'TargetPort'"
is-sorted-desc="$ctrl.state.orderBy === 'TargetPort' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('TargetPort')"
></table-column-header>
</th>
<th>
<table-column-header
col-title="'Container port'"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'Port'"
is-sorted-desc="$ctrl.state.orderBy === 'Port' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('Port')"
></table-column-header>
</th>
<th>
<table-column-header col-title="'HTTP route'" can-sort="false"></table-column-header>
</th>
</tr>
</thead>
<tbody>
<!-- main rows -->
<!-- dir-paginate-start track by $index -->
<tr
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
ng-click="$ctrl.expandItem(item, !item.Expanded)"
pagination-id="$ctrl.tableKey"
>
<!-- expandable -->
<td>
<div ng-if="$ctrl.itemCanExpand(item)">
<pr-icon ng-if="item.Expanded" icon="'chevron-down'" feather="true" class-name="'icon'"></pr-icon>
<pr-icon ng-if="!item.Expanded" icon="'chevron-right'" feather="true" class-name="'icon'"></pr-icon>
</div>
</td>
<!-- Application -->
<td>
<a ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool })">{{ item.Name }}</a>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item)">system</span>
<span class="label label-primary image-tag label-margins" ng-if="!$ctrl.isSystemNamespace(item) && $ctrl.isExternalApplication(item)">external</span>
</td>
<!-- Publishing mode -->
<td>
<!-- LB -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.LOAD_BALANCER">
<span><pr-icon icon="'share-2'" feather="true" class-name="'icon'"></pr-icon> LoadBalancer </span>
<span class="text-muted small ml-5">
<span ng-if="item.LoadBalancerIPAddress">{{ item.LoadBalancerIPAddress }}</span>
<span ng-if="!item.LoadBalancerIPAddress">pending</span>
</span>
</span>
<!-- Internal -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.CLUSTER_IP"> <i class="fa fa-list-alt mr-0.5" aria-hidden="true"></i> ClusterIP </span>
<!-- Cluster -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.NODE_PORT"> <pr-icon icon="'list'" feather="true" class-name="'icon'"></pr-icon> NodePort </span>
</td>
<!-- Exposed port -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)">
{{ item.Ports[0].Port }}
<a class="vertical-center" ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ item.Ports[0].Port }}" target="_blank" class="ml-1">
<pr-icon icon="'external-link'" feather="true" class-name="'icon'"></pr-icon> access
</a>
</span>
</td>
<!-- Container port -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)"> {{ item.Ports[0].TargetPort }}/{{ item.Ports[0].Protocol }} </span>
</td>
<!-- HTTP route -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)">
<span ng-if="!$ctrl.portHasIngressRules(item.Ports[0])">-</span>
<span ng-if="$ctrl.portHasIngressRules(item.Ports[0])">
<span <span
ng-if="!$ctrl.ruleCanBeDisplayed(rule)" ng-if="!$ctrl.ruleCanBeDisplayed(item.Ports[0].IngressRules[0])"
class="text-muted" class="text-muted cursor-pointer"
tooltip-append-to-body="true" tooltip-append-to-body="true"
tooltip-placement="bottom" tooltip-placement="bottom"
tooltip-class="portainer-tooltip" tooltip-class="portainer-tooltip"
uib-tooltip="Ingress controller IP address not available yet" uib-tooltip="Ingress controller IP address not available yet"
style="cursor: pointer"
>pending >pending
</span> </span>
<span ng-if="$ctrl.ruleCanBeDisplayed(rule)"> <span ng-if="$ctrl.ruleCanBeDisplayed(item.Ports[0].IngressRules[0])">
<a ng-href="{{ $ctrl.buildIngressRuleURL(rule) }}" target="_blank"> <a ng-href="{{ $ctrl.buildIngressRuleURL(item.Ports[0].IngressRules[0]) }}" target="_blank">
{{ $ctrl.buildIngressRuleURL(rule) | stripprotocol }} {{ $ctrl.buildIngressRuleURL(item.Ports[0].IngressRules[0]) | stripprotocol }}
</a> </a>
</span> </span>
</td> </span>
</tr>
<tr dir-paginate-end></tr>
<!-- no dataset -->
<tr ng-if="!$ctrl.dataset">
<td colspan="6" class="text-center text-muted">Loading...</td>
</tr>
<!-- no values in filtered dataset -->
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="6" class="text-center text-muted">No application port mapping available.</td>
</tr>
</tbody>
</table>
</div>
<div class="footer" ng-if="$ctrl.dataset">
<div class="infoBar" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div>
<div class="paginationControls">
<form class="form-inline">
<span class="limitSelector">
<span style="margin-right: 5px"> Items per page </span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()" data-cy="component-paginationSelect">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</span> </span>
<dir-pagination-controls max-size="5" pagination-id="$ctrl.tableKey"></dir-pagination-controls> </td>
</form> </tr>
</div> <!-- sub rows -->
</div> <tr ng-show="item.Expanded" ng-repeat-start="port in item.Ports" ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }">
</rd-widget-body> <td ng-if="!$ctrl.portHasIngressRules(port)"></td>
</rd-widget> <td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">
{{ port.Port }}
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ port.Port }}" target="_blank" class="ml-1">
<pr-icon icon="'external-link'" feather="true"></pr-icon> access
</a>
</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">{{ port.TargetPort }}/{{ port.Protocol }}</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
</tr>
<tr
ng-show="item.Expanded"
ng-repeat-end
ng-repeat="rule in port.IngressRules"
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
>
<td></td>
<td>-</td>
<td>-</td>
<td>
{{ port.Port }}
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ port.Port }}" target="_blank" class="ml-1">
<pr-icon icon="'external-link'" feather="true"></pr-icon>access
</a>
</td>
<td>{{ port.TargetPort }}/{{ port.Protocol }}</td>
<td>
<span
ng-if="!$ctrl.ruleCanBeDisplayed(rule)"
class="text-muted cursor-pointer"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Ingress controller IP address not available yet"
>pending
</span>
<span ng-if="$ctrl.ruleCanBeDisplayed(rule)">
<a ng-href="{{ $ctrl.buildIngressRuleURL(rule) }}" target="_blank">
{{ $ctrl.buildIngressRuleURL(rule) | stripprotocol }}
</a>
</span>
</td>
</tr>
<tr class="!h-0" dir-paginate-end></tr>
<!-- no dataset -->
<tr ng-if="!$ctrl.dataset">
<td colspan="6" class="text-center text-muted">Loading...</td>
</tr>
<!-- no values in filtered dataset -->
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="6" class="text-center text-muted">No application port mapping available.</td>
</tr>
</tbody>
</table>
</div>
<div class="footer pl-5" ng-if="$ctrl.dataset">
<div class="infoBar !ml-0" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div>
<div class="paginationControls">
<form class="form-inline">
<span class="limitSelector">
<span class="mr-1"> Items per page </span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()" data-cy="component-paginationSelect">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</span>
<dir-pagination-controls max-size="5" pagination-id="$ctrl.tableKey"></dir-pagination-controls>
</form>
</div>
</div>
</div> </div>

View File

@ -1,31 +1,69 @@
<div class="datatable"> <div class="datatable">
<rd-widget> <!-- table title and action menu -->
<rd-widget-body classes="no-padding"> <div class="toolBar !flex-col gap-1">
<div class="toolBar"> <div class="toolBar vertical-center !gap-x-5 !gap-y-1 flex-wrap !p-0 w-full">
<div class="toolBarTitle"> <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px"></i> {{ $ctrl.titleText }} </div> <!-- title -->
<span class="small text-muted" style="float: left; margin-top: 5px" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem"> <div class="toolBarTitle vertical-center">
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px"></i> <pr-icon icon="'list'" feather="true" class-name="'icon-nested-blue'" mode="'primary'"></pr-icon>
System resources are hidden, this can be changed in the table settings. Stacks
</span> </div>
<div class="settings"> <!-- actions -->
<div class="searchBar vertical-center">
<pr-icon icon="'search'" feather="true" class-name="'!h-3'"></pr-icon>
<input
type="text"
class="searchInput min-w-min self-start"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search for a stack..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>
</div>
<div class="actionBar !gap-3 !mr-0">
<button
type="button"
class="btn btn-sm btn-dangerlight h-fit vertical-center !ml-0"
ng-disabled="$ctrl.state.selectedItemCount === 0"
ng-click="$ctrl.removeAction($ctrl.state.selectedItems)"
data-cy="k8sApp-removeAppButton"
>
<pr-icon icon="'trash-2'" feather="true"></pr-icon>
Remove
</button>
<div class="settings" data-cy="k8sApp-tableSettings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open"> <span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Table settings</span> <span uib-dropdown-toggle>
<pr-icon icon="'more-vertical'" feather="true" class-name="'!mr-0 !h-4'"></pr-icon>
</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu> <div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu"> <div class="tableMenu">
<div class="menuHeader"> Table settings </div> <div class="menuHeader"> Table settings </div>
<div class="menuContent"> <div class="menuContent">
<div> <div>
<div class="md-checkbox" ng-if="$ctrl.isAdmin"> <div class="md-checkbox" ng-if="$ctrl.isAdmin">
<input id="stacks_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" /> <input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
<label for="stacks_setting_show_system">Show system resources</label> <label for="applications_setting_show_system">Show system resources</label>
</div> </div>
<div class="md-checkbox"> <div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()" /> <input
id="setting_auto_refresh"
type="checkbox"
ng-model="$ctrl.settings.repeater.autoRefresh"
ng-change="$ctrl.onSettingsRepeaterChange()"
data-cy="k8sApp-autoRefreshCheckbox"
/>
<label for="setting_auto_refresh">Auto refresh</label> <label for="setting_auto_refresh">Auto refresh</label>
</div> </div>
<div ng-if="$ctrl.settings.repeater.autoRefresh"> <div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate"> Refresh rate </label> <label for="settings_refresh_rate"> Refresh rate </label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select"> <select
id="settings_refresh_rate"
ng-model="$ctrl.settings.repeater.refreshRate"
ng-change="$ctrl.onSettingsRepeaterChange()"
class="small-select"
data-cy="k8sApp-refreshRateDropdown"
>
<option value="10">10s</option> <option value="10">10s</option>
<option value="30">30s</option> <option value="30">30s</option>
<option value="60">1min</option> <option value="60">1min</option>
@ -33,148 +71,155 @@
<option value="300">5min</option> <option value="300">5min</option>
</select> </select>
<span> <span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i> <i id="refreshRateChange" class="fa fa-check green-icon mt-2" aria-hidden="true"></i>
</span> </span>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a> <a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton">Close</a>
</div> </div>
</div> </div>
</div> </div>
</span> </span>
</div> </div>
</div> </div>
<div class="actionBar"> </div>
<button type="button" class="btn btn-sm btn-danger" ng-disabled="$ctrl.state.selectedItemCount === 0" ng-click="$ctrl.removeAction($ctrl.state.selectedItems)"> <!-- info text -->
<i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove <div class="flex flex-row">
</button> <span class="small text-muted mt-1" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
</div> <pr-icon icon="'info'" feather="true"></pr-icon>
<div class="searchBar"> System resources are hidden, this can be changed in the table settings.
<i class="fa fa-search searchIcon" aria-hidden="true"></i> </span>
<input </div>
type="text" </div>
class="searchInput" <div class="table-responsive">
ng-model="$ctrl.state.textFilter" <table class="table table-hover nowrap-cells">
ng-change="$ctrl.onTextFilterChange()" <thead>
placeholder="Search..." <tr>
auto-focus <th class="w-20 dropdown">
ng-model-options="{ debounce: 300 }" <div class="flex no-wrap h-full items-center">
/> <span class="md-checkbox">
</div> <input id="select_all" type="checkbox" ng-model="$ctrl.state.selectAll" ng-change="$ctrl.selectAll()" />
<div class="table-responsive"> <label for="select_all"></label>
<table class="table table-hover nowrap-cells"> </span>
<thead> <div class="cursor-pointer" ng-click="$ctrl.expandAll()" ng-if="$ctrl.hasExpandableItems()">
<tr> <pr-icon ng-if="$ctrl.state.expandAll" icon="'chevron-down'" feather="true"></pr-icon>
<th style="width: 55px"> <pr-icon ng-if="!$ctrl.state.expandAll" icon="'chevron-right'" feather="true"></pr-icon>
<span class="md-checkbox"> </div>
<input id="select_all" type="checkbox" ng-model="$ctrl.state.selectAll" ng-change="$ctrl.selectAll()" /> </div>
<label for="select_all"></label> </th>
</span> <th>
<a ng-click="$ctrl.expandAll()" ng-if="$ctrl.hasExpandableItems()"> <table-column-header
<i ng-class="{ 'fas fa-angle-down': $ctrl.state.expandAll, 'fas fa-angle-right': !$ctrl.state.expandAll }" aria-hidden="true"></i> col-title="'Stack'"
</a> can-sort="true"
</th> is-sorted="$ctrl.state.orderBy === 'Name'"
<th> is-sorted-desc="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"
<a ng-click="$ctrl.changeOrderBy('Name')"> ng-click="$ctrl.changeOrderBy('Name')"
Stack ></table-column-header>
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && !$ctrl.state.reverseOrder"></i> </th>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"></i> <th>
</a> <table-column-header
</th> col-title="'Namespace'"
<th> can-sort="true"
<a ng-click="$ctrl.changeOrderBy('ResourcePool')"> is-sorted="$ctrl.state.orderBy === 'ResourcePool'"
Namespace is-sorted-desc="$ctrl.state.orderBy === 'ResourcePool' && $ctrl.state.reverseOrder"
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'ResourcePool' && !$ctrl.state.reverseOrder"></i> ng-click="$ctrl.changeOrderBy('ResourcePool')"
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'ResourcePool' && $ctrl.state.reverseOrder"></i> ></table-column-header>
</a> </th>
</th> <th>
<th> <table-column-header
<a ng-click="$ctrl.changeOrderBy('Applications.length')"> col-title="'Applications'"
Applications can-sort="true"
<i class="fa fa-sort-numeric-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Applications.length' && !$ctrl.state.reverseOrder"></i> is-sorted="$ctrl.state.orderBy === 'Applications.length'"
<i class="fa fa-sort-numeric-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Applications.length' && $ctrl.state.reverseOrder"></i> is-sorted-desc="$ctrl.state.orderBy === 'Applications.length' && $ctrl.state.reverseOrder"
</a> ng-click="$ctrl.changeOrderBy('Applications.length')"
</th> ></table-column-header>
<th> Actions </th> </th>
</tr> <th>
</thead> <table-column-header col-title="'Actions'" can-sort="false"></table-column-header>
<tbody> </th>
<tr </tr>
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))" </thead>
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }" <tbody>
ng-click="$ctrl.expandItem(item, !item.Expanded)" <tr
pagination-id="$ctrl.tableKey" dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
ng-click="$ctrl.expandItem(item, !item.Expanded)"
pagination-id="$ctrl.tableKey"
>
<td>
<div class="flex no-wrap items-center">
<span class="md-checkbox">
<input
id="select_{{ $index }}"
type="checkbox"
ng-model="item.Checked"
ng-click="$ctrl.selectItem(item, $event); $event.stopPropagation();"
ng-disabled="!$ctrl.allowSelection(item)"
/>
<label for="select_{{ $index }}"></label>
</span>
<div ng-if="$ctrl.itemCanExpand(item)" class="vertical-center">
<pr-icon ng-if="item.Expanded" icon="'chevron-down'" feather="true"></pr-icon>
<pr-icon ng-if="!item.Expanded" icon="'chevron-right'" feather="true"></pr-icon>
</div>
</div>
</td>
<td>
{{ item.Name }}
</td>
<td>
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: item.ResourcePool })" ng-click="$event.stopPropagation();">{{ item.ResourcePool }}</a>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item.ResourcePool)">system</span>
</td>
<td>{{ item.Applications.length }}</td>
<td>
<a class="vertical-center" ui-sref="kubernetes.stacks.stack.logs({ namespace: item.ResourcePool, name: item.Name })">
<pr-icon icon="'file-text'" size="'md'" title="Logs" feather="true"></pr-icon>
Logs
</a>
</td>
</tr>
<tr
dir-paginate-end
ng-show="item.Expanded"
ng-repeat="app in item.Applications"
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
>
<td></td>
<td colspan="4">
<a ui-sref="kubernetes.applications.application({ name: app.Name, namespace: app.ResourcePool })">{{ app.Name }}</a>
<span style="margin-left: 5px" class="label label-primary image-tag" ng-if="!$ctrl.isSystemNamespace(app.ResourcePool) && $ctrl.isExternalApplication(app)"
>external</span
> >
<td> </td>
<span class="md-checkbox"> </tr>
<input <tr ng-if="!$ctrl.dataset">
id="select_{{ $index }}" <td colspan="5" class="text-center text-muted">Loading...</td>
type="checkbox" </tr>
ng-model="item.Checked" <tr ng-if="$ctrl.state.filteredDataSet.length === 0">
ng-click="$ctrl.selectItem(item, $event); $event.stopPropagation();" <td colspan="5" class="text-center text-muted">No stack available.</td>
ng-disabled="!$ctrl.allowSelection(item)" </tr>
/> </tbody>
<label for="select_{{ $index }}"></label> </table>
</span> </div>
<a ng-if="$ctrl.itemCanExpand(item)"> <div class="footer pl-5" ng-if="$ctrl.dataset">
<i ng-class="{ 'fas fa-angle-down': item.Expanded, 'fas fa-angle-right': !item.Expanded }" class="space-right" aria-hidden="true"></i> <div class="infoBar !ml-0" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div>
</a> <div class="paginationControls">
</td> <form class="form-inline">
<td> <span class="limitSelector">
{{ item.Name }} <span style="margin-right: 5px"> Items per page </span>
</td> <select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()" data-cy="component-paginationSelect">
<td> <option value="0">All</option>
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: item.ResourcePool })" ng-click="$event.stopPropagation();">{{ item.ResourcePool }}</a> <option value="10">10</option>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item.ResourcePool)">system</span> <option value="25">25</option>
</td> <option value="50">50</option>
<td>{{ item.Applications.length }}</td> <option value="100">100</option>
<td> </select>
<a ui-sref="kubernetes.stacks.stack.logs({ namespace: item.ResourcePool, name: item.Name })"> <i class="fa fa-file-alt" aria-hidden="true"></i> Logs </a> </span>
</td> <dir-pagination-controls max-size="5" pagination-id="$ctrl.tableKey"></dir-pagination-controls>
</tr> </form>
<tr </div>
dir-paginate-end </div>
ng-show="item.Expanded"
ng-repeat="app in item.Applications"
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
>
<td></td>
<td colspan="4">
<a ui-sref="kubernetes.applications.application({ name: app.Name, namespace: app.ResourcePool })">{{ app.Name }}</a>
<span style="margin-left: 5px" class="label label-primary image-tag" ng-if="!$ctrl.isSystemNamespace(app.ResourcePool) && $ctrl.isExternalApplication(app)"
>external</span
>
</td>
</tr>
<tr ng-if="!$ctrl.dataset">
<td colspan="5" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="5" class="text-center text-muted">No stack available.</td>
</tr>
</tbody>
</table>
</div>
<div class="footer" ng-if="$ctrl.dataset">
<div class="infoBar" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div>
<div class="paginationControls">
<form class="form-inline">
<span class="limitSelector">
<span style="margin-right: 5px"> Items per page </span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()" data-cy="component-paginationSelect">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</span>
<dir-pagination-controls max-size="5" pagination-id="$ctrl.tableKey"></dir-pagination-controls>
</form>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div> </div>

View File

@ -9,7 +9,7 @@
<rd-widget-body classes="no-padding"> <rd-widget-body classes="no-padding">
<uib-tabset active="ctrl.state.activeTab" justified="true" type="pills"> <uib-tabset active="ctrl.state.activeTab" justified="true" type="pills">
<uib-tab index="0" classes="btn-sm" select="ctrl.selectTab(0)"> <uib-tab index="0" classes="btn-sm" select="ctrl.selectTab(0)">
<uib-tab-heading> <i class="fa fa-laptop-code space-right" aria-hidden="true"></i> Applications </uib-tab-heading> <uib-tab-heading class="vertical-center"> <pr-icon icon="'box'" feather="true"></pr-icon> Applications </uib-tab-heading>
<kubernetes-applications-datatable <kubernetes-applications-datatable
dataset="ctrl.state.applications" dataset="ctrl.state.applications"
table-key="kubernetes.applications" table-key="kubernetes.applications"
@ -23,12 +23,12 @@
</kubernetes-applications-datatable> </kubernetes-applications-datatable>
</uib-tab> </uib-tab>
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)"> <uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
<uib-tab-heading> <i class="fa fa-exchange-alt space-right" aria-hidden="true"></i> Port mappings </uib-tab-heading> <uib-tab-heading class="vertical-center"> <pr-icon icon="'repeat'" feather="true"></pr-icon> Port mappings </uib-tab-heading>
<kubernetes-applications-ports-datatable dataset="ctrl.state.ports" table-key="kubernetes.applications.ports" order-by="Name" refresh-callback="ctrl.getApplications"> <kubernetes-applications-ports-datatable dataset="ctrl.state.ports" table-key="kubernetes.applications.ports" order-by="Name" refresh-callback="ctrl.getApplications">
</kubernetes-applications-ports-datatable> </kubernetes-applications-ports-datatable>
</uib-tab> </uib-tab>
<uib-tab index="2" classes="btn-sm" select="ctrl.selectTab(2)"> <uib-tab index="2" classes="btn-sm" select="ctrl.selectTab(2)">
<uib-tab-heading> <i class="fa fa-th-list space-right" aria-hidden="true"></i> Stacks </uib-tab-heading> <uib-tab-heading class="vertical-center"> <pr-icon icon="'list'" feather="true"></pr-icon> Stacks </uib-tab-heading>
<kubernetes-applications-stacks-datatable <kubernetes-applications-stacks-datatable
dataset="ctrl.state.stacks" dataset="ctrl.state.stacks"
table-key="kubernetes.applications.stacks" table-key="kubernetes.applications.stacks"

View File

@ -1,4 +1,10 @@
<span> <span>
<button type="button" class="btn btn-link nopadding" ng-click="$ctrl.copyValueText()" title="Copy Value"> <i class="fa fa-copy"></i> Copy </button> <button type="button" class="btn btn-link nopadding" ng-click="$ctrl.copyValueText()" title="Copy Value">
<span ng-class="{ 'copy-button-fadeout': $ctrl.state.isFading }" class="copy-button-copy-text"> <i class="fa fa-check" aria-hidden="true"></i> copied </span> <pr-icon icon="'clipboard'" feather="true"></pr-icon>
Copy
</button>
<span ng-class="{ 'copy-button-fadeout': $ctrl.state.isFading }" class="copy-button-copy-text">
<pr-icon icon="'check'" feather="true"></pr-icon>
copied
</span>
</span> </span>

View File

@ -47,6 +47,10 @@
text-decoration: underline; text-decoration: underline;
} }
.datatable tr > td a.actions {
color: currentColor;
}
.toolBar .actionBar { .toolBar .actionBar {
display: inline-flex; display: inline-flex;
} }

View File

@ -4,6 +4,12 @@
</div> </div>
<button type="button" class="btn btn-link nopadding" ng-click="$ctrl.show = !$ctrl.show" title="Show/Hide value"> <button type="button" class="btn btn-link nopadding" ng-click="$ctrl.show = !$ctrl.show" title="Show/Hide value">
<div ng-if="!$ctrl.show"> <i class="fa fa-eye-slash"></i> Show</div> <div ng-if="!$ctrl.show">
<div ng-if="$ctrl.show"> <i class="fa fa-eye"></i> Hide</div> <pr-icon icon="'eye-off'" feather="true"></pr-icon>
Show</div
>
<div ng-if="$ctrl.show">
<pr-icon icon="'eye'" feather="true"></pr-icon>
Hide</div
>
</button> </button>