mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(home): update endpoint list (#2060)
This commit is contained in:
parent
48179b9e3d
commit
3c6f6cf5bf
18 changed files with 247 additions and 234 deletions
|
@ -1,113 +0,0 @@
|
|||
<div class="datatable">
|
||||
<rd-widget>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<div class="toolBar">
|
||||
<div class="toolBarTitle">
|
||||
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="searchBar">
|
||||
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
|
||||
<input type="text" class="searchInput" ng-model="$ctrl.state.textFilter" placeholder="Search by name, group, tag..." auto-focus>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table nowrap-cells">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('Name')">
|
||||
Name
|
||||
<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>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('GroupName')">
|
||||
Group
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'GroupName' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'GroupName' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('Status')">
|
||||
Status
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Status' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Status' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('Type')">
|
||||
Type
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Type' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Type' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('Snapshots[0].Time')">
|
||||
Last snapshot
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Snapshots[0].Time' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Snapshots[0].Time' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit))">
|
||||
<td>
|
||||
<a ng-click="$ctrl.dashboardAction(item)"><i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{ item.Name }}</a>
|
||||
</td>
|
||||
<td>{{ item.GroupName }}</td>
|
||||
<td>
|
||||
<span class="label label-{{ item.Status|endpointstatusbadge }}">{{ item.Status === 1 ? 'up' : 'down' }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>
|
||||
<i ng-class="item.Type | endpointtypeicon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
{{ item.Type | endpointtypename }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="item.Snapshots.length > 0">
|
||||
{{ item.Snapshots[0].Time | getisodatefromtimestamp }}
|
||||
</span>
|
||||
<span ng-if="item.Snapshots.length === 0">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr dir-paginate-end class="text-muted" ng-if="item.Snapshots.length > 0">
|
||||
<td colspan="5" style="border: 0; text-align:center;">
|
||||
<snapshot-details
|
||||
snapshot="item.Snapshots[0]"
|
||||
></snapshot-details
|
||||
</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 endpoint available.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="footer" ng-if="$ctrl.dataset">
|
||||
<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()">
|
||||
<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"></dir-pagination-controls>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
|
@ -1,13 +0,0 @@
|
|||
angular.module('portainer.app').component('endpointsSnapshotDatatable', {
|
||||
templateUrl: 'app/portainer/components/datatables/endpoints-snapshot-datatable/endpointsSnapshotDatatable.html',
|
||||
controller: 'GenericDatatableController',
|
||||
bindings: {
|
||||
titleText: '@',
|
||||
titleIcon: '@',
|
||||
dataset: '<',
|
||||
tableKey: '@',
|
||||
orderBy: '@',
|
||||
reverseOrder: '<',
|
||||
dashboardAction: '<'
|
||||
}
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
<span style="border-top: 2px solid #e2e2e2; padding: 7px;">
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-th-list space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.StackCount }} stacks
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;" ng-if="$ctrl.snapshot.Swarm">
|
||||
<i class="fa fa-list-alt space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.ServiceCount }} services
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-server space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.RunningContainerCount + $ctrl.snapshot.StoppedContainerCount }} containers
|
||||
<span ng-if="$ctrl.snapshot.RunningContainerCount > 0 || $ctrl.snapshot.StoppedContainerCount > 0">
|
||||
-
|
||||
<i class="fa fa-heartbeat green-icon" aria-hidden="true"></i> {{ $ctrl.snapshot.RunningContainerCount }}
|
||||
<i class="fa fa-heartbeat red-icon" aria-hidden="true"></i> {{ $ctrl.snapshot.StoppedContainerCount }}
|
||||
</span>
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-cubes space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.VolumeCount }} volumes
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-clone space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.ImageCount }} images
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px; border-left: 2px solid #e2e2e2;">
|
||||
<i class="fa fa-memory" aria-hidden="true"></i> {{ $ctrl.snapshot.TotalMemory | humansize }}
|
||||
<i class="fa fa-microchip space-left" aria-hidden="true"></i> {{ $ctrl.snapshot.TotalCPU }}
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px; border-left: 2px solid #e2e2e2;">
|
||||
{{ $ctrl.snapshot.Swarm ? 'Swarm' : 'Standalone' }} {{ $ctrl.snapshot.DockerVersion }}
|
||||
</span>
|
||||
</span>
|
|
@ -1,6 +0,0 @@
|
|||
angular.module('portainer.app').component('snapshotDetails', {
|
||||
templateUrl: 'app/portainer/components/datatables/endpoints-snapshot-datatable/snapshot-details/snapshotDetails.html',
|
||||
bindings: {
|
||||
snapshot: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,75 @@
|
|||
<div class="blocklist-item" ng-click="$ctrl.onSelect($ctrl.model)">
|
||||
<div class="blocklist-item-box">
|
||||
<span ng-class="['blocklist-item-logo', 'endpoint-item', { azure: $ctrl.model.Type === 3 }]">
|
||||
<i ng-class="$ctrl.model.Type | endpointtypeicon" class="fa-4x blue-icon" aria-hidden="true"></i>
|
||||
</span>
|
||||
|
||||
<span class="col-sm-12">
|
||||
|
||||
<div class="blocklist-item-line endpoint-item">
|
||||
<span>
|
||||
<span class="blocklist-item-title endpoint-item">
|
||||
{{ $ctrl.model.Name }}
|
||||
</span>
|
||||
<span class="space-left blocklist-item-subtitle">
|
||||
<span class="label label-{{ $ctrl.model.Status|endpointstatusbadge }}">
|
||||
{{ $ctrl.model.Status === 1 ? 'up' : 'down' }}
|
||||
</span>
|
||||
<span class="space-left small text-muted" ng-if="$ctrl.model.Snapshots[0]">
|
||||
{{ $ctrl.model.Snapshots[0].Time | getisodatefromtimestamp }}
|
||||
</span>
|
||||
|
||||
</span>
|
||||
</span>
|
||||
<span class="small">
|
||||
{{ $ctrl.model.GroupName }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="blocklist-item-line endpoint-item" ng-if="$ctrl.model.Snapshots[0]">
|
||||
<span class="blocklist-item-desc">
|
||||
<span>
|
||||
<span style="padding: 0 7px 0 0;">
|
||||
<i class="fa fa-th-list space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].StackCount }} stacks
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;" ng-if="$ctrl.model.Snapshots[0].Swarm">
|
||||
<i class="fa fa-list-alt space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].ServiceCount }} services
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-server space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].RunningContainerCount + $ctrl.model.Snapshots[0].StoppedContainerCount }} containers
|
||||
<span ng-if="$ctrl.model.Snapshots[0].RunningContainerCount > 0 || $ctrl.model.Snapshots[0].StoppedContainerCount > 0">
|
||||
-
|
||||
<i class="fa fa-heartbeat green-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].RunningContainerCount }}
|
||||
<i class="fa fa-heartbeat red-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].StoppedContainerCount }}
|
||||
</span>
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-cubes space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].VolumeCount }} volumes
|
||||
</span>
|
||||
<span style="padding: 0 7px 0 7px;">
|
||||
<i class="fa fa-clone space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].ImageCount }} images
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="small text-muted">
|
||||
{{ $ctrl.model.Snapshots[0].Swarm ? 'Swarm' : 'Standalone' }} {{ $ctrl.model.Snapshots[0].DockerVersion }} <span ng-if="$ctrl.model.Type === 2">+ <i class="fa fa-bolt" aria-hidden="true"></i> Agent</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="blocklist-item-line endpoint-item">
|
||||
<span class="small text-muted">
|
||||
<span ng-if="$ctrl.model.Tags.length === 0">
|
||||
<i class="fa fa-tags" aria-hidden="true"></i> No tags
|
||||
</span>
|
||||
<span ng-if="$ctrl.model.Tags.length > 0">
|
||||
<i class="fa fa-tags" aria-hidden="true"></i>
|
||||
<span ng-repeat="tag in $ctrl.model.Tags">
|
||||
{{ tag }}{{ $last? '' : ', ' }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
angular.module('portainer.app').component('endpointItem', {
|
||||
templateUrl: 'app/portainer/components/endpoint-list/endpoint-item/endpointItem.html',
|
||||
bindings: {
|
||||
model: '<',
|
||||
onSelect: '<'
|
||||
}
|
||||
});
|
16
app/portainer/components/endpoint-list/endpoint-list.js
Normal file
16
app/portainer/components/endpoint-list/endpoint-list.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
angular.module('portainer.app').component('endpointList', {
|
||||
templateUrl: 'app/portainer/components/endpoint-list/endpointList.html',
|
||||
controller: function() {
|
||||
var ctrl = this;
|
||||
|
||||
this.state = {
|
||||
textFilter: ''
|
||||
};
|
||||
},
|
||||
bindings: {
|
||||
titleText: '@',
|
||||
titleIcon: '@',
|
||||
endpoints: '<',
|
||||
dashboardAction: '<'
|
||||
}
|
||||
});
|
32
app/portainer/components/endpoint-list/endpointList.html
Normal file
32
app/portainer/components/endpoint-list/endpointList.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<div class="datatable">
|
||||
<rd-widget>
|
||||
<rd-widget-body classes="no-padding">
|
||||
|
||||
<div class="toolBar">
|
||||
<div class="toolBarTitle">
|
||||
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="searchBar">
|
||||
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
|
||||
<input type="text" class="searchInput" ng-model="$ctrl.state.textFilter" placeholder="Search by name, group, tag..." auto-focus>
|
||||
</div>
|
||||
|
||||
<div class="blocklist">
|
||||
<endpoint-item
|
||||
ng-repeat="endpoint in $ctrl.endpoints | filter:$ctrl.state.textFilter"
|
||||
model="endpoint"
|
||||
on-select="$ctrl.dashboardAction"
|
||||
></endpoint-item>
|
||||
<div ng-if="!$ctrl.endpoints" class="text-center text-muted">
|
||||
Loading...
|
||||
</div>
|
||||
<div ng-if="($ctrl.endpoints | filter:$ctrl.state.textFilter).length === 0" class="text-center text-muted">
|
||||
No endpoint available.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
|
@ -1,23 +1,23 @@
|
|||
<!-- template -->
|
||||
<div ng-class="{ 'template-container--selected': $ctrl.model.Selected }" class="template-container" ng-click="$ctrl.onSelect($ctrl.model)">
|
||||
<div class="template-main">
|
||||
<div ng-class="{ 'blocklist-item--selected': $ctrl.model.Selected }" class="blocklist-item" ng-click="$ctrl.onSelect($ctrl.model)">
|
||||
<div class="blocklist-item-box">
|
||||
<!-- template-image -->
|
||||
<span ng-if="$ctrl.model.Logo">
|
||||
<img class="template-logo" ng-src="{{ $ctrl.model.Logo }}" />
|
||||
<img class="blocklist-item-logo" ng-src="{{ $ctrl.model.Logo }}" />
|
||||
</span>
|
||||
<span class="template-logo" ng-if="!$ctrl.model.Logo">
|
||||
<span class="blocklist-item-logo" ng-if="!$ctrl.model.Logo">
|
||||
<i class="fa fa-rocket fa-4x blue-icon" aria-hidden="true"></i>
|
||||
</span>
|
||||
<!-- !template-image -->
|
||||
<!-- template-details -->
|
||||
<span class="col-sm-12">
|
||||
<!-- template-line1 -->
|
||||
<div class="template-line">
|
||||
<!-- blocklist-item-line1 -->
|
||||
<div class="blocklist-item-line">
|
||||
<span>
|
||||
<span class="template-title">
|
||||
<span class="blocklist-item-title">
|
||||
{{ $ctrl.model.Title }}
|
||||
</span>
|
||||
<span class="space-left template-type">
|
||||
<span class="space-left blocklist-item-subtitle">
|
||||
<span>
|
||||
<i class="fab fa-linux" aria-hidden="true" ng-if="$ctrl.model.Platform === 'linux' || !$ctrl.model.Platform"></i>
|
||||
<span ng-if="!$ctrl.model.Platform"> & </span>
|
||||
|
@ -38,17 +38,17 @@
|
|||
</btn>
|
||||
</span>
|
||||
</div>
|
||||
<!-- !template-line1 -->
|
||||
<!-- template-line2 -->
|
||||
<div class="template-line">
|
||||
<span class="template-description">
|
||||
<!-- !blocklist-item-line1 -->
|
||||
<!-- blocklist-item-line2 -->
|
||||
<div class="blocklist-item-line">
|
||||
<span class="blocklist-item-desc">
|
||||
{{ $ctrl.model.Description }}
|
||||
</span>
|
||||
<span class="small text-muted" ng-if="$ctrl.model.Categories.length > 0">
|
||||
{{ $ctrl.model.Categories.join(', ') }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- !template-line2 -->
|
||||
<!-- !blocklist-item-line2 -->
|
||||
</span>
|
||||
<!-- !template-details -->
|
||||
</div>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<input type="text" class="searchInput" ng-model="$ctrl.state.textFilter" placeholder="Search..." auto-focus>
|
||||
</div>
|
||||
|
||||
<div class="template-list">
|
||||
<div class="blocklist">
|
||||
<template-item
|
||||
ng-repeat="template in $ctrl.templates | filter: $ctrl.filterByType | filter:$ctrl.filterByCategory | filter:$ctrl.state.textFilter"
|
||||
model="template"
|
||||
|
@ -52,7 +52,7 @@
|
|||
<div ng-if="!$ctrl.templates" class="text-center text-muted">
|
||||
Loading...
|
||||
</div>
|
||||
<div ng-if="($ctrl.templates | filter: $ctrl.filterByType | filter:$ctrl.filterByCategory | filter:$ctrl.state.textFilter).length == 0" class="text-center text-muted">
|
||||
<div ng-if="($ctrl.templates | filter: $ctrl.filterByType | filter:$ctrl.filterByCategory | filter:$ctrl.state.textFilter).length === 0" class="text-center text-muted">
|
||||
No templates available.
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -80,7 +80,7 @@ angular.module('portainer.app')
|
|||
data: {
|
||||
Name: name,
|
||||
EndpointType: 3,
|
||||
GroupID: groupID,
|
||||
GroupID: groupId,
|
||||
Tags: Upload.json(tags),
|
||||
AzureApplicationID: applicationId,
|
||||
AzureTenantID: tenantId,
|
||||
|
|
|
@ -7,18 +7,17 @@
|
|||
<rd-header-content>Endpoints</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<information-panel title-text="Information" ng-if="!isAdmin && endpoints.length === 0">
|
||||
<span class="small">
|
||||
<p class="text-muted">
|
||||
<information-panel title-text="Information">
|
||||
<span class="small text-muted">
|
||||
<p ng-if="endpoints.length > 0">
|
||||
Welcome to Portainer ! Click on any endpoint in the list below to access management features.
|
||||
</p>
|
||||
<p ng-if="!isAdmin && endpoints.length === 0">
|
||||
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
You do not have access to any environment. Please contact your administrator.
|
||||
</p>
|
||||
</span>
|
||||
</information-panel>
|
||||
|
||||
<information-panel title-text="Information" ng-if="isAdmin && !applicationState.application.snapshot">
|
||||
<span class="small">
|
||||
<p class="text-muted">
|
||||
<p ng-if="isAdmin && !applicationState.application.snapshot">
|
||||
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Endpoint snapshot is disabled.
|
||||
</p>
|
||||
|
@ -27,11 +26,10 @@
|
|||
|
||||
<div class="row" ng-if="endpoints.length > 0">
|
||||
<div class="col-sm-12">
|
||||
<endpoints-snapshot-datatable
|
||||
<endpoint-list
|
||||
title-text="Endpoints" title-icon="fa-plug"
|
||||
dataset="endpoints" table-key="endpoints"
|
||||
order-by="Name"
|
||||
endpoints="endpoints"
|
||||
dashboard-action="goToDashboard"
|
||||
></endpoints-snapshot-datatable>
|
||||
></endpoint-list>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue