Skip to content

Commit

Permalink
fix: misc fixes
Browse files Browse the repository at this point in the history
Signed-off-by: Mason Hu <[email protected]>
  • Loading branch information
MasWho committed Feb 21, 2025
1 parent 1135690 commit c6e0d52
Show file tree
Hide file tree
Showing 28 changed files with 143 additions and 100 deletions.
4 changes: 2 additions & 2 deletions src/api/auth-groups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import type { LxdApiResponse } from "types/apiResponse";
import type { LxdGroup } from "types/permissions";
import { withEntitlementsQuery } from "util/entitlements/api";

export const groupEntitlements = ["can_edit", "can_delete"];
export const groupEntitlements = ["can_delete", "can_edit"];

export const fetchGroups = (
isFineGrained: boolean | null,
): Promise<LxdGroup[]> => {
const entitlements = `&${withEntitlementsQuery(isFineGrained, groupEntitlements)}`;
const entitlements = withEntitlementsQuery(isFineGrained, groupEntitlements);
return new Promise((resolve, reject) => {
fetch(`/1.0/auth/groups?recursion=1${entitlements}`)
.then(handleResponse)
Expand Down
12 changes: 9 additions & 3 deletions src/api/auth-identities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import type { LxdApiResponse } from "types/apiResponse";
import type { LxdIdentity, TlsIdentityTokenDetail } from "types/permissions";
import { withEntitlementsQuery } from "util/entitlements/api";

export const identitiesEntitlements = ["can_edit", "can_delete"];
export const identitiesEntitlements = ["can_delete", "can_edit"];

export const fetchIdentities = (
isFineGrained: boolean | null,
): Promise<LxdIdentity[]> => {
const entitlements = `&${withEntitlementsQuery(isFineGrained, identitiesEntitlements)}`;
const entitlements = withEntitlementsQuery(
isFineGrained,
identitiesEntitlements,
);
return new Promise((resolve, reject) => {
fetch(`/1.0/auth/identities?recursion=1${entitlements}`)
.then(handleResponse)
Expand All @@ -31,7 +34,10 @@ export const fetchIdentity = (
authMethod: string,
isFineGrained: boolean | null,
): Promise<LxdIdentity> => {
const entitlements = `&${withEntitlementsQuery(isFineGrained, identitiesEntitlements)}`;
const entitlements = withEntitlementsQuery(
isFineGrained,
identitiesEntitlements,
);
return new Promise((resolve, reject) => {
fetch(`/1.0/auth/identities/${authMethod}/${id}?recursion=1${entitlements}`)
.then(handleResponse)
Expand Down
7 changes: 5 additions & 2 deletions src/api/auth-idp-groups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import type { LxdApiResponse } from "types/apiResponse";
import type { IdpGroup } from "types/permissions";
import { withEntitlementsQuery } from "util/entitlements/api";

const idpGroupEntitlements = ["can_edit", "can_delete"];
const idpGroupEntitlements = ["can_delete", "can_edit"];

export const fetchIdpGroups = (
isFineGrained: boolean | null,
): Promise<IdpGroup[]> => {
const entitlements = `&${withEntitlementsQuery(isFineGrained, idpGroupEntitlements)}`;
const entitlements = withEntitlementsQuery(
isFineGrained,
idpGroupEntitlements,
);
return new Promise((resolve, reject) => {
fetch(`/1.0/auth/identity-provider-groups?recursion=1${entitlements}`)
.then(handleResponse)
Expand Down
8 changes: 4 additions & 4 deletions src/api/networks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export const fetchNetworks = (
target?: string,
): Promise<LxdNetwork[]> => {
const targetParam = target ? `&target=${target}` : "";
const entitlements = `&${withEntitlementsQuery(
const entitlements = withEntitlementsQuery(
isFineGrained,
networkEntitlements,
)}`;
);
return new Promise((resolve, reject) => {
fetch(
`/1.0/networks?project=${project}&recursion=1${targetParam}${entitlements}`,
Expand Down Expand Up @@ -81,10 +81,10 @@ export const fetchNetwork = (
target?: string,
): Promise<LxdNetwork> => {
const targetParam = target ? `&target=${target}` : "";
const entitlements = `&${withEntitlementsQuery(
const entitlements = withEntitlementsQuery(
isFineGrained,
networkEntitlements,
)}`;
);
return new Promise((resolve, reject) => {
fetch(
`/1.0/networks/${name}?project=${project}${targetParam}${entitlements}`,
Expand Down
18 changes: 9 additions & 9 deletions src/components/SelectableMainTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ interface SelectableMainTableProps {
parentName: string;
selectedNames: string[];
setSelectedNames: (val: string[], isUnselectAll?: boolean) => void;
processingNames: string[];
disabledNames: string[];
rows: MainTableRow[];
indeterminateNames?: string[];
disableSelect?: boolean;
onToggleRow?: (rowName: string) => void;
hideContextualMenu?: boolean;
defaultSortKey?: string;
disableHeaderCheckbox?: boolean;
disableSelectAll?: boolean;
}

type Props = SelectableMainTableProps & MainTableProps;
Expand All @@ -37,15 +37,15 @@ const SelectableMainTable: FC<Props> = ({
parentName,
selectedNames,
setSelectedNames,
processingNames,
disabledNames,
rows,
headers,
indeterminateNames = [],
disableSelect = false,
onToggleRow,
hideContextualMenu,
defaultSortKey,
disableHeaderCheckbox,
disableSelectAll,
...props
}: Props) => {
const [currentSelectedIndex, setCurrentSelectedIndex] = useState<number>();
Expand Down Expand Up @@ -93,7 +93,7 @@ const SelectableMainTable: FC<Props> = ({
checked={isAllSelected}
indeterminate={isSomeSelected && !isAllSelected}
onChange={isSomeSelected ? selectNone : selectPage}
disabled={disableSelect || disableHeaderCheckbox}
disabled={disableSelect || disableSelectAll}
/>
{!hideContextualMenu && (
<ContextualMenu
Expand Down Expand Up @@ -130,11 +130,11 @@ const SelectableMainTable: FC<Props> = ({
];

const selectedNamesLookup = new Set(selectedNames);
const processingNamesLookup = new Set(processingNames);
const disabledNamesLookup = new Set(disabledNames);
const indeterminateNamesLookup = new Set(indeterminateNames);
const rowsWithCheckbox = rows.map((row, rowIndex) => {
const isRowSelected = selectedNamesLookup.has(row.name ?? "");
const isRowProcessing = processingNamesLookup.has(row.name ?? "");
const isRowDisabled = disabledNamesLookup.has(row.name ?? "");
const isRowIndeterminate = indeterminateNamesLookup.has(row.name ?? "");

const toggleRow = (event: PointerEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -185,7 +185,7 @@ const SelectableMainTable: FC<Props> = ({
labelClassName="u-no-margin--bottom"
checked={isRowSelected}
onChange={toggleRow}
disabled={isRowProcessing || !row.name || disableSelect}
disabled={isRowDisabled || !row.name || disableSelect}
indeterminate={isRowIndeterminate && !isRowSelected}
/>
),
Expand All @@ -197,7 +197,7 @@ const SelectableMainTable: FC<Props> = ({

const className = classnames(row.className, {
"selected-row": isRowSelected,
"processing-row": isRowProcessing,
"disabled-row": isRowDisabled,
});

const key = row.key ?? row.name;
Expand Down
2 changes: 1 addition & 1 deletion src/context/useIdentities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const useIdentity = (
): UseQueryResult<LxdIdentity> => {
const { isFineGrained } = useAuth();
return useQuery({
queryKey: [queryKeys.identities, id],
queryKey: [queryKeys.identities, authMethod, id],
queryFn: () => fetchIdentity(id, authMethod, isFineGrained),
enabled: (enabled ?? true) && isFineGrained !== null,
});
Expand Down
2 changes: 1 addition & 1 deletion src/pages/cluster/ClusterGroupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ const ClusterGroupForm: FC<Props> = ({ group }) => {
setSelectedNames={(newMembers: string[]) =>
void formik.setFieldValue("members", newMembers)
}
processingNames={[]}
disabledNames={[]}
/>
</Col>
</Row>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/images/ImageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ const ImageList: FC = () => {
itemName="image"
parentName="project"
filteredNames={filteredImages.map((item) => item.fingerprint)}
processingNames={processingNames}
disabledNames={processingNames}
rows={[]}
disableSelect={!deletableImages.length}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/instances/InstanceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ const InstanceList: FC = () => {
parentName="project"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
disabledNames={processingNames}
filteredNames={filteredInstances.map(
(instance) => instance.name,
)}
Expand All @@ -716,7 +716,7 @@ const InstanceList: FC = () => {
parentName="project"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
disabledNames={processingNames}
filteredNames={filteredInstances.map(
(instance) => instance.name,
)}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/instances/InstanceSnapshots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ const InstanceSnapshots = (props: Props) => {
parentName="instance"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
disabledNames={processingNames}
filteredNames={filteredSnapshots.map(
(snapshot) => snapshot.name,
)}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/permissions/PermissionGroups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ const PermissionGroups: FC = () => {
parentName=""
selectedNames={selectedGroupNames}
setSelectedNames={setSelectedGroupNames}
processingNames={[]}
disabledNames={[]}
filteredNames={filteredGroups.map((item) => item.name)}
disableSelect={!!panelParams.panel}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/permissions/PermissionIdentities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ const PermissionIdentities: FC = () => {
parentName=""
selectedNames={selectedIdentityIds}
setSelectedNames={setSelectedIdentityIds}
processingNames={[]}
disabledNames={[]}
filteredNames={fineGrainedIdentities.map(
(identity) => identity.id,
)}
Expand Down
12 changes: 6 additions & 6 deletions src/pages/permissions/PermissionIdpGroups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const PermissionIdpGroups: FC = () => {
const { data: settings } = useSettings();
const hasCustomClaim = settings?.config?.["oidc.groups.claim"];
const { canCreateIdpGroups } = useServerEntitlements();
const { canEditGroup } = useIdpGroupEntitlements();
const { canEditIdpGroup } = useIdpGroupEntitlements();

if (error) {
notify.failure("Loading provider groups failed", error);
Expand Down Expand Up @@ -94,7 +94,7 @@ const PermissionIdpGroups: FC = () => {
title: idpGroup.name,
},
{
content: canEditGroup(idpGroup) ? (
content: canEditIdpGroup(idpGroup) ? (
<Button
appearance="link"
dense
Expand Down Expand Up @@ -125,11 +125,11 @@ const PermissionIdpGroups: FC = () => {
type="button"
aria-label="Edit IDP group details"
title={
canEditGroup(idpGroup)
canEditIdpGroup(idpGroup)
? "Edit details"
: "You do not have permission to edit this IDP group"
: "You do not have permission to modify this IDP group"
}
disabled={!canEditGroup(idpGroup)}
disabled={!canEditIdpGroup(idpGroup)}
>
<Icon name="edit" />
</Button>,
Expand Down Expand Up @@ -232,7 +232,7 @@ const PermissionIdpGroups: FC = () => {
parentName=""
selectedNames={selectedGroupNames}
setSelectedNames={setSelectedGroupNames}
processingNames={[]}
disabledNames={[]}
filteredNames={filteredGroups.map((item) => item.name)}
disableSelect={!!panelParams.panel}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/permissions/actions/BulkDeleteIdentitiesBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const BulkDeleteIdentitiesBtn: FC<Props & ButtonProps> = ({
))}
</ul>
You do not have permission to delete the following{" "}
{pluralize("identity", deletableIdentities.length)}:
{pluralize("identity", restrictedIdentities.length)}:
<ul>
{restrictedIdentities.map((identity) => (
<li key={identity.name}>{identity.name}</li>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/permissions/actions/BulkDeleteIdpGroupsBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ interface Props {

const BulkDeleteIdpGroupsBtn: FC<Props> = ({ idpGroups, className }) => {
const [confirming, setConfirming] = useState(false);
const { canDeleteGroup } = useIdpGroupEntitlements();
const deletableGroups = idpGroups.filter(canDeleteGroup);
const { canEditIdpGroup } = useIdpGroupEntitlements();
const deletableGroups = idpGroups.filter(canEditIdpGroup);

const handleConfirmDelete = () => {
setConfirming(true);
Expand Down
51 changes: 36 additions & 15 deletions src/pages/permissions/actions/DeleteGroupModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import type { LxdGroup } from "types/permissions";
import { useGroupEntitlements } from "util/entitlements/groups";
import { pluralize } from "util/instanceBulkActions";
import { queryKeys } from "util/queryKeys";
import LoggedInUserNotification from "../panels/LoggedInUserNotification";
import { useSettings } from "context/useSettings";

interface Props {
groups: LxdGroup[];
Expand All @@ -29,15 +31,26 @@ const DeleteGroupModal: FC<Props> = ({ groups, close }) => {
const [submitting, setSubmitting] = useState(false);
const confirmText = "confirm-delete-group";
const { canDeleteGroup } = useGroupEntitlements();
const { data: settings } = useSettings();
const loggedInIdentityID = settings?.auth_user_name ?? "";

const restrictedGroups: LxdGroup[] = [];
const deletableGroups: LxdGroup[] = [];
let hasGroupsForLoggedInUser = false;
groups.forEach((group) => {
if (canDeleteGroup(group)) {
deletableGroups.push(group);
} else {
restrictedGroups.push(group);
}

if (group.identities?.oidc?.includes(loggedInIdentityID)) {
hasGroupsForLoggedInUser = true;
}

if (group.identities?.tls?.includes(loggedInIdentityID)) {
hasGroupsForLoggedInUser = true;
}
});

const hasOneGroup = deletableGroups.length === 1;
Expand Down Expand Up @@ -104,22 +117,30 @@ const DeleteGroupModal: FC<Props> = ({ groups, close }) => {
</strong>
?
</p>
{restrictedGroups.length && (
<Notification
severity="caution"
title="Restricted permissions"
titleElement="h2"
>
<p className="u-no-margin--bottom">
You do not have permission to delete the following groups:
</p>
<ul className="u-no-margin--bottom">
{restrictedGroups.map((group) => (
<li key={group.name}>{group.name}</li>
))}
</ul>
</Notification>
{hasGroupsForLoggedInUser && (
<div className="u-sv1">
<LoggedInUserNotification isVisible={hasGroupsForLoggedInUser} />
</div>
)}
{restrictedGroups.length ? (
<div className="u-sv1">
<Notification
severity="information"
title="Restricted permissions"
titleElement="h2"
className="u-no-margin--bottom"
>
<p className="u-no-margin--bottom">
You do not have permission to delete the following groups:
</p>
<ul className="u-no-margin--bottom">
{restrictedGroups.map((group) => (
<li key={group.name}>{group.name}</li>
))}
</ul>
</Notification>
</div>
) : null}
<p>
This action cannot be undone and may result in users losing access to
LXD, including the possibility that all users lose admin access.
Expand Down
Loading

0 comments on commit c6e0d52

Please sign in to comment.