Compare commits

...

2 Commits

10 changed files with 57 additions and 37 deletions

View File

@@ -8,7 +8,6 @@ import {
usePagination,
} from 'react-table';
import { useRowSelectColumn } from '@lineup-lite/hooks';
import _ from 'lodash';
import { Environment } from '@/portainer/environments/types';
import { PaginationControls } from '@/portainer/components/pagination-controls';
@@ -65,7 +64,6 @@ export function EdgeDevicesDatatable({
showWaitingRoomLink,
mpsServer,
dataset,
groups,
onRefresh,
setLoadingMessage,
}: EdgeDevicesTableProps) {
@@ -140,8 +138,6 @@ export function EdgeDevicesDatatable({
environment.AMTDeviceGUID && environment.AMTDeviceGUID !== ''
);
const groupsById = _.groupBy(groups, 'Id');
return (
<TableContainer>
<TableTitle icon="fa-plug" label="Edge Devices">
@@ -213,13 +209,8 @@ export function EdgeDevicesDatatable({
{page.map((row) => {
prepareRow(row);
const { key, className, role, style } = row.getRowProps();
const group = groupsById[row.original.GroupId];
return (
<RowProvider
key={key}
isOpenAmtEnabled={isOpenAmtEnabled}
groupName={group[0]?.Name}
>
<RowProvider key={key} isOpenAmtEnabled={isOpenAmtEnabled}>
<TableRow<Environment>
cells={row.cells}
key={key}

View File

@@ -2,25 +2,19 @@ import { createContext, useContext, useMemo, PropsWithChildren } from 'react';
interface RowContextState {
isOpenAmtEnabled: boolean;
groupName?: string;
}
const RowContext = createContext<RowContextState | null>(null);
export interface RowProviderProps {
groupName?: string;
isOpenAmtEnabled: boolean;
}
export function RowProvider({
groupName,
isOpenAmtEnabled,
children,
}: PropsWithChildren<RowProviderProps>) {
const state = useMemo(
() => ({ groupName, isOpenAmtEnabled }),
[groupName, isOpenAmtEnabled]
);
const state = useMemo(() => ({ isOpenAmtEnabled }), [isOpenAmtEnabled]);
return <RowContext.Provider value={state}>{children}</RowContext.Provider>;
}

View File

@@ -0,0 +1,13 @@
import { CellProps, Column } from 'react-table';
import { Environment } from '@/portainer/environments/types';
import { DefaultFilter } from '@/portainer/components/datatables/components/Filter';
export const edgeGroup: Column<Environment> = {
Header: 'Edge Groups',
accessor: (row) => row.EdgeGroupName,
Cell: ({ row }: CellProps<Environment>) => row.original.EdgeGroupName,
id: 'edgeGroupName',
Filter: DefaultFilter,
canHide: true,
};

View File

@@ -1,21 +1,13 @@
import { Column } from 'react-table';
import { CellProps, Column } from 'react-table';
import { Environment } from '@/portainer/environments/types';
import { DefaultFilter } from '@/portainer/components/datatables/components/Filter';
import { useRowContext } from './RowContext';
export const group: Column<Environment> = {
Header: 'Group',
accessor: (row) => row.GroupId,
Cell: GroupCell,
accessor: (row) => row.GroupName,
Cell: ({ row }: CellProps<Environment>) => row.original.GroupName,
id: 'groupName',
Filter: DefaultFilter,
canHide: true,
};
function GroupCell() {
const { groupName } = useRowContext();
return groupName;
}

View File

@@ -2,9 +2,10 @@ import { useMemo } from 'react';
import { name } from './name';
import { heartbeat } from './heartbeat';
import { edgeGroup } from './edgeGroup';
import { group } from './group';
import { actions } from './actions';
export function useColumns() {
return useMemo(() => [name, heartbeat, group, actions], []);
return useMemo(() => [name, heartbeat, edgeGroup, group, actions], []);
}

View File

@@ -2,7 +2,7 @@ import { getEndpoints } from 'Portainer/environments/environment.service';
angular.module('portainer.edge').controller('EdgeDevicesViewController', EdgeDevicesViewController);
/* @ngInject */
export function EdgeDevicesViewController($q, $async, EndpointService, GroupService, SettingsService, ModalService, Notifications) {
export function EdgeDevicesViewController($q, $async, EndpointService, EdgeGroupService, GroupService, SettingsService, ModalService, Notifications) {
var ctrl = this;
ctrl.edgeDevices = [];
@@ -10,13 +10,34 @@ export function EdgeDevicesViewController($q, $async, EndpointService, GroupServ
this.getEnvironments = function () {
return $async(async () => {
try {
const [endpointsResponse, groups] = await Promise.all([
getEndpoints(0, 100, {
edgeDeviceFilter: 'trusted',
}),
const [endpointsResponse, groups, edgeGroups] = await Promise.all([
getEndpoints(0, 100, { edgeDeviceFilter: 'trusted' }),
GroupService.groups(),
EdgeGroupService.groups(),
]);
ctrl.groups = groups;
// Update GroupName and EdgeGroupName for each endpoint
let groupNameMap = new Map();
groups.forEach(function (group) {
groupNameMap[group.Id] = group.Name;
});
let endpointEdgeGroupMap = new Map();
endpointsResponse.value.forEach(function (endpoint) {
endpoint.GroupName = groupNameMap[endpoint.GroupId] ? groupNameMap[endpoint.GroupId] : groupNameMap[1];
endpoint.EdgeGroupName = 'Unassigned';
endpointEdgeGroupMap[endpoint.Id] = [];
});
edgeGroups.forEach(function (edgeGroup) {
edgeGroup.Endpoints.forEach(function (endpointId) {
if (endpointEdgeGroupMap[Number(endpointId)]) {
endpointEdgeGroupMap[Number(endpointId)].push(edgeGroup.Name);
}
});
});
endpointsResponse.value.forEach(function (endpoint) {
if (endpointEdgeGroupMap[endpoint.Id].length > 0) {
endpoint.EdgeGroupName = endpointEdgeGroupMap[endpoint.Id].join(', ');
}
});
ctrl.edgeDevices = endpointsResponse.value;
} catch (err) {
Notifications.error('Failure', err, 'Unable to retrieve edge devices');

View File

@@ -4,7 +4,7 @@ import { Menu, MenuButton, MenuPopover } from '@reach/menu-button';
import { ColumnInstance } from 'react-table';
export function DefaultFilter({
column: { filterValue, setFilter, preFilteredRows, id },
column: { filterValue, setFilter, preFilteredRows, id, Header },
}: {
column: ColumnInstance;
}) {
@@ -22,6 +22,7 @@ export function DefaultFilter({
options={options}
filterKey={id}
value={filterValue}
header={String(Header)}
onChange={setFilter}
/>
);
@@ -31,6 +32,7 @@ interface MultipleSelectionFilterProps {
options: string[];
value: string[];
filterKey: string;
header: string;
onChange: (value: string[]) => void;
}
@@ -38,6 +40,7 @@ function MultipleSelectionFilter({
options,
value = [],
filterKey,
header,
onChange,
}: MultipleSelectionFilterProps) {
const enabled = value.length > 0;
@@ -59,7 +62,7 @@ function MultipleSelectionFilter({
</MenuButton>
<MenuPopover className="dropdown-menu">
<div className="tableMenu">
<div className="menuHeader">Filter by state</div>
<div className="menuHeader">Filter by {header}</div>
<div className="menuContent">
{options.map((option, index) => (
<div className="md-checkbox" key={index}>

View File

@@ -59,8 +59,10 @@ export type Environment = {
Type: EnvironmentType;
TagIds: TagId[];
GroupId: EnvironmentGroupId;
GroupName: string;
EdgeID?: string;
EdgeCheckinInterval?: number;
EdgeGroupName?: string;
QueryDate?: number;
LastCheckInDate?: number;
Name: string;

View File

@@ -61,6 +61,7 @@ function mockEnvironment(type: EnvironmentType): Environment {
Id: 1,
Name: 'environment',
GroupId: 1,
GroupName: 'Unassigned',
Snapshots: [],
Status: EnvironmentStatus.Up,
TagIds: [],

View File

@@ -15,6 +15,7 @@ test('loads component', async () => {
const env: Environment = {
TagIds: [],
GroupId: 1,
GroupName: 'Unassigned',
Type: 1,
Name: 'environment',
Status: 1,
@@ -36,6 +37,7 @@ test('shows group name', async () => {
const env: Environment = {
TagIds: [],
GroupId: groupId,
GroupName: 'Unassigned',
Type: 1,
Name: 'environment',
Status: 1,