mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Improve TypeScript definitions for app context (#4603)
* Refactor AppContext with improved TypeScript definitions for actions * Sort teams on setAvailableTeams action * Add case insensitive sort by name to team table on team settings page
This commit is contained in:
parent
3e07f4a626
commit
a693d82c11
4 changed files with 99 additions and 49 deletions
|
|
@ -1,10 +1,49 @@
|
|||
import React, { createContext, useReducer, ReactNode } from "react";
|
||||
|
||||
import { IUser } from "interfaces/user";
|
||||
import { IConfig } from "interfaces/config";
|
||||
import { ITeamSummary } from "interfaces/team";
|
||||
import permissions from "utilities/permissions";
|
||||
import { IEnrollSecret } from "interfaces/enroll_secret";
|
||||
import { ITeamSummary } from "interfaces/team";
|
||||
import { IUser } from "interfaces/user";
|
||||
import permissions from "utilities/permissions";
|
||||
import sort from "utilities/sort";
|
||||
|
||||
enum ACTIONS {
|
||||
SET_AVAILABLE_TEAMS = "SET_AVAILABLE_TEAMS",
|
||||
SET_CURRENT_USER = "SET_CURRENT_USER",
|
||||
SET_CURRENT_TEAM = "SET_CURRENT_TEAM",
|
||||
SET_CONFIG = "SET_CONFIG",
|
||||
SET_ENROLL_SECRET = "SET_ENROLL_SECRET",
|
||||
}
|
||||
|
||||
interface ISetAvailableTeamsAction {
|
||||
type: ACTIONS.SET_AVAILABLE_TEAMS;
|
||||
availableTeams: ITeamSummary[];
|
||||
}
|
||||
|
||||
interface ISetConfigAction {
|
||||
type: ACTIONS.SET_CONFIG;
|
||||
config: IConfig;
|
||||
}
|
||||
|
||||
interface ISetCurrentTeamAction {
|
||||
type: ACTIONS.SET_CURRENT_TEAM;
|
||||
currentTeam: ITeamSummary | undefined;
|
||||
}
|
||||
interface ISetCurrentUserAction {
|
||||
type: ACTIONS.SET_CURRENT_USER;
|
||||
currentUser: IUser;
|
||||
}
|
||||
interface ISetEnrollSecretAction {
|
||||
type: ACTIONS.SET_ENROLL_SECRET;
|
||||
enrollSecret: IEnrollSecret[];
|
||||
}
|
||||
|
||||
type IAction =
|
||||
| ISetAvailableTeamsAction
|
||||
| ISetConfigAction
|
||||
| ISetCurrentTeamAction
|
||||
| ISetCurrentUserAction
|
||||
| ISetEnrollSecretAction;
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
|
|
@ -70,21 +109,17 @@ const initialState = {
|
|||
setEnrollSecret: () => null,
|
||||
};
|
||||
|
||||
const actions = {
|
||||
SET_AVAILABLE_TEAMS: "SET_AVAILABLE_TEAMS",
|
||||
SET_CURRENT_USER: "SET_CURRENT_USER",
|
||||
SET_CURRENT_TEAM: "SET_CURRENT_TEAM",
|
||||
SET_CONFIG: "SET_CONFIG",
|
||||
SET_ENROLL_SECRET: "SET_ENROLL_SECRET",
|
||||
};
|
||||
|
||||
const detectPreview = () => {
|
||||
return window.location.origin === "http://localhost:1337";
|
||||
};
|
||||
|
||||
// helper function - this is run every
|
||||
// time currentUser, currentTeam, config, or teamId is changed
|
||||
const setPermissions = (user: IUser, config: IConfig, teamId = 0) => {
|
||||
const setPermissions = (
|
||||
user: IUser | null,
|
||||
config: IConfig | null,
|
||||
teamId = 0
|
||||
) => {
|
||||
if (!user || !config) {
|
||||
return {};
|
||||
}
|
||||
|
|
@ -113,44 +148,52 @@ const setPermissions = (user: IUser, config: IConfig, teamId = 0) => {
|
|||
};
|
||||
};
|
||||
|
||||
const reducer = (state: any, action: any) => {
|
||||
const reducer = (state: InitialStateType, action: IAction) => {
|
||||
switch (action.type) {
|
||||
case actions.SET_AVAILABLE_TEAMS:
|
||||
case ACTIONS.SET_AVAILABLE_TEAMS: {
|
||||
const { availableTeams } = action;
|
||||
|
||||
return {
|
||||
...state,
|
||||
availableTeams: action.availableTeams,
|
||||
};
|
||||
case actions.SET_CURRENT_USER:
|
||||
return {
|
||||
...state,
|
||||
currentUser: action.currentUser,
|
||||
...setPermissions(
|
||||
action.currentUser,
|
||||
state.config,
|
||||
state.currentTeam?.id
|
||||
availableTeams: availableTeams.sort(
|
||||
(a: ITeamSummary, b: ITeamSummary) =>
|
||||
sort.caseInsensitiveAsc(a.name, b.name)
|
||||
),
|
||||
};
|
||||
case actions.SET_CURRENT_TEAM:
|
||||
}
|
||||
case ACTIONS.SET_CURRENT_USER: {
|
||||
const { currentUser } = action;
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentTeam: action.currentTeam,
|
||||
...setPermissions(
|
||||
state.currentUser,
|
||||
state.config,
|
||||
action.currentTeam?.id
|
||||
),
|
||||
currentUser,
|
||||
...setPermissions(currentUser, state.config, state.currentTeam?.id),
|
||||
};
|
||||
case actions.SET_CONFIG:
|
||||
}
|
||||
case ACTIONS.SET_CURRENT_TEAM: {
|
||||
const { currentTeam } = action;
|
||||
return {
|
||||
...state,
|
||||
config: action.config,
|
||||
...setPermissions(state.currentUser, action.config),
|
||||
currentTeam,
|
||||
...setPermissions(state.currentUser, state.config, currentTeam?.id),
|
||||
};
|
||||
case actions.SET_ENROLL_SECRET:
|
||||
}
|
||||
case ACTIONS.SET_CONFIG: {
|
||||
const { config } = action;
|
||||
|
||||
return {
|
||||
...state,
|
||||
enrollSecret: action.enrollSecret,
|
||||
config,
|
||||
...setPermissions(state.currentUser, config),
|
||||
};
|
||||
}
|
||||
case ACTIONS.SET_ENROLL_SECRET: {
|
||||
const { enrollSecret } = action;
|
||||
return {
|
||||
...state,
|
||||
enrollSecret,
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
@ -184,19 +227,19 @@ const AppProvider = ({ children }: Props): JSX.Element => {
|
|||
isOnlyObserver: state.isOnlyObserver,
|
||||
isNoAccess: state.isNoAccess,
|
||||
setAvailableTeams: (availableTeams: ITeamSummary[]) => {
|
||||
dispatch({ type: actions.SET_AVAILABLE_TEAMS, availableTeams });
|
||||
dispatch({ type: ACTIONS.SET_AVAILABLE_TEAMS, availableTeams });
|
||||
},
|
||||
setCurrentUser: (currentUser: IUser) => {
|
||||
dispatch({ type: actions.SET_CURRENT_USER, currentUser });
|
||||
dispatch({ type: ACTIONS.SET_CURRENT_USER, currentUser });
|
||||
},
|
||||
setCurrentTeam: (currentTeam: ITeamSummary | undefined) => {
|
||||
dispatch({ type: actions.SET_CURRENT_TEAM, currentTeam });
|
||||
dispatch({ type: ACTIONS.SET_CURRENT_TEAM, currentTeam });
|
||||
},
|
||||
setConfig: (config: IConfig) => {
|
||||
dispatch({ type: actions.SET_CONFIG, config });
|
||||
dispatch({ type: ACTIONS.SET_CONFIG, config });
|
||||
},
|
||||
setEnrollSecret: (enrollSecret: IEnrollSecret[]) => {
|
||||
dispatch({ type: actions.SET_ENROLL_SECRET, enrollSecret });
|
||||
dispatch({ type: ACTIONS.SET_ENROLL_SECRET, enrollSecret });
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export interface ITeamSummary {
|
|||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
host_count: number;
|
||||
host_count?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -32,8 +32,8 @@ export interface ITeam extends ITeamSummary {
|
|||
count?: number;
|
||||
created_at?: string;
|
||||
agent_options?: any;
|
||||
user_count: number;
|
||||
host_count: number;
|
||||
user_count?: number;
|
||||
host_count?: number;
|
||||
secrets?: IEnrollSecret[];
|
||||
role?: string; // role value is included when the team is in the context of a user
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,8 +382,11 @@ const TeamDetailsWrapper = ({
|
|||
}
|
||||
|
||||
const hostCount = currentTeam.host_count;
|
||||
const hostsTotalDisplay =
|
||||
hostCount >= 2 ? `${hostCount} hosts` : `${hostCount} host`;
|
||||
let hostsTotalDisplay: string | undefined;
|
||||
if (hostCount !== undefined) {
|
||||
hostsTotalDisplay =
|
||||
hostCount === 1 ? `${hostCount} host` : `${hostCount} hosts`;
|
||||
}
|
||||
|
||||
const adminTeams = isGlobalAdmin
|
||||
? availableTeams
|
||||
|
|
@ -417,9 +420,11 @@ const TeamDetailsWrapper = ({
|
|||
onClose={handleTeamMenuClose}
|
||||
/>
|
||||
)}
|
||||
<span className={`${baseClass}__host-count`}>
|
||||
{hostsTotalDisplay}
|
||||
</span>
|
||||
{!!hostsTotalDisplay && (
|
||||
<span className={`${baseClass}__host-count`}>
|
||||
{hostsTotalDisplay}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${baseClass}__team-actions`}>
|
||||
<Button onClick={toggleAddHostsModal}>Add hosts</Button>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ interface IDataColumn {
|
|||
| ((props: IDropdownCellProps) => JSX.Element);
|
||||
disableHidden?: boolean;
|
||||
disableSortBy?: boolean;
|
||||
sortType?: string;
|
||||
}
|
||||
|
||||
interface ITeamTableData extends ITeam {
|
||||
|
|
@ -56,6 +57,7 @@ const generateTableHeaders = (
|
|||
title: "Name",
|
||||
Header: "Name",
|
||||
disableSortBy: true,
|
||||
sortType: "caseInsensitive",
|
||||
accessor: "name",
|
||||
Cell: (cellProps: ICellProps) => (
|
||||
<LinkCell
|
||||
|
|
|
|||
Loading…
Reference in a new issue