mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
refactor(docker): migrate dashboard to react [EE-2191] (#11574)
Some checks are pending
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
This commit is contained in:
parent
2669a44d79
commit
014a590704
54 changed files with 1297 additions and 507 deletions
|
@ -150,8 +150,7 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([
|
|||
url: '/dashboard',
|
||||
views: {
|
||||
'content@': {
|
||||
templateUrl: './views/dashboard/dashboard.html',
|
||||
controller: 'DashboardController',
|
||||
component: 'dockerDashboardView',
|
||||
},
|
||||
},
|
||||
data: {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
angular.module('portainer.docker').component('dashboardClusterAgentInfo', {
|
||||
templateUrl: './dashboardClusterAgentInfo.html',
|
||||
controller: 'DashboardClusterAgentInfoController',
|
||||
bindings: {
|
||||
endpointId: '<',
|
||||
},
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
<rd-widget>
|
||||
<rd-widget-header icon="gauge" title-text="Cluster information"></rd-widget-header>
|
||||
<rd-widget-body classes="!px-5 !py-0">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Nodes in the cluster</td>
|
||||
<td>{{ $ctrl.agentCount }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a ui-sref="docker.swarm.visualizer" class="vertical-center"><pr-icon icon="'trello'" class-name="'icon'"></pr-icon>Go to cluster visualizer</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
|
@ -1,17 +0,0 @@
|
|||
angular.module('portainer.docker').controller('DashboardClusterAgentInfoController', [
|
||||
'AgentService',
|
||||
'Notifications',
|
||||
function (AgentService, Notifications) {
|
||||
var ctrl = this;
|
||||
|
||||
this.$onInit = function () {
|
||||
AgentService.agents(ctrl.endpointId)
|
||||
.then(function success(data) {
|
||||
ctrl.agentCount = data.length;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve agent information');
|
||||
});
|
||||
};
|
||||
},
|
||||
]);
|
|
@ -3,15 +3,18 @@ import angular from 'angular';
|
|||
import { ItemView as NetworksItemView } from '@/react/docker/networks/ItemView';
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
import { DashboardView } from '@/react/docker/DashboardView/DashboardView';
|
||||
|
||||
import { containersModule } from './containers';
|
||||
|
||||
export const viewsModule = angular
|
||||
.module('portainer.docker.react.views', [containersModule])
|
||||
|
||||
.component(
|
||||
'dockerDashboardView',
|
||||
r2a(withUIRouter(withCurrentUser(DashboardView)), [])
|
||||
)
|
||||
.component(
|
||||
'networkDetailsView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(NetworksItemView))), [])
|
||||
r2a(withUIRouter(withCurrentUser(NetworksItemView)), [])
|
||||
).name;
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
<page-header title="'Dashboard'" breadcrumbs="['Environment summary']"> </page-header>
|
||||
|
||||
<div class="row" ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
|
||||
<div class="col-sm-12">
|
||||
<dashboard-cluster-agent-info endpoint-id="endpoint.Id"></dashboard-cluster-agent-info>
|
||||
</div>
|
||||
</div>
|
||||
<information-panel
|
||||
ng-if="
|
||||
!applicationState.UI.dismissedInfoPanels['docker-dashboard-info-01'] &&
|
||||
!applicationState.endpoint.mode.agentProxy &&
|
||||
applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'
|
||||
"
|
||||
title-text="Information"
|
||||
dismiss-action="dismissInformationPanel('docker-dashboard-info-01')"
|
||||
>
|
||||
<span class="small">
|
||||
<p class="text-muted" ng-if="applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<pr-icon icon="'alert-circle'" mode="'primary'"></pr-icon>
|
||||
Portainer is connected to a node that is part of a Swarm cluster. Some resources located on other nodes in the cluster might not be available for management, have a look at
|
||||
<help-link doc-link="'/admin/environments/add/swarm/agent'" target="'_blank'" children="'our agent setup'"></help-link> for more details.
|
||||
</p>
|
||||
<p class="text-muted" ng-if="applicationState.endpoint.mode.role === 'WORKER'">
|
||||
<pr-icon icon="'alert-circle'" mode="'primary'"></pr-icon>
|
||||
Portainer is connected to a worker node. Swarm management features will not be available.
|
||||
</p>
|
||||
</span>
|
||||
</information-panel>
|
||||
|
||||
<div ng-if="info">
|
||||
<div class="row" ng-if="(!applicationState.endpoint.mode.agentProxy || applicationState.endpoint.mode.provider !== 'DOCKER_SWARM_MODE') && info && endpoint">
|
||||
<div class="col-sm-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="gauge" title-text="Environment info"></rd-widget-header>
|
||||
<rd-widget-body classes="!px-5 !py-0">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Environment</td>
|
||||
<td>
|
||||
{{ endpoint.Name }}
|
||||
<span class="small text-muted space-left">
|
||||
<pr-icon icon="'cpu'"></pr-icon> {{ endpoint.Snapshots[0].TotalCPU }} <pr-icon icon="'svg-memory'"></pr-icon>
|
||||
{{ endpoint.Snapshots[0].TotalMemory | humansize }}
|
||||
</span>
|
||||
<span class="small text-muted">
|
||||
- {{ info.Swarm && info.Swarm.NodeID !== '' ? 'Swarm' : 'Standalone' }} {{ info.ServerVersion }}
|
||||
<span ng-if="endpoint.Type === 2">
|
||||
<pr-icon icon="'zap'"></pr-icon>
|
||||
Agent</span
|
||||
></span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="showEnvUrl">
|
||||
<td>URL</td>
|
||||
<td>{{ endpoint.URL | stripprotocol }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ endpoint.Gpus.length <= 1 ? 'GPU' : 'GPUs' }}</td>
|
||||
<td>{{ gpuInfoStr }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ endpointTags }}</td>
|
||||
</tr>
|
||||
<tr ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<td colspan="2">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a ui-sref="docker.swarm.visualizer" class="vertical-center"><pr-icon icon="'trello'" class-name="'icon'"></pr-icon>Go to cluster visualizer</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-4 grid grid-cols-2 gap-3">
|
||||
<a class="no-link" ui-sref="docker.stacks" ng-if="showStacks">
|
||||
<dashboard-item icon="'layers'" type="'Stack'" value="stackCount"></dashboard-item>
|
||||
</a>
|
||||
|
||||
<div ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<a class="no-link" ui-sref="docker.services">
|
||||
<dashboard-item icon="'shuffle'" type="'Service'" value="serviceCount"></dashboard-item>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<a class="no-link" ng-if="containers" ui-sref="docker.containers">
|
||||
<dashboard-item icon="'box'" type="'Container'" value="containers.length" children="containerStatusComponent"></dashboard-item>
|
||||
</a>
|
||||
|
||||
<a class="no-link" ng-if="images" ui-sref="docker.images">
|
||||
<dashboard-item icon="'list'" type="'Image'" value="images.length" children="imagesTotalSizeComponent"></dashboard-item>
|
||||
</a>
|
||||
|
||||
<a class="no-link" ui-sref="docker.volumes">
|
||||
<dashboard-item icon="'database'" type="'Volume'" value="volumeCount"></dashboard-item>
|
||||
</a>
|
||||
|
||||
<a class="no-link" ui-sref="docker.networks">
|
||||
<dashboard-item icon="'Network'" type="'Network'" value="networkCount"></dashboard-item>
|
||||
</a>
|
||||
|
||||
<div>
|
||||
<dashboard-item
|
||||
ng-if="endpoint.EnableGPUManagement && applicationState.endpoint.mode.provider === 'DOCKER_STANDALONE'"
|
||||
icon="'cpu'"
|
||||
type="'GPU'"
|
||||
value="endpoint.Gpus.length"
|
||||
></dashboard-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,141 +0,0 @@
|
|||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { PortainerEndpointTypes } from 'Portainer/models/endpoint/models';
|
||||
import { useContainerStatusComponent } from '@/react/docker/DashboardView/ContainerStatus';
|
||||
import { useImagesTotalSizeComponent } from '@/react/docker/DashboardView/ImagesTotalSize';
|
||||
|
||||
angular.module('portainer.docker').controller('DashboardController', [
|
||||
'$scope',
|
||||
'$q',
|
||||
'Authentication',
|
||||
'ContainerService',
|
||||
'ImageService',
|
||||
'NetworkService',
|
||||
'VolumeService',
|
||||
'SystemService',
|
||||
'ServiceService',
|
||||
'StackService',
|
||||
'Notifications',
|
||||
'StateManager',
|
||||
'TagService',
|
||||
'endpoint',
|
||||
function (
|
||||
$scope,
|
||||
$q,
|
||||
Authentication,
|
||||
ContainerService,
|
||||
ImageService,
|
||||
NetworkService,
|
||||
VolumeService,
|
||||
SystemService,
|
||||
ServiceService,
|
||||
StackService,
|
||||
Notifications,
|
||||
StateManager,
|
||||
TagService,
|
||||
endpoint
|
||||
) {
|
||||
$scope.dismissInformationPanel = function (id) {
|
||||
StateManager.dismissInformationPanel(id);
|
||||
};
|
||||
|
||||
$scope.showStacks = false;
|
||||
|
||||
$scope.buildGpusStr = function (gpuUseSet) {
|
||||
var gpusAvailable = new Object();
|
||||
for (let i = 0; i < ($scope.endpoint.Gpus || []).length; i++) {
|
||||
if (!gpuUseSet.has($scope.endpoint.Gpus[i].name)) {
|
||||
var exist = false;
|
||||
for (let gpuAvailable in gpusAvailable) {
|
||||
if ($scope.endpoint.Gpus[i].value == gpuAvailable) {
|
||||
gpusAvailable[gpuAvailable] += 1;
|
||||
exist = true;
|
||||
}
|
||||
}
|
||||
if (exist === false) {
|
||||
gpusAvailable[$scope.endpoint.Gpus[i].value] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
var retStr = Object.keys(gpusAvailable).length
|
||||
? _.join(
|
||||
_.map(Object.keys(gpusAvailable), (gpuAvailable) => {
|
||||
var _str = gpusAvailable[gpuAvailable];
|
||||
_str += ' x ';
|
||||
_str += gpuAvailable;
|
||||
return _str;
|
||||
}),
|
||||
' + '
|
||||
)
|
||||
: 'none';
|
||||
return retStr;
|
||||
};
|
||||
|
||||
async function initView() {
|
||||
const endpointMode = $scope.applicationState.endpoint.mode;
|
||||
$scope.endpoint = endpoint;
|
||||
|
||||
$scope.showStacks = await shouldShowStacks();
|
||||
$scope.showEnvUrl = endpoint.Type !== PortainerEndpointTypes.EdgeAgentOnDockerEnvironment && endpoint.Type !== PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment;
|
||||
$q.all({
|
||||
containers: ContainerService.containers(endpoint.Id, 1),
|
||||
images: ImageService.images(),
|
||||
volumes: VolumeService.volumes(),
|
||||
networks: NetworkService.networks(true, true, true),
|
||||
services: endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER' ? ServiceService.services() : [],
|
||||
stacks: StackService.stacks(true, endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER', endpoint.Id),
|
||||
info: SystemService.info(),
|
||||
tags: TagService.tags(),
|
||||
})
|
||||
.then(function success(data) {
|
||||
$scope.containers = data.containers;
|
||||
$scope.containerStatusComponent = useContainerStatusComponent(data.containers);
|
||||
|
||||
$scope.images = data.images;
|
||||
$scope.imagesTotalSizeComponent = useImagesTotalSizeComponent(imagesTotalSize(data.images));
|
||||
|
||||
$scope.volumeCount = data.volumes.length;
|
||||
$scope.networkCount = data.networks.length;
|
||||
$scope.serviceCount = data.services.length;
|
||||
$scope.stackCount = data.stacks.length;
|
||||
$scope.info = data.info;
|
||||
|
||||
$scope.gpuInfoStr = $scope.buildGpusStr(new Set());
|
||||
$scope.gpuUseAll = _.get($scope, 'endpoint.Snapshots[0].GpuUseAll', false);
|
||||
$scope.gpuUseList = _.get($scope, 'endpoint.Snapshots[0].GpuUseList', []);
|
||||
$scope.gpuFreeStr = 'all';
|
||||
if ($scope.gpuUseAll == true) $scope.gpuFreeStr = 'none';
|
||||
else $scope.gpuFreeStr = $scope.buildGpusStr(new Set($scope.gpuUseList));
|
||||
|
||||
$scope.endpointTags = endpoint.TagIds.length
|
||||
? _.join(
|
||||
_.filter(
|
||||
_.map(endpoint.TagIds, (id) => {
|
||||
const tag = data.tags.find((tag) => tag.Id === id);
|
||||
return tag ? tag.Name : '';
|
||||
}),
|
||||
Boolean
|
||||
),
|
||||
', '
|
||||
)
|
||||
: '-';
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to load dashboard data');
|
||||
});
|
||||
}
|
||||
|
||||
async function shouldShowStacks() {
|
||||
const isAdmin = Authentication.isAdmin();
|
||||
|
||||
return isAdmin || endpoint.SecuritySettings.allowStackManagementForRegularUsers;
|
||||
}
|
||||
|
||||
initView();
|
||||
},
|
||||
]);
|
||||
|
||||
function imagesTotalSize(images) {
|
||||
return images.reduce((acc, image) => acc + image.Size, 0);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue