mirror of
https://github.com/quay/quay.git
synced 2026-01-26 06:21:37 +03:00
[redhat-3.16] chore: migrate SidebarState and AlertState from Recoil to React Context (#4481)
* chore: migrate SidebarState and AlertState from Recoil to React Context Migrates UI state management from Recoil atoms to a centralized UIContext using pure React Context API. This is part of the broader effort to simplify state management and reduce dependencies. Changes: - Create UIContext with sidebar and alert state management - Migrate SidebarState: isSidebarOpen with localStorage persistence - Migrate AlertState: alerts array with add/remove/clear operations - Move AlertVariant enum and AlertDetails interface to UIContext - Remove UseAlerts hook (now redundant - consumers use useUI directly) - Update Alerts component to use removeAlert from context - Update QuayHeader and QuaySidebar to use useUI hook - Update 128 files to import types/hooks from UIContext - Delete AlertState.ts, SidebarState.ts, and UseAlerts.ts Benefits: - Zero runtime logic changes for consumers - Centralized UI state in single context - Reduced Recoil surface area (2 fewer atoms) - Simpler architecture (removed unnecessary hook wrapper) - Future-proof for additional UI state (theme, plugin mode) - Pure React with no external dependencies for UI state Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Brady Pratt <bpratt@redhat.com> * fix(ui): add toast alerts for create organization, repository, and application token operations Adds success and failure toast alerts to create operations that previously only showed inline error messages. This provides consistent feedback across all CRUD operations and ensures users receive confirmation after modals close. Also fixes browser compatibility issue in UIContext by replacing crypto.randomUUID() with Math.random().toString(36) for alert key generation, maintaining compatibility with the original UseAlerts implementation. Changes: - Add toast alerts to CreateOrganizationModal for create org operations - Add toast alerts to CreateRepoModalTemplate for create repo operations - Add toast alerts to CreateApplicationTokenModal for token creation - Fix UIContext to use Math.random() instead of crypto.randomUUID() - Maintain existing inline error displays for immediate validation feedback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> * fix(ui): clear alerts on route navigation to prevent stale alerts from persisting Adds route-level alert cleanup to StandaloneMain to clear all alerts when navigating between routes. This prevents old alerts from accumulating and reappearing when users return to previously visited pages. Previously, alerts (especially failure alerts which don't auto-dismiss) would persist in UIContext state and re-render when navigating back to a page. Now alerts are automatically cleared whenever the route pathname changes. Changes: - Add useLocation hook to track route changes - Add clearAllAlerts from UIContext - Add useEffect to clear alerts on location.pathname change - Ensures fresh alert state for each route 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Brady Pratt <bpratt@redhat.com> * chore: address coderabbit feedback - fix early return, initialize the useEffect first - call props.toggleModal() - fix entityType shadowing - improve grammar in alerts for ToggleUserStatusModal Signed-off-by: Brady Pratt <bpratt@redhat.com> * fix(ui): wait for collaborator deletion before closing modal The CollaboratorsDeleteModal was closing immediately after clicking delete, causing it to unmount before the async deletion completed. This prevented the success alert from appearing because the useEffect hook that adds the alert never fired after component unmount. Fixed by moving the toggleModal() call from the delete button's onClick handler into the success and error useEffect hooks, ensuring the modal stays open until the mutation completes and the alert is displayed. Co-authored-by: Claude <noreply@anthropic.com> --------- Signed-off-by: Brady Pratt <bpratt@redhat.com> Co-authored-by: Brady Pratt <bpratt@redhat.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
f1ff178e3b
commit
32602f5c32
@@ -1,19 +0,0 @@
|
||||
import {ReactNode} from 'react';
|
||||
import {atom} from 'recoil';
|
||||
|
||||
export enum AlertVariant {
|
||||
Success = 'success',
|
||||
Failure = 'danger',
|
||||
}
|
||||
|
||||
export interface AlertDetails {
|
||||
variant: AlertVariant;
|
||||
title: string;
|
||||
key?: string;
|
||||
message?: string | ReactNode;
|
||||
}
|
||||
|
||||
export const alertState = atom<AlertDetails[]>({
|
||||
key: 'alertState',
|
||||
default: [],
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
import {atom} from 'recoil';
|
||||
|
||||
export const SidebarState = atom({
|
||||
key: 'sidebarState',
|
||||
default: {
|
||||
isOpen: true,
|
||||
},
|
||||
});
|
||||
@@ -15,13 +15,12 @@ import logo from 'src/assets/quay.svg';
|
||||
import rh_logo from 'src/assets/RH_QuayIO2.svg';
|
||||
import {HeaderToolbar} from './HeaderToolbar';
|
||||
import {Link} from 'react-router-dom';
|
||||
import {SidebarState} from 'src/atoms/SidebarState';
|
||||
import {useSetRecoilState} from 'recoil';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import './QuayHeader.css';
|
||||
|
||||
export function QuayHeader({toggleDrawer}: {toggleDrawer: () => void}) {
|
||||
const setSidebarState = useSetRecoilState(SidebarState);
|
||||
const {toggleSidebar} = useUI();
|
||||
const quayConfig = useQuayConfig();
|
||||
let logoUrl = logo;
|
||||
if (quayConfig && quayConfig.config?.BRANDING?.logo) {
|
||||
@@ -33,17 +32,13 @@ export function QuayHeader({toggleDrawer}: {toggleDrawer: () => void}) {
|
||||
logoUrl = rh_logo;
|
||||
}
|
||||
|
||||
const toggleSidebarVisibility = () => {
|
||||
setSidebarState((oldState) => ({isOpen: !oldState.isOpen}));
|
||||
};
|
||||
|
||||
return (
|
||||
<Masthead>
|
||||
<MastheadToggle>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label="Global navigation"
|
||||
onClick={toggleSidebarVisibility}
|
||||
onClick={toggleSidebar}
|
||||
>
|
||||
<BarsIcon />
|
||||
</Button>
|
||||
|
||||
@@ -1,192 +1,281 @@
|
||||
import {Label as ImageLabel} from 'src/resources/TagResource';
|
||||
import {
|
||||
Label as ImageLabel,
|
||||
} from 'src/resources/TagResource';
|
||||
import { Button, DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Label, Skeleton} from '@patternfly/react-core';
|
||||
Button,
|
||||
DescriptionList,
|
||||
DescriptionListDescription,
|
||||
DescriptionListGroup,
|
||||
DescriptionListTerm,
|
||||
Label,
|
||||
Skeleton,
|
||||
} from '@patternfly/react-core';
|
||||
import './Labels.css';
|
||||
import { useLabels } from 'src/hooks/UseTagLabels';
|
||||
import { useEffect, useState } from 'react';
|
||||
import {useLabels} from 'src/hooks/UseTagLabels';
|
||||
import {useEffect, useState} from 'react';
|
||||
import Conditional from '../empty/Conditional';
|
||||
import { useAlerts } from 'src/hooks/UseAlerts';
|
||||
import { AlertVariant } from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import EditableLabel from './EditableLabel';
|
||||
|
||||
export default function EditableLabels(props: EditableLabelsProps) {
|
||||
const {
|
||||
labels,
|
||||
setLabels,
|
||||
initialLabels,
|
||||
loading,
|
||||
error,
|
||||
createLabels,
|
||||
successCreatingLabels,
|
||||
errorCreatingLabels,
|
||||
errorCreatingLabelsDetails,
|
||||
loadingCreateLabels,
|
||||
deleteLabels,
|
||||
successDeletingLabels,
|
||||
errorDeletingLabels,
|
||||
errorDeletingLabelsDetails,
|
||||
loadingDeleteLabels,
|
||||
} = useLabels(props.org, props.repo, props.digest);
|
||||
const [newLabel, setNewLabel] = useState<string>('');
|
||||
const [invalidNewLabel, setInvalidNewLabel] = useState<string>(null);
|
||||
const { addAlert } = useAlerts();
|
||||
const loadingLabelChanges: boolean = loadingCreateLabels || loadingDeleteLabels;
|
||||
const readonlyLabels = labels.filter((label: ImageLabel) => label.source_type !== 'api');
|
||||
const mutableLabels = labels.filter((label: ImageLabel) => label.source_type === 'api');
|
||||
const {
|
||||
labels,
|
||||
setLabels,
|
||||
initialLabels,
|
||||
loading,
|
||||
error,
|
||||
createLabels,
|
||||
successCreatingLabels,
|
||||
errorCreatingLabels,
|
||||
errorCreatingLabelsDetails,
|
||||
loadingCreateLabels,
|
||||
deleteLabels,
|
||||
successDeletingLabels,
|
||||
errorDeletingLabels,
|
||||
errorDeletingLabelsDetails,
|
||||
loadingDeleteLabels,
|
||||
} = useLabels(props.org, props.repo, props.digest);
|
||||
const [newLabel, setNewLabel] = useState<string>('');
|
||||
const [invalidNewLabel, setInvalidNewLabel] = useState<string>(null);
|
||||
const {addAlert} = useUI();
|
||||
const loadingLabelChanges: boolean =
|
||||
loadingCreateLabels || loadingDeleteLabels;
|
||||
const readonlyLabels = labels.filter(
|
||||
(label: ImageLabel) => label.source_type !== 'api',
|
||||
);
|
||||
const mutableLabels = labels.filter(
|
||||
(label: ImageLabel) => label.source_type === 'api',
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return <>Unable to get labels</>;
|
||||
useEffect(() => {
|
||||
if (successCreatingLabels) {
|
||||
addAlert({
|
||||
variant: AlertVariant.Success,
|
||||
title: `Created labels successfully`,
|
||||
});
|
||||
}
|
||||
if (loading) {
|
||||
return <Skeleton width="100%" />;
|
||||
if (errorCreatingLabels) {
|
||||
const errorCreatingLabelsMessage = (
|
||||
<>
|
||||
{Array.from(errorCreatingLabelsDetails.getErrors()).map(
|
||||
([label, error]) => (
|
||||
<p key={label}>
|
||||
Could not create label {label}: {error.error.message}
|
||||
</p>
|
||||
),
|
||||
)}
|
||||
</>
|
||||
);
|
||||
addAlert({
|
||||
variant: AlertVariant.Failure,
|
||||
title: `Could not create labels`,
|
||||
message: errorCreatingLabelsMessage,
|
||||
});
|
||||
}
|
||||
if (successDeletingLabels) {
|
||||
addAlert({
|
||||
variant: AlertVariant.Success,
|
||||
title: `Deleted labels successfully`,
|
||||
});
|
||||
}
|
||||
if (errorDeletingLabels) {
|
||||
const errorDeletingLabelsMessage = (
|
||||
<>
|
||||
{Array.from(errorDeletingLabelsDetails.getErrors()).map(
|
||||
([label, error]) => (
|
||||
<p key={label}>
|
||||
Could not delete label {label}: {error.error.message}
|
||||
</p>
|
||||
),
|
||||
)}
|
||||
</>
|
||||
);
|
||||
addAlert({
|
||||
variant: AlertVariant.Failure,
|
||||
title: `Could not delete labels`,
|
||||
message: errorDeletingLabelsMessage,
|
||||
});
|
||||
}
|
||||
if (
|
||||
(successCreatingLabels ||
|
||||
errorCreatingLabels ||
|
||||
successDeletingLabels ||
|
||||
errorDeletingLabels) &&
|
||||
!loadingLabelChanges
|
||||
) {
|
||||
props.onComplete();
|
||||
}
|
||||
}, [
|
||||
successCreatingLabels,
|
||||
errorCreatingLabels,
|
||||
successDeletingLabels,
|
||||
errorDeletingLabels,
|
||||
loadingLabelChanges,
|
||||
addAlert,
|
||||
props.onComplete,
|
||||
errorCreatingLabelsDetails,
|
||||
errorDeletingLabelsDetails,
|
||||
]);
|
||||
|
||||
if (error) {
|
||||
return <>Unable to get labels</>;
|
||||
}
|
||||
if (loading) {
|
||||
return <Skeleton width="100%" />;
|
||||
}
|
||||
|
||||
const onEditComplete = (newLabel: string) => {
|
||||
if (newLabel === '') {
|
||||
setNewLabel('');
|
||||
setInvalidNewLabel(null);
|
||||
return;
|
||||
}
|
||||
let invalidMessage: string = null;
|
||||
let key: string = null;
|
||||
let value: string = null;
|
||||
const keyValue: string[] = newLabel.split('=');
|
||||
if (keyValue.length === 2) {
|
||||
key = keyValue[0].trim();
|
||||
value = keyValue[1].trim();
|
||||
if (key === '' || !/^[0-9A-Za-z/\-_.]+$/.test(key)) {
|
||||
invalidMessage =
|
||||
'Invalid label format, key must match ^[0-9A-Za-z/\\-_.]+=.+$';
|
||||
}
|
||||
if (value === '' || !/^[0-9A-Za-z/\-_.]+$/.test(value)) {
|
||||
invalidMessage =
|
||||
'Invalid label format, value must match ^[0-9A-Za-z/\\-_.]+=.+$';
|
||||
}
|
||||
} else {
|
||||
invalidMessage = 'Invalid label format, must be key value separated by =';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (successCreatingLabels) {
|
||||
addAlert({ variant: AlertVariant.Success, title: `Created labels successfully` });
|
||||
}
|
||||
if (errorCreatingLabels) {
|
||||
let errorCreatingLabelsMessage = (<>{Array.from(errorCreatingLabelsDetails.getErrors()).map(([label, error]) => (<p key={label}>Could not create label {label}: {error.error.message}</p>))}</>)
|
||||
addAlert({ variant: AlertVariant.Failure, title: `Could not create labels`, message: errorCreatingLabelsMessage });
|
||||
}
|
||||
if (successDeletingLabels) {
|
||||
addAlert({ variant: AlertVariant.Success, title: `Deleted labels successfully` });
|
||||
}
|
||||
if (errorDeletingLabels) {
|
||||
let errorDeletingLabelsMessage = (<>{Array.from(errorDeletingLabelsDetails.getErrors()).map(([label, error]) => (<p key={label}>Could not delete label {label}: {error.error.message}</p>))}</>)
|
||||
addAlert({ variant: AlertVariant.Failure, title: `Could not delete labels`, message: errorDeletingLabelsMessage });
|
||||
}
|
||||
if ((successCreatingLabels || errorCreatingLabels || successDeletingLabels || errorDeletingLabels) && !loadingLabelChanges) {
|
||||
props.onComplete();
|
||||
}
|
||||
}, [successCreatingLabels, errorCreatingLabels, successDeletingLabels, errorDeletingLabels]);
|
||||
|
||||
const onEditComplete = (newLabel: string) => {
|
||||
if(newLabel === '') {
|
||||
setNewLabel('');
|
||||
setInvalidNewLabel(null);
|
||||
return;
|
||||
}
|
||||
let invalidMessage: string = null;
|
||||
let key: string = null;
|
||||
let value: string = null;
|
||||
const keyValue: string[] = newLabel.split('=');
|
||||
if (keyValue.length === 2) {
|
||||
key = keyValue[0].trim();
|
||||
value = keyValue[1].trim();
|
||||
if (key === "" || !/^[0-9A-Za-z/\-_.]+$/.test(key)) {
|
||||
invalidMessage = 'Invalid label format, key must match ^[0-9A-Za-z/\\-_.]+=.+$'
|
||||
}
|
||||
if (value === "" || !/^[0-9A-Za-z/\-_.]+$/.test(value)) {
|
||||
invalidMessage = 'Invalid label format, value must match ^[0-9A-Za-z/\\-_.]+=.+$';
|
||||
}
|
||||
} else {
|
||||
invalidMessage = 'Invalid label format, must be key value separated by ='
|
||||
}
|
||||
|
||||
if (labels.some(l => l.key === key && l.value === value)) {
|
||||
invalidMessage = 'Key value already exists'
|
||||
}
|
||||
|
||||
if (invalidMessage === null) {
|
||||
setNewLabel('');
|
||||
const newLabelObj: ImageLabel = { id: `${key}=${value}`, key, value, source_type: 'api', media_type: null };
|
||||
setLabels(prev => [...prev, newLabelObj])
|
||||
setInvalidNewLabel(null);
|
||||
} else {
|
||||
setInvalidNewLabel(invalidMessage);
|
||||
setNewLabel(newLabel);
|
||||
}
|
||||
if (labels.some((l) => l.key === key && l.value === value)) {
|
||||
invalidMessage = 'Key value already exists';
|
||||
}
|
||||
|
||||
const removeLabel = (label: ImageLabel) => {
|
||||
setLabels(prev => prev.filter(l => l.id !== label.id))
|
||||
if (invalidMessage === null) {
|
||||
setNewLabel('');
|
||||
const newLabelObj: ImageLabel = {
|
||||
id: `${key}=${value}`,
|
||||
key,
|
||||
value,
|
||||
source_type: 'api',
|
||||
media_type: null,
|
||||
};
|
||||
setLabels((prev) => [...prev, newLabelObj]);
|
||||
setInvalidNewLabel(null);
|
||||
} else {
|
||||
setInvalidNewLabel(invalidMessage);
|
||||
setNewLabel(newLabel);
|
||||
}
|
||||
};
|
||||
|
||||
const saveLabels = () => {
|
||||
const [addedLabels, deletedLabels] = filterLabels(initialLabels, labels);
|
||||
if (addedLabels.length > 0) {
|
||||
createLabels(addedLabels);
|
||||
}
|
||||
if (deletedLabels.length > 0) {
|
||||
deleteLabels(deletedLabels);
|
||||
}
|
||||
const removeLabel = (label: ImageLabel) => {
|
||||
setLabels((prev) => prev.filter((l) => l.id !== label.id));
|
||||
};
|
||||
|
||||
const saveLabels = () => {
|
||||
const [addedLabels, deletedLabels] = filterLabels(initialLabels, labels);
|
||||
if (addedLabels.length > 0) {
|
||||
createLabels(addedLabels);
|
||||
}
|
||||
|
||||
const isSaveButtonDisabled = () => {
|
||||
const [addedLabels, deletedLabels] = filterLabels(initialLabels, labels);
|
||||
return (addedLabels.length === 0 && deletedLabels.length === 0);
|
||||
if (deletedLabels.length > 0) {
|
||||
deleteLabels(deletedLabels);
|
||||
}
|
||||
};
|
||||
|
||||
const filterLabels = (initialLabels: ImageLabel[], updatedLabels: ImageLabel[]) => {
|
||||
const addedLabels: ImageLabel[] = updatedLabels.filter(updatedLabel => !initialLabels.some(intitialLabel => intitialLabel.key===updatedLabel.key && intitialLabel.value===updatedLabel.value));
|
||||
const deletedLabels: ImageLabel[] = initialLabels.filter(intitialLabel => !updatedLabels.some(updatedLabel => intitialLabel.key===updatedLabel.key && intitialLabel.value===updatedLabel.value));
|
||||
return [addedLabels, deletedLabels];
|
||||
}
|
||||
const isSaveButtonDisabled = () => {
|
||||
const [addedLabels, deletedLabels] = filterLabels(initialLabels, labels);
|
||||
return addedLabels.length === 0 && deletedLabels.length === 0;
|
||||
};
|
||||
|
||||
return (<>
|
||||
<DescriptionList>
|
||||
<DescriptionListGroup>
|
||||
<DescriptionListTerm>Read-only labels</DescriptionListTerm>
|
||||
<DescriptionListDescription id='readonly-labels'>
|
||||
{readonlyLabels?.length === 0 ? "No labels found" : readonlyLabels.map((label: ImageLabel) => (
|
||||
<>
|
||||
<Label key={label.key} className="label">
|
||||
<span className="label-content">
|
||||
{label.key} = {label.value}
|
||||
</span>
|
||||
</Label>{' '}
|
||||
</>
|
||||
))}
|
||||
</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
<DescriptionListGroup>
|
||||
<DescriptionListTerm>Mutable labels</DescriptionListTerm>
|
||||
<DescriptionListDescription id='mutable-labels'>
|
||||
{mutableLabels?.map((label: ImageLabel) => (
|
||||
<Label key={label.id} className="label" onClose={() => { removeLabel(label) }}>
|
||||
<span className="label-content">
|
||||
{label.key}={label.value}
|
||||
</span>
|
||||
</Label>
|
||||
))}
|
||||
<EditableLabel
|
||||
value={newLabel}
|
||||
setValue={setNewLabel}
|
||||
onEditComplete={onEditComplete}
|
||||
invalid={invalidNewLabel !== null}
|
||||
/>
|
||||
<Conditional if={invalidNewLabel !== null}>
|
||||
<div style={{ color: 'red' }}>
|
||||
{invalidNewLabel}
|
||||
</div>
|
||||
</Conditional>
|
||||
</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
</DescriptionList>
|
||||
<br />
|
||||
<Button
|
||||
key="cancel"
|
||||
variant="primary"
|
||||
onClick={props.onComplete}
|
||||
>
|
||||
Cancel
|
||||
</Button>{' '}
|
||||
<Button
|
||||
key="modal-action-button"
|
||||
variant="primary"
|
||||
onClick={saveLabels}
|
||||
isDisabled={isSaveButtonDisabled()}
|
||||
>
|
||||
Save Labels
|
||||
</Button>
|
||||
</>)
|
||||
const filterLabels = (
|
||||
initialLabels: ImageLabel[],
|
||||
updatedLabels: ImageLabel[],
|
||||
) => {
|
||||
const addedLabels: ImageLabel[] = updatedLabels.filter(
|
||||
(updatedLabel) =>
|
||||
!initialLabels.some(
|
||||
(intitialLabel) =>
|
||||
intitialLabel.key === updatedLabel.key &&
|
||||
intitialLabel.value === updatedLabel.value,
|
||||
),
|
||||
);
|
||||
const deletedLabels: ImageLabel[] = initialLabels.filter(
|
||||
(intitialLabel) =>
|
||||
!updatedLabels.some(
|
||||
(updatedLabel) =>
|
||||
intitialLabel.key === updatedLabel.key &&
|
||||
intitialLabel.value === updatedLabel.value,
|
||||
),
|
||||
);
|
||||
return [addedLabels, deletedLabels];
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DescriptionList>
|
||||
<DescriptionListGroup>
|
||||
<DescriptionListTerm>Read-only labels</DescriptionListTerm>
|
||||
<DescriptionListDescription id="readonly-labels">
|
||||
{readonlyLabels?.length === 0
|
||||
? 'No labels found'
|
||||
: readonlyLabels.map((label: ImageLabel) => (
|
||||
<>
|
||||
<Label key={label.key} className="label">
|
||||
<span className="label-content">
|
||||
{label.key} = {label.value}
|
||||
</span>
|
||||
</Label>{' '}
|
||||
</>
|
||||
))}
|
||||
</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
<DescriptionListGroup>
|
||||
<DescriptionListTerm>Mutable labels</DescriptionListTerm>
|
||||
<DescriptionListDescription id="mutable-labels">
|
||||
{mutableLabels?.map((label: ImageLabel) => (
|
||||
<Label
|
||||
key={label.id}
|
||||
className="label"
|
||||
onClose={() => {
|
||||
removeLabel(label);
|
||||
}}
|
||||
>
|
||||
<span className="label-content">
|
||||
{label.key}={label.value}
|
||||
</span>
|
||||
</Label>
|
||||
))}
|
||||
<EditableLabel
|
||||
value={newLabel}
|
||||
setValue={setNewLabel}
|
||||
onEditComplete={onEditComplete}
|
||||
invalid={invalidNewLabel !== null}
|
||||
/>
|
||||
<Conditional if={invalidNewLabel !== null}>
|
||||
<div style={{color: 'red'}}>{invalidNewLabel}</div>
|
||||
</Conditional>
|
||||
</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
</DescriptionList>
|
||||
<br />
|
||||
<Button key="cancel" variant="primary" onClick={props.onComplete}>
|
||||
Cancel
|
||||
</Button>{' '}
|
||||
<Button
|
||||
key="modal-action-button"
|
||||
variant="primary"
|
||||
onClick={saveLabels}
|
||||
isDisabled={isSaveButtonDisabled()}
|
||||
>
|
||||
Save Labels
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface EditableLabelsProps {
|
||||
org: string;
|
||||
repo: string;
|
||||
digest: string;
|
||||
onComplete?: () => void;
|
||||
org: string;
|
||||
repo: string;
|
||||
digest: string;
|
||||
onComplete?: () => void;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
import {useCurrentUser} from 'src/hooks/UseCurrentUser';
|
||||
import {useConvertAccount} from 'src/hooks/UseConvertAccount';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import Avatar from 'src/components/Avatar';
|
||||
|
||||
interface ChangeAccountTypeModalProps {
|
||||
@@ -33,7 +32,7 @@ export default function ChangeAccountTypeModal({
|
||||
}: ChangeAccountTypeModalProps) {
|
||||
const {user} = useCurrentUser();
|
||||
const quayConfig = useQuayConfig();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const canConvert = user?.organizations?.length === 0;
|
||||
const [convertStep, setConvertStep] = useState(canConvert ? 1 : 0); // Start at step 1 if can convert
|
||||
const [accountType, setAccountType] = useState('organization'); // Default to organization
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
import {useCreateApplicationToken} from 'src/hooks/UseApplicationTokens';
|
||||
import {IApplicationToken} from 'src/resources/UserResource';
|
||||
import CredentialsModal from './CredentialsModal';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
|
||||
interface CreateApplicationTokenModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -27,14 +29,24 @@ export default function CreateApplicationTokenModal({
|
||||
null,
|
||||
);
|
||||
const [error, setError] = useState('');
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const createTokenMutator = useCreateApplicationToken({
|
||||
onSuccess: (data) => {
|
||||
setCreatedToken(data.token);
|
||||
setError('');
|
||||
addAlert({
|
||||
variant: AlertVariant.Success,
|
||||
title: `Successfully created application token "${title}"`,
|
||||
});
|
||||
},
|
||||
onError: (err) => {
|
||||
setError(err.message);
|
||||
addAlert({
|
||||
variant: AlertVariant.Failure,
|
||||
title: 'Failed to create application token',
|
||||
message: err.message,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ import {addDisplayError} from 'src/resources/ErrorHandling';
|
||||
import {IOrganization} from 'src/resources/OrganizationResource';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import {useCreateRepository} from 'src/hooks/UseCreateRepository';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
|
||||
enum visibilityType {
|
||||
PUBLIC = 'PUBLIC',
|
||||
@@ -39,6 +41,7 @@ export default function CreateRepositoryModalTemplate(
|
||||
}
|
||||
const [err, setErr] = useState<string>();
|
||||
const quayConfig = useQuayConfig();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const [currentOrganization, setCurrentOrganization] = useState({
|
||||
// For org scoped view, the name is set current org and for Repository list view,
|
||||
@@ -53,10 +56,23 @@ export default function CreateRepositoryModalTemplate(
|
||||
|
||||
const {createRepository} = useCreateRepository({
|
||||
onSuccess: () => {
|
||||
addAlert({
|
||||
variant: AlertVariant.Success,
|
||||
title: `Successfully created repository ${currentOrganization.name}/${newRepository.name}`,
|
||||
});
|
||||
props.handleModalToggle();
|
||||
},
|
||||
onError: (error) => {
|
||||
setErr(addDisplayError('Unable to create repository', error));
|
||||
const errorMessage = addDisplayError(
|
||||
'Unable to create repository',
|
||||
error,
|
||||
);
|
||||
setErr(errorMessage);
|
||||
addAlert({
|
||||
variant: AlertVariant.Failure,
|
||||
title: 'Unable to create repository',
|
||||
message: errorMessage,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import {
|
||||
SelectOption,
|
||||
} from '@patternfly/react-core';
|
||||
import React from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useManageOrgSubscriptions} from 'src/hooks/UseMarketplaceSubscriptions';
|
||||
|
||||
interface OrgSubscriptionModalProps {
|
||||
@@ -29,7 +28,7 @@ export default function OrgSubscriptionModal(props: OrgSubscriptionModalProps) {
|
||||
const [selectedSku, setSelectedSku] = React.useState('');
|
||||
const [menuIsOpen, setMenuIsOpen] = React.useState(false);
|
||||
const [bindingQuantity, setBindingQuantity] = React.useState(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const onSelect = (
|
||||
_event: React.MouseEvent<Element, MouseEvent> | undefined,
|
||||
value: string | number | undefined,
|
||||
|
||||
@@ -15,15 +15,14 @@ import {PlusIcon, TrashIcon} from '@patternfly/react-icons';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import DisplayModal from './robotAccountWizard/DisplayModal';
|
||||
import {useRobotFederation} from 'src/hooks/useRobotFederation';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
function RobotFederationForm(props: RobotFederationFormProps) {
|
||||
const [federationFormState, setFederationFormState] = useState<
|
||||
RobotFederationFormEntryProps[]
|
||||
>([]);
|
||||
|
||||
const alerts = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {robotFederationConfig, loading, fetchError, setRobotFederationConfig} =
|
||||
useRobotFederation({
|
||||
@@ -33,13 +32,13 @@ function RobotFederationForm(props: RobotFederationFormProps) {
|
||||
setFederationFormState(
|
||||
result.map((config) => ({...config, isExpanded: false})),
|
||||
);
|
||||
alerts.addAlert({
|
||||
addAlert({
|
||||
title: 'Robot federation config saved',
|
||||
variant: AlertVariant.Success,
|
||||
});
|
||||
},
|
||||
onError: (e) => {
|
||||
alerts.addAlert({
|
||||
addAlert({
|
||||
title: e.error_message || 'Error saving federation config',
|
||||
variant: AlertVariant.Failure,
|
||||
});
|
||||
|
||||
@@ -12,14 +12,13 @@ import NameAndDescription from 'src/components/modals/robotAccountWizard/NameAnd
|
||||
import {addDisplayError} from 'src/resources/ErrorHandling';
|
||||
import TeamView from './TeamView';
|
||||
import {useCreateTeam} from 'src/hooks/UseTeams';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
export default function AddToTeam(props: AddToTeamProps) {
|
||||
const [newTeamName, setNewTeamName] = useState('');
|
||||
const [newTeamDescription, setNewTeamDescription] = useState('');
|
||||
const [err, setErr] = useState<string>();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {createNewTeamHook} = useCreateTeam(props.orgName, {
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -7,14 +7,13 @@ import {
|
||||
PageSidebarBody,
|
||||
} from '@patternfly/react-core';
|
||||
import {Link, useLocation} from 'react-router-dom';
|
||||
import {SidebarState} from 'src/atoms/SidebarState';
|
||||
import {NavigationPath} from 'src/routes/NavigationPath';
|
||||
import OrganizationsList from 'src/routes/OrganizationsList/OrganizationsList';
|
||||
import RepositoriesList from 'src/routes/RepositoriesList/RepositoriesList';
|
||||
import {useRecoilValue} from 'recoil';
|
||||
import OverviewList from 'src/routes/OverviewList/OverviewList';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import {useCurrentUser} from 'src/hooks/UseCurrentUser';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import ServiceKeys from 'src/routes/Superuser/ServiceKeys/ServiceKeys';
|
||||
import ChangeLog from 'src/routes/Superuser/ChangeLog/ChangeLog';
|
||||
import UsageLogs from 'src/routes/Superuser/UsageLogs/UsageLogs';
|
||||
@@ -31,7 +30,7 @@ interface SideNavProps {
|
||||
|
||||
export function QuaySidebar() {
|
||||
const location = useLocation();
|
||||
const sidebarState = useRecoilValue(SidebarState);
|
||||
const {isSidebarOpen} = useUI();
|
||||
const quayConfig = useQuayConfig();
|
||||
const {isSuperUser} = useCurrentUser();
|
||||
|
||||
@@ -178,7 +177,7 @@ export function QuaySidebar() {
|
||||
</Nav>
|
||||
);
|
||||
|
||||
if (sidebarState.isOpen) {
|
||||
if (isSidebarOpen) {
|
||||
return (
|
||||
<PageSidebar className="page-sidebar" theme="dark">
|
||||
<PageSidebarBody>{Navigation}</PageSidebarBody>
|
||||
|
||||
108
web/src/contexts/UIContext.tsx
Normal file
108
web/src/contexts/UIContext.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useMemo,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
|
||||
export enum AlertVariant {
|
||||
Success = 'success',
|
||||
Failure = 'danger',
|
||||
}
|
||||
|
||||
export interface AlertDetails {
|
||||
variant: AlertVariant;
|
||||
title: string;
|
||||
key?: string;
|
||||
message?: string | ReactNode;
|
||||
}
|
||||
|
||||
interface UIContextType {
|
||||
// Sidebar state
|
||||
isSidebarOpen: boolean;
|
||||
toggleSidebar: () => void;
|
||||
|
||||
// Alert state
|
||||
alerts: AlertDetails[];
|
||||
addAlert: (alert: AlertDetails) => void;
|
||||
removeAlert: (key: string) => void;
|
||||
clearAllAlerts: () => void;
|
||||
}
|
||||
|
||||
const UIContext = createContext<UIContextType | undefined>(undefined);
|
||||
|
||||
interface UIProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function UIProvider({children}: UIProviderProps) {
|
||||
// Sidebar state with localStorage persistence
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState<boolean>(() => {
|
||||
const stored = localStorage.getItem('quay-sidebar-open');
|
||||
return stored !== null ? stored === 'true' : true; // Default to open
|
||||
});
|
||||
|
||||
// Alert state
|
||||
const [alerts, setAlerts] = useState<AlertDetails[]>([]);
|
||||
|
||||
// Persist sidebar state to localStorage
|
||||
useEffect(() => {
|
||||
localStorage.setItem('quay-sidebar-open', String(isSidebarOpen));
|
||||
}, [isSidebarOpen]);
|
||||
|
||||
const toggleSidebar = useCallback(() => {
|
||||
setIsSidebarOpen((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const addAlert = useCallback((alert: AlertDetails) => {
|
||||
const alertWithKey = {
|
||||
...alert,
|
||||
key: alert.key ?? Math.random().toString(36).substring(7),
|
||||
};
|
||||
setAlerts((prev) => [...prev, alertWithKey]);
|
||||
}, []);
|
||||
|
||||
const removeAlert = useCallback((key: string) => {
|
||||
setAlerts((prev) => prev.filter((a) => a.key !== key));
|
||||
}, []);
|
||||
|
||||
const clearAllAlerts = useCallback(() => {
|
||||
setAlerts([]);
|
||||
}, []);
|
||||
|
||||
const value: UIContextType = useMemo(
|
||||
() => ({
|
||||
isSidebarOpen,
|
||||
toggleSidebar,
|
||||
alerts,
|
||||
addAlert,
|
||||
removeAlert,
|
||||
clearAllAlerts,
|
||||
}),
|
||||
[
|
||||
isSidebarOpen,
|
||||
toggleSidebar,
|
||||
alerts,
|
||||
addAlert,
|
||||
removeAlert,
|
||||
clearAllAlerts,
|
||||
],
|
||||
);
|
||||
|
||||
return <UIContext.Provider value={value}>{children}</UIContext.Provider>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook to access UI context
|
||||
* @returns UI context with sidebar state and future alert/theme state
|
||||
*/
|
||||
export function useUI(): UIContextType {
|
||||
const context = useContext(UIContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useUI must be used within a UIProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import {useRecoilState} from 'recoil';
|
||||
import {AlertDetails, alertState} from 'src/atoms/AlertState';
|
||||
|
||||
export function useAlerts() {
|
||||
const [alerts, setAlerts] = useRecoilState(alertState);
|
||||
const addAlert = (alert: AlertDetails) => {
|
||||
if (alert.key == null) {
|
||||
alert.key = Math.random().toString(36).substring(7);
|
||||
}
|
||||
setAlerts([...alerts, alert]);
|
||||
};
|
||||
|
||||
const clearAllAlerts = () => {
|
||||
setAlerts([]);
|
||||
};
|
||||
|
||||
return {
|
||||
addAlert,
|
||||
clearAllAlerts,
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useForm} from 'react-hook-form';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
import {
|
||||
createServiceKey,
|
||||
CreateServiceKeyRequest,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {useState} from 'react';
|
||||
import {useForm} from 'react-hook-form';
|
||||
import {MirroringFormData} from 'src/routes/RepositoryDetails/Mirroring/types';
|
||||
import {Entity, EntityKind} from 'src/resources/UserResource';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
|
||||
// Default form values
|
||||
const defaultFormValues: MirroringFormData = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useForm} from 'react-hook-form';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
import {
|
||||
OAuthApplicationFormData,
|
||||
defaultOAuthFormValues,
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
import {BulkOperationError, ResourceError} from 'src/resources/ErrorHandling';
|
||||
import {useCurrentUser} from './UseCurrentUser';
|
||||
import {IAvatar} from 'src/resources/OrganizationResource';
|
||||
import {useAlerts} from './UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useUI, AlertVariant} from 'src/contexts/UIContext';
|
||||
import {addRepoPermissionToTeam} from 'src/resources/DefaultPermissionResource';
|
||||
|
||||
interface createNewTeamForNamespaceParams {
|
||||
@@ -29,7 +28,7 @@ interface createNewTeamForNamespaceParams {
|
||||
|
||||
export function useCreateTeam(orgName, {onSuccess, onError}) {
|
||||
const queryClient = useQueryClient();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
data: responseData,
|
||||
|
||||
@@ -3,6 +3,7 @@ import {createRoot} from 'react-dom/client';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import {RecoilRoot} from 'recoil';
|
||||
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
|
||||
import {UIProvider} from './contexts/UIContext';
|
||||
|
||||
// Load App after patternfly so custom CSS that overrides patternfly doesn't require !important
|
||||
import App from './App';
|
||||
@@ -22,9 +23,11 @@ const root = createRoot(container);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<RecoilRoot>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
<UIProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
</UIProvider>
|
||||
</RecoilRoot>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
||||
@@ -3,11 +3,10 @@ import {
|
||||
AlertActionCloseButton,
|
||||
AlertGroup,
|
||||
} from '@patternfly/react-core';
|
||||
import {useRecoilState} from 'recoil';
|
||||
import {AlertVariant, alertState} from 'src/atoms/AlertState';
|
||||
import {useUI, AlertVariant} from 'src/contexts/UIContext';
|
||||
|
||||
export default function Alerts() {
|
||||
const [alerts, setAlerts] = useRecoilState(alertState);
|
||||
const {alerts, removeAlert} = useUI();
|
||||
return (
|
||||
<AlertGroup isToast isLiveRegion>
|
||||
{alerts.map((alert) => (
|
||||
@@ -19,7 +18,7 @@ export default function Alerts() {
|
||||
actionClose={
|
||||
<AlertActionCloseButton
|
||||
onClose={() => {
|
||||
setAlerts((prev) => prev.filter((a) => a.key !== alert.key));
|
||||
removeAlert(alert.key);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -38,8 +38,7 @@ import {
|
||||
TriggeredBuildDescription,
|
||||
} from 'src/routes/RepositoryDetails/Builds/BuildHistory';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {getErrorMessageFromUnknown} from 'src/resources/ErrorHandling';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {
|
||||
@@ -59,7 +58,7 @@ import {RepositoryBuildPhase} from 'src/resources/BuildResource';
|
||||
export default function Build() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [poll, setPoll] = useState<boolean>(true);
|
||||
const [showTimestamps, setShowTimestamps] = useState<boolean>(false);
|
||||
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
||||
|
||||
@@ -16,6 +16,8 @@ import {useState} from 'react';
|
||||
import FormError from 'src/components/errors/FormError';
|
||||
import {addDisplayError} from 'src/resources/ErrorHandling';
|
||||
import {useOrganizations} from 'src/hooks/UseOrganizations';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
|
||||
interface Validation {
|
||||
message: string;
|
||||
@@ -40,6 +42,7 @@ export const CreateOrganizationModal = (
|
||||
const [err, setErr] = useState<string>();
|
||||
|
||||
const {createOrganization} = useOrganizations();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const handleNameInputChange = (value: string) => {
|
||||
const regex = /^([a-z0-9]+(?:[._-][a-z0-9]+)*)$/;
|
||||
@@ -77,9 +80,22 @@ export const CreateOrganizationModal = (
|
||||
const createOrganizationHandler = async () => {
|
||||
try {
|
||||
await createOrganization(organizationName, organizationEmail);
|
||||
addAlert({
|
||||
variant: AlertVariant.Success,
|
||||
title: `Successfully created organization ${organizationName}`,
|
||||
});
|
||||
props.handleModalToggle();
|
||||
} catch (err) {
|
||||
setErr(addDisplayError('Unable to create organization', err));
|
||||
const errorMessage = addDisplayError(
|
||||
'Unable to create organization',
|
||||
err,
|
||||
);
|
||||
setErr(errorMessage);
|
||||
addAlert({
|
||||
variant: AlertVariant.Failure,
|
||||
title: 'Unable to create organization',
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ import {CubeIcon} from '@patternfly/react-icons';
|
||||
import {useAuthorizedApplications} from 'src/hooks/UseAuthorizedApplications';
|
||||
import GenerateTokenAuthorizationModal from 'src/components/modals/GenerateTokenAuthorizationModal';
|
||||
import TokenDisplayModal from 'src/components/modals/TokenDisplayModal';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {GlobalAuthState} from 'src/resources/AuthResource';
|
||||
import {useQueryClient} from '@tanstack/react-query';
|
||||
|
||||
@@ -33,7 +32,7 @@ export default function AuthorizedApplicationsList() {
|
||||
isRevoking,
|
||||
isDeletingAssigned,
|
||||
} = useAuthorizedApplications();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [isAuthModalOpen, setIsAuthModalOpen] = useState(false);
|
||||
|
||||
@@ -11,15 +11,14 @@ import {
|
||||
useUpdateDefaultPermission,
|
||||
} from 'src/hooks/UseDefaultPermissions';
|
||||
import {repoPermissions} from './DefaultPermissionsList';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {titleCase} from 'src/libs/utils';
|
||||
|
||||
export default function DefaultPermissionsDropDown(
|
||||
props: DefaultPermissionsDropdownProps,
|
||||
) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
setDefaultPermission,
|
||||
|
||||
@@ -25,8 +25,7 @@ import {BulkDeleteModalTemplate} from 'src/components/modals/BulkDeleteModalTemp
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import {BulkOperationError, addDisplayError} from 'src/resources/ErrorHandling';
|
||||
import RequestError from 'src/components/errors/RequestError';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import ErrorModal from 'src/components/errors/ErrorModal';
|
||||
import {usePaginatedSortableTable} from '../../../../../hooks/usePaginatedSortableTable';
|
||||
|
||||
@@ -80,7 +79,7 @@ export default function DefaultPermissionsList(
|
||||
>([]);
|
||||
const [bulkDeleteModalIsOpen, setBulkDeleteModalIsOpen] = useState(false);
|
||||
const [err, setError] = useState<string[]>();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const onSelectPermission = (
|
||||
permission: IDefaultPermission,
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
MenuToggleElement,
|
||||
} from '@patternfly/react-core';
|
||||
import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {
|
||||
IDefaultPermission,
|
||||
useDeleteDefaultPermission,
|
||||
@@ -18,7 +17,7 @@ export default function DeleteDefaultPermissionKebab(
|
||||
props: DefaultPermissionsDropdownProps,
|
||||
) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
removeDefaultPermission,
|
||||
|
||||
@@ -34,8 +34,7 @@ import Conditional from 'src/components/empty/Conditional';
|
||||
import {useFetchTeams} from 'src/hooks/UseTeams';
|
||||
import {repoPermissions} from 'src/routes/OrganizationsList/Organization/Tabs/DefaultPermissions/DefaultPermissionsList';
|
||||
import {RepoPermissionDropdownItems} from 'src/routes/RepositoriesList/RobotAccountsList';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {validateTeamName} from 'src/libs/utils';
|
||||
|
||||
export default function CreatePermissionDrawer(
|
||||
@@ -74,7 +73,7 @@ export default function CreatePermissionDrawer(
|
||||
const {robots, isLoadingRobots} = useFetchRobotAccounts(props.orgName);
|
||||
// Get teams
|
||||
const {teams, isLoadingTeams} = useFetchTeams(props.orgName);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const permissionRadioButtons = (
|
||||
<>
|
||||
|
||||
@@ -11,8 +11,7 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
import {ExclamationCircleIcon} from '@patternfly/react-icons';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useCreateTeam} from 'src/hooks/UseTeams';
|
||||
|
||||
type validate = 'success' | 'error' | 'default';
|
||||
@@ -23,7 +22,7 @@ export const CreateTeamModal = (props: CreateTeamModalProps): JSX.Element => {
|
||||
|
||||
const [validatedName, setValidatedName] = useState<validate>('default');
|
||||
const [nameHelperText, setNameHelperText] = useState(props.nameHelperText);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const handleNameChange = (
|
||||
_event: React.FormEvent<HTMLInputElement>,
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
import {getAccountTypeForMember} from 'src/libs/utils';
|
||||
import {TrashIcon} from '@patternfly/react-icons';
|
||||
import NameAndDescription from 'src/components/modals/robotAccountWizard/NameAndDescription';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import ToggleDrawer from 'src/components/ToggleDrawer';
|
||||
|
||||
const memberAndRobotColNames = {
|
||||
@@ -30,7 +29,7 @@ export default function AddTeamMember(props: AddTeamMemberProps) {
|
||||
const [perPage, setPerPage] = useState(20);
|
||||
const [newRobotAccntName, setNewRobotAccntName] = useState('');
|
||||
const [newRobotAccntDescription, setNewRobotAccntDescription] = useState('');
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {error, robots} = useFetchRobotAccounts(props.orgName);
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ import AddTeamMember from './AddTeamMember';
|
||||
import Review from './ReviewTeam';
|
||||
import ReviewAndFinishFooter from './ReviewAndFinishFooter';
|
||||
import {useAddRepoPermissionToTeam} from 'src/hooks/UseTeams';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
|
||||
const [selectedRepoPerms, setSelectedRepoPerms] = useRecoilState(
|
||||
@@ -47,7 +46,7 @@ export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
|
||||
const [deletedTeamMembers, setDeletedTeamMembers] = useState<ITeamMember[]>(
|
||||
[],
|
||||
);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
// Fetching repos
|
||||
const {repos} = useRepositories(props.orgName);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import {Modal, ModalVariant, Button, Form} from '@patternfly/react-core';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import {FormTextInput} from 'src/components/forms/FormTextInput';
|
||||
import {useOAuthApplicationForm} from 'src/hooks/UseOAuthApplicationForm';
|
||||
import {OAuthApplicationFormData} from './types';
|
||||
@@ -8,7 +8,7 @@ import {OAuthApplicationFormData} from './types';
|
||||
export default function CreateOAuthApplicationModal(
|
||||
props: CreateOAuthApplicationModalProps,
|
||||
) {
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {control, errors, formValues, handleSubmit, isValid} =
|
||||
useOAuthApplicationForm(
|
||||
|
||||
@@ -23,8 +23,7 @@ import EntitySearch from 'src/components/EntitySearch';
|
||||
import {Entity} from 'src/resources/UserResource';
|
||||
import {GlobalAuthState} from 'src/resources/AuthResource';
|
||||
import {OAUTH_SCOPES, OAuthScope} from '../types';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface GenerateTokenTabProps {
|
||||
application: IOAuthApplication | null;
|
||||
@@ -45,7 +44,7 @@ export default function GenerateTokenTab(props: GenerateTokenTabProps) {
|
||||
const [isTokenDisplayModalOpen, setIsTokenDisplayModalOpen] = useState(false);
|
||||
const {user} = useCurrentUser();
|
||||
const quayConfig = useQuayConfig();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
// Initialize form with all scopes set to false
|
||||
const defaultValues: GenerateTokenFormData = {};
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
IOAuthApplication,
|
||||
useResetOAuthApplicationClientSecret,
|
||||
} from 'src/hooks/UseOAuthApplications';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {ConfirmationModal} from 'src/components/modals/ConfirmationModal';
|
||||
|
||||
interface OAuthInformationTabProps {
|
||||
@@ -29,7 +28,7 @@ interface OAuthInformationTabProps {
|
||||
|
||||
export default function OAuthInformationTab(props: OAuthInformationTabProps) {
|
||||
const [isResetModalOpen, setIsResetModalOpen] = useState(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {resetOAuthApplicationClientSecretMutation} =
|
||||
useResetOAuthApplicationClientSecret(
|
||||
|
||||
@@ -11,8 +11,7 @@ import {
|
||||
IOAuthApplication,
|
||||
useUpdateOAuthApplication,
|
||||
} from 'src/hooks/UseOAuthApplications';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {FormTextInput} from 'src/components/forms/FormTextInput';
|
||||
import {OAuthApplicationFormData} from '../types';
|
||||
|
||||
@@ -23,7 +22,7 @@ interface SettingsTabProps {
|
||||
}
|
||||
|
||||
export default function SettingsTab(props: SettingsTabProps) {
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
control,
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
MenuToggleElement,
|
||||
} from '@patternfly/react-core';
|
||||
import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {
|
||||
IOAuthApplication,
|
||||
useDeleteOAuthApplication,
|
||||
@@ -20,7 +19,7 @@ export default function OAuthApplicationActionsKebab(
|
||||
) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
removeOAuthApplication,
|
||||
|
||||
@@ -18,8 +18,7 @@ import ManageOAuthApplicationDrawer from './ManageOAuthApplicationDrawer';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import {BulkOperationError, addDisplayError} from 'src/resources/ErrorHandling';
|
||||
import RequestError from 'src/components/errors/RequestError';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import ErrorModal from 'src/components/errors/ErrorModal';
|
||||
import Empty from 'src/components/empty/Empty';
|
||||
import {KeyIcon} from '@patternfly/react-icons';
|
||||
@@ -44,7 +43,7 @@ export default function OAuthApplicationsList(
|
||||
IOAuthApplication[]
|
||||
>([]);
|
||||
const [error, setError] = useState<string[]>([]);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
loading,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import {Button, Spinner, Title} from '@patternfly/react-core';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import RequestError from 'src/components/errors/RequestError';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {
|
||||
useCreateNamespaceAutoPrunePolicy,
|
||||
useDeleteNamespaceAutoPrunePolicy,
|
||||
@@ -31,7 +30,7 @@ export const shorthandTimeUnits = {
|
||||
|
||||
export default function AutoPruning(props: AutoPruning) {
|
||||
const [policies, setPolicies] = useState([]);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const config = useQuayConfig();
|
||||
const {
|
||||
error,
|
||||
|
||||
@@ -19,8 +19,7 @@ import {useOrganization} from 'src/hooks/UseOrganization';
|
||||
import {useUpgradePlan} from 'src/hooks/UseUpgradePlan';
|
||||
import {AxiosError} from 'axios';
|
||||
import {useOrganizationSettings} from 'src/hooks/UseOrganizationSettings';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import Alerts from 'src/routes/Alerts';
|
||||
import MarketplaceDetails from './MarketplaceDetails';
|
||||
|
||||
@@ -31,7 +30,7 @@ type BillingInformationProps = {
|
||||
export const BillingInformation = (props: BillingInformationProps) => {
|
||||
const organizationName = props.organizationName;
|
||||
const {user} = useCurrentUser();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {
|
||||
updateUser,
|
||||
loading: userUpdateLoading,
|
||||
|
||||
@@ -17,8 +17,7 @@ import {
|
||||
import {useForm, Controller} from 'react-hook-form';
|
||||
import moment from 'moment';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useCurrentUser, useUpdateUser} from 'src/hooks/UseCurrentUser';
|
||||
import {useOrganization} from 'src/hooks/UseOrganization';
|
||||
import {useOrganizationSettings} from 'src/hooks/UseOrganizationSettings';
|
||||
@@ -65,7 +64,7 @@ export const GeneralSettings = (props: GeneralSettingsProps) => {
|
||||
const {user, loading: isUserLoading} = useCurrentUser();
|
||||
const {organization, isUserOrganization, loading} =
|
||||
useOrganization(organizationName);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {updateOrgSettings} = useOrganizationSettings({
|
||||
name: organizationName,
|
||||
|
||||
@@ -12,8 +12,7 @@ import {
|
||||
TextInput,
|
||||
} from '@patternfly/react-core';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {
|
||||
IProxyCacheConfig,
|
||||
useCreateProxyCacheConfig,
|
||||
@@ -41,7 +40,7 @@ export const ProxyCacheConfig = (props: ProxyCacheConfigProps) => {
|
||||
const [proxyCacheConfig, setProxyCacheConfig] = useState<IProxyCacheConfig>(
|
||||
defaultProxyCacheConfig,
|
||||
);
|
||||
const {addAlert, clearAllAlerts} = useAlerts();
|
||||
const {addAlert, clearAllAlerts} = useUI();
|
||||
|
||||
const {fetchedProxyCacheConfig, isLoadingProxyCacheConfig} =
|
||||
useFetchProxyCacheConfig(props.organizationName);
|
||||
|
||||
@@ -23,8 +23,7 @@ import {PlusIcon} from '@patternfly/react-icons';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {useForm, Controller} from 'react-hook-form';
|
||||
import {FormTextInput} from 'src/components/forms/FormTextInput';
|
||||
import {AlertVariant as AlertVariantState} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant as AlertVariantState, useUI} from 'src/contexts/UIContext';
|
||||
import {useCurrentUser} from 'src/hooks/UseCurrentUser';
|
||||
import {useSuperuserPermissions} from 'src/hooks/UseSuperuserPermissions';
|
||||
import {
|
||||
@@ -119,7 +118,7 @@ export const QuotaManagement = (props: QuotaManagementProps) => {
|
||||
}>({});
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
|
||||
const {addAlert, clearAllAlerts} = useAlerts();
|
||||
const {addAlert, clearAllAlerts} = useUI();
|
||||
|
||||
// Check if there's already a "Reject" limit to prevent adding duplicates
|
||||
const hasRejectLimit = limits.some((limit) => limit.type === 'Reject');
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import {Alert, Button, Modal, ModalVariant} from '@patternfly/react-core';
|
||||
import {useEffect} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useDeleteCollaborator} from 'src/hooks/UseMembers';
|
||||
import {IMembers} from 'src/resources/MembersResource';
|
||||
|
||||
export default function CollaboratorsDeleteModal(
|
||||
props: CollaboratorsDeleteModalProps,
|
||||
) {
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const deleteMsg =
|
||||
'User will be removed from all teams and repositories under this organization in which they are a member or have permissions.';
|
||||
const deleteAlert = (
|
||||
@@ -27,6 +26,7 @@ export default function CollaboratorsDeleteModal(
|
||||
variant: AlertVariant.Failure,
|
||||
title: `Error deleting collaborator`,
|
||||
});
|
||||
props.toggleModal();
|
||||
}
|
||||
}, [errorDeleteCollaborator]);
|
||||
|
||||
@@ -36,6 +36,7 @@ export default function CollaboratorsDeleteModal(
|
||||
variant: AlertVariant.Success,
|
||||
title: `Successfully deleted collaborator`,
|
||||
});
|
||||
props.toggleModal();
|
||||
}
|
||||
}, [successDeleteCollaborator]);
|
||||
|
||||
@@ -55,7 +56,6 @@ export default function CollaboratorsDeleteModal(
|
||||
removeCollaborator({
|
||||
collaborator: props.collaborator.name,
|
||||
});
|
||||
props.toggleModal;
|
||||
}}
|
||||
data-testid={`${props.collaborator.name}-del-btn`}
|
||||
>
|
||||
|
||||
@@ -11,8 +11,7 @@ import {useFetchCollaborators} from 'src/hooks/UseMembers';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {IMembers} from 'src/resources/MembersResource';
|
||||
import {TrashIcon} from '@patternfly/react-icons';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {ToolbarPagination} from 'src/components/toolbar/ToolbarPagination';
|
||||
import CollaboratorsDeleteModal from './CollaboratorsDeleteModal';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
@@ -55,7 +54,7 @@ export default function CollaboratorsViewList(
|
||||
const [selectedCollaborators, setSelectedCollaborators] = useState<
|
||||
IMembers[]
|
||||
>([]);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [collaboratorToBeDeleted, setCollaboratorToBeDeleted] =
|
||||
useState<IMembers>();
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ import {useEffect, useState} from 'react';
|
||||
import MembersViewToolbar from './MembersViewToolbar';
|
||||
import {useFetchMembers} from 'src/hooks/UseMembers';
|
||||
import {IMemberTeams, IMembers} from 'src/resources/MembersResource';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {getTeamMemberPath} from 'src/routes/NavigationPath';
|
||||
import {ToolbarPagination} from 'src/components/toolbar/ToolbarPagination';
|
||||
import {usePaginatedSortableTable} from '../../../../../../hooks/usePaginatedSortableTable';
|
||||
@@ -59,7 +58,7 @@ export default function MembersViewList(props: MembersViewListProps) {
|
||||
const [selectedMembers, setSelectedMembers] = useState<IMembers[]>([]);
|
||||
const [isPopoverOpen, setPopoverOpen] = useState(false);
|
||||
const [searchParams] = useSearchParams();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
|
||||
@@ -18,11 +18,10 @@ import {DesktopIcon} from '@patternfly/react-icons';
|
||||
import React, {useState} from 'react';
|
||||
import {Ref} from 'react';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import EntitySearch from 'src/components/EntitySearch';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import CreateRobotAccountModal from 'src/components/modals/CreateRobotAccountModal';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {
|
||||
useAddMembersToTeam,
|
||||
useFetchTeamMembersForOrg,
|
||||
@@ -50,7 +49,7 @@ export default function AddNewTeamMemberDrawer(
|
||||
const {robots, isLoadingRobots} = useFetchRobotAccounts(props.orgName);
|
||||
// Get teams
|
||||
const {teams} = useFetchTeams(props.orgName);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const creatorDefaultOptions = [
|
||||
<React.Fragment key="creator">
|
||||
|
||||
@@ -47,8 +47,7 @@ import {
|
||||
} from '@patternfly/react-icons';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import Empty from 'src/components/empty/Empty';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {
|
||||
getAccountTypeForMember,
|
||||
formatDate,
|
||||
@@ -164,7 +163,7 @@ export default function ManageMembersList(props: ManageMembersListProps) {
|
||||
const [selectedTeamMembers, setSelectedTeamMembers] = useState<ITeamMember[]>(
|
||||
[],
|
||||
);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [teamDescr, setTeamDescr] = useState<string>();
|
||||
|
||||
@@ -3,7 +3,7 @@ import {Button, Modal, ModalVariant, Spinner} from '@patternfly/react-core';
|
||||
import {useEffect, useState} from 'react';
|
||||
import Empty from 'src/components/empty/Empty';
|
||||
import {CubesIcon} from '@patternfly/react-icons';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import SetRepoPermissionsToolbar from './SetRepoPermissionsForTeamToolbar';
|
||||
import {
|
||||
ITeamRepoPerms,
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
} from 'src/hooks/UseTeams';
|
||||
import {SetRepoPermForTeamRoleDropDown} from './SetRepoPermForTeamRoleDropDown';
|
||||
import {formatDate} from 'src/libs/utils';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
|
||||
export const setRepoPermForTeamColumnNames = {
|
||||
repoName: 'Repository',
|
||||
@@ -50,7 +49,7 @@ export default function SetRepoPermissionForTeamModal(
|
||||
[],
|
||||
);
|
||||
const [isKebabOpen, setKebabOpen] = useState(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
useEffect(() => {
|
||||
if (successUpdateRepoPerm) {
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
MenuToggle,
|
||||
MenuToggleElement,
|
||||
} from '@patternfly/react-core';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useUpdateTeamDetails} from 'src/hooks/UseTeams';
|
||||
import {titleCase} from 'src/libs/utils';
|
||||
|
||||
@@ -19,7 +18,7 @@ export enum teamPermissions {
|
||||
|
||||
export function TeamsRoleDropDown(props: TeamsRoleDropDownProps) {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
updateTeamDetails,
|
||||
|
||||
@@ -22,8 +22,7 @@ import {BulkDeleteModalTemplate} from 'src/components/modals/BulkDeleteModalTemp
|
||||
import {BulkOperationError, addDisplayError} from 'src/resources/ErrorHandling';
|
||||
import ErrorModal from 'src/components/errors/ErrorModal';
|
||||
import {getTeamMemberPath} from 'src/routes/NavigationPath';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import SetRepoPermissionForTeamModal from 'src/routes/OrganizationsList/Organization/Tabs/TeamsAndMembership/TeamsView/SetRepoPermissionsModal/SetRepoPermissionForTeamModal';
|
||||
import {ToolbarPagination} from 'src/components/toolbar/ToolbarPagination';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
@@ -76,7 +75,7 @@ export default function TeamsViewList(props: TeamsViewListProps) {
|
||||
const [deleteModalIsOpen, setDeleteModalIsOpen] = useState(false);
|
||||
const [err, setIsError] = useState<string[]>();
|
||||
const [searchParams] = useSearchParams();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [isSetRepoPermModalOpen, setIsSetRepoPermModalOpen] = useState(false);
|
||||
const [repoPermForTeam, setRepoPermForTeam] = useState<string>('');
|
||||
const [isDeleteModalForRowOpen, setIsDeleteModalForRowOpen] = useState(false);
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
Alert,
|
||||
} from '@patternfly/react-core';
|
||||
import {useChangeUserEmail} from 'src/hooks/UseUserActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface ChangeEmailModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -21,7 +20,7 @@ interface ChangeEmailModalProps {
|
||||
export default function ChangeEmailModal(props: ChangeEmailModalProps) {
|
||||
const [newEmail, setNewEmail] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {changeEmail, isLoading} = useChangeUserEmail({
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
Alert,
|
||||
} from '@patternfly/react-core';
|
||||
import {useChangeUserPassword} from 'src/hooks/UseUserActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface ChangePasswordModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -21,7 +20,7 @@ interface ChangePasswordModalProps {
|
||||
export default function ChangePasswordModal(props: ChangePasswordModalProps) {
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {changePassword, isLoading} = useChangeUserPassword({
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
import {useForm} from 'react-hook-form';
|
||||
import {useCreateUser} from 'src/hooks/UseCreateUser';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface CreateUserModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -28,7 +27,7 @@ interface CreateUserFormData {
|
||||
|
||||
export function CreateUserModal(props: CreateUserModalProps) {
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {
|
||||
register,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {useState} from 'react';
|
||||
import {Modal, ModalVariant, Button, Text, Alert} from '@patternfly/react-core';
|
||||
import {useDeleteSingleOrganization} from 'src/hooks/UseOrganizationActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface DeleteOrganizationModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -14,7 +13,7 @@ export default function DeleteOrganizationModal(
|
||||
props: DeleteOrganizationModalProps,
|
||||
) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {deleteOrganization, isLoading} = useDeleteSingleOrganization({
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {useState} from 'react';
|
||||
import {Modal, ModalVariant, Button, Text, Alert} from '@patternfly/react-core';
|
||||
import {useDeleteUser} from 'src/hooks/UseUserActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface DeleteUserModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -12,7 +11,7 @@ interface DeleteUserModalProps {
|
||||
|
||||
export default function DeleteUserModal(props: DeleteUserModalProps) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {deleteUser, isLoading} = useDeleteUser({
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
Alert,
|
||||
} from '@patternfly/react-core';
|
||||
import {useRenameOrganization} from 'src/hooks/UseOrganizationActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface RenameOrganizationModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -23,7 +22,7 @@ export default function RenameOrganizationModal(
|
||||
) {
|
||||
const [newName, setNewName] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {renameOrganization, isLoading} = useRenameOrganization({
|
||||
onSuccess: (oldName: string, newName: string) => {
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
AlertVariant as PFAlertVariant,
|
||||
} from '@patternfly/react-core';
|
||||
import {useSendRecoveryEmail} from 'src/hooks/UseUserActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface SendRecoveryEmailModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -21,7 +20,7 @@ export default function SendRecoveryEmailModal(
|
||||
) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [successEmail, setSuccessEmail] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {sendRecovery, isLoading} = useSendRecoveryEmail({
|
||||
onSuccess: (data) => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {useState} from 'react';
|
||||
import {Modal, ModalVariant, Button, Text, Alert} from '@patternfly/react-core';
|
||||
import {useTakeOwnership} from 'src/hooks/UseOrganizationActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface TakeOwnershipModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -13,7 +12,7 @@ interface TakeOwnershipModalProps {
|
||||
|
||||
export default function TakeOwnershipModal(props: TakeOwnershipModalProps) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const entityType = props.isUser ? 'user' : 'organization';
|
||||
|
||||
const {takeOwnership, isLoading} = useTakeOwnership({
|
||||
@@ -46,8 +45,6 @@ export default function TakeOwnershipModal(props: TakeOwnershipModalProps) {
|
||||
takeOwnership(props.organizationName);
|
||||
};
|
||||
|
||||
const entityType = props.isUser ? 'user' : 'organization';
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Take Ownership"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {useState} from 'react';
|
||||
import {Modal, ModalVariant, Button, Text, Alert} from '@patternfly/react-core';
|
||||
import {useToggleUserStatus} from 'src/hooks/UseUserActions';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
interface ToggleUserStatusModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -15,14 +14,15 @@ export default function ToggleUserStatusModal(
|
||||
props: ToggleUserStatusModalProps,
|
||||
) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const action = props.currentlyEnabled ? 'disabled' : 'enabled';
|
||||
const {addAlert} = useUI();
|
||||
const action = props.currentlyEnabled ? 'Disable' : 'Enable';
|
||||
const actionLower = action.toLowerCase();
|
||||
|
||||
const {toggleStatus, isLoading} = useToggleUserStatus({
|
||||
onSuccess: () => {
|
||||
addAlert({
|
||||
variant: AlertVariant.Success,
|
||||
title: `Successfully ${action} user ${props.username}`,
|
||||
title: `Successfully ${actionLower}d user ${props.username}`,
|
||||
});
|
||||
handleClose();
|
||||
},
|
||||
@@ -32,9 +32,7 @@ export default function ToggleUserStatusModal(
|
||||
setError(errorMessage);
|
||||
addAlert({
|
||||
variant: AlertVariant.Failure,
|
||||
title: `Failed to ${
|
||||
action === 'disabled' ? 'disable' : 'enable'
|
||||
} user ${props.username}`,
|
||||
title: `Failed to ${actionLower} user ${props.username}`,
|
||||
message: errorMessage,
|
||||
});
|
||||
},
|
||||
@@ -50,9 +48,6 @@ export default function ToggleUserStatusModal(
|
||||
toggleStatus(props.username, !props.currentlyEnabled);
|
||||
};
|
||||
|
||||
const action = props.currentlyEnabled ? 'Disable' : 'Enable';
|
||||
const actionLower = action.toLowerCase();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={`${action} User`}
|
||||
|
||||
@@ -50,8 +50,7 @@ import {
|
||||
import {useRobotRepoPermissions} from 'src/hooks/useRobotAccounts';
|
||||
import RobotTokensModal from 'src/components/modals/RobotTokensModal';
|
||||
import {SearchState} from 'src/components/toolbar/SearchTypes';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {RobotFederationModal} from 'src/components/modals/RobotFederationModal';
|
||||
import {usePaginatedSortableTable} from '../../hooks/usePaginatedSortableTable';
|
||||
|
||||
@@ -113,7 +112,7 @@ export default function RobotAccountsList(props: RobotAccountsListProps) {
|
||||
const [isRobotFederationModalOpen, setRobotFederationModalOpen] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const {robotAccountsForOrg} = useRobotAccounts({
|
||||
name: props.organizationName,
|
||||
|
||||
@@ -14,8 +14,7 @@ import BuildTriggerDescription from './BuildTriggerDescription';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import {useState} from 'react';
|
||||
import {useStartBuild} from 'src/hooks/UseBuilds';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useSourceRefs} from 'src/hooks/UseBuildTriggers';
|
||||
import TypeAheadSelect from 'src/components/TypeAheadSelect';
|
||||
import {isNullOrUndefined} from 'src/libs/utils';
|
||||
@@ -25,7 +24,7 @@ export default function ManuallyStartTrigger(props: ManuallyStartTriggerProps) {
|
||||
const [commit, setCommit] = useState<string>('');
|
||||
const [ref, setRef] = useState<SourceRef>({name: '', kind: null});
|
||||
const [isValid, setIsValid] = useState<boolean>(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {refs, isLoading, isError, error} = useSourceRefs(
|
||||
org,
|
||||
repo,
|
||||
|
||||
@@ -12,12 +12,11 @@ import {
|
||||
import {DesktopIcon} from '@patternfly/react-icons';
|
||||
import React from 'react';
|
||||
import {useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import EntitySearch from 'src/components/EntitySearch';
|
||||
import FileUpload from 'src/components/FileUpload';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import CreateRobotAccountModal from 'src/components/modals/CreateRobotAccountModal';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useStartDockerfileBuild} from 'src/hooks/UseBuilds';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import {useRepository, useTransitivePermissions} from 'src/hooks/UseRepository';
|
||||
@@ -37,7 +36,7 @@ export default function DockerfileUploadBuild(
|
||||
const [privateRepo, setPrivatRepo] = useState<string>();
|
||||
const [selectedRobot, setSelectedRobot] = useState<string>(null);
|
||||
const [isCreateRobotModalOpen, setIsCreateRobotModalOpen] = useState(false);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {teams} = useFetchTeams(props.org);
|
||||
const [org, repo] = privateRepo?.split('/') ?? [null, null];
|
||||
const {repoDetails} = useRepository(org, repo);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {Button, Modal, ModalVariant} from '@patternfly/react-core';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useDeleteBuildTrigger} from 'src/hooks/UseBuildTriggers';
|
||||
|
||||
export default function BuildTriggerDeleteModal(
|
||||
props: BuildTriggerDeleteModalProps,
|
||||
) {
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {deleteTrigger} = useDeleteBuildTrigger(
|
||||
props.org,
|
||||
props.repo,
|
||||
|
||||
@@ -12,8 +12,7 @@ import ContextStep from './BuildTriggerSetupWizardContext';
|
||||
import RobotAccounts from './BuildTriggerSetupWizardRobotAccounts';
|
||||
import ReviewAndFinishProps from './BuildTriggerSetupWizardReviewAndFinish';
|
||||
import {useActivateBuildTrigger} from 'src/hooks/UseBuildTriggers';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import SelectOrganization from './BuildTriggerSetupWizardOrganization';
|
||||
import {isNullOrUndefined} from 'src/libs/utils';
|
||||
import HostedRepository from './BuildTriggerSetupWizardHostedRepository';
|
||||
@@ -45,7 +44,7 @@ export default function BuildTriggerSetupWizard(
|
||||
repoUrl,
|
||||
!isNullOrUndefined(repoUrl) && repoUrl !== '' && !isCustomGit,
|
||||
);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {activateTrigger} = useActivateBuildTrigger(
|
||||
props.org,
|
||||
props.repo,
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {Button, Modal, ModalVariant} from '@patternfly/react-core';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useToggleBuildTrigger} from 'src/hooks/UseBuildTriggers';
|
||||
|
||||
export default function BuildTriggerToggleModal(
|
||||
props: BuildTriggerToggleModalProps,
|
||||
) {
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {toggleTrigger} = useToggleBuildTrigger(
|
||||
props.org,
|
||||
props.repo,
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import {Td, Tr} from '@patternfly/react-table';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useDeleteBuildTrigger} from 'src/hooks/UseBuildTriggers';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
|
||||
export default function InactiveTrigger(props: InactiveTriggerProps) {
|
||||
const config = useQuayConfig();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {deleteTrigger} = useDeleteBuildTrigger(
|
||||
props.org,
|
||||
props.repo,
|
||||
|
||||
@@ -24,8 +24,7 @@ import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import {useQuayState} from 'src/hooks/UseQuayState';
|
||||
import {RepositoryDetails} from 'src/resources/RepositoryResource';
|
||||
import axios from 'src/libs/axios';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import Markdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import React from 'react';
|
||||
@@ -91,7 +90,7 @@ export default function Information(props: InformationProps) {
|
||||
const {organization, repository, repoDetails} = props;
|
||||
const config = useQuayConfig();
|
||||
const {inReadOnlyMode} = useQuayState();
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [description, setDescription] = useState(
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
import {DesktopIcon, UsersIcon} from '@patternfly/react-icons';
|
||||
import {useRepository} from 'src/hooks/UseRepository';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import FormError from 'src/components/errors/FormError';
|
||||
import {useFetchRobotAccounts} from 'src/hooks/useRobotAccounts';
|
||||
import {useFetchTeams} from 'src/hooks/UseTeams';
|
||||
@@ -40,7 +40,7 @@ export const Mirroring: React.FC<MirroringProps> = ({namespace, repoName}) => {
|
||||
errorLoadingRepoDetails,
|
||||
isLoading: isLoadingRepo,
|
||||
} = useRepository(namespace, repoName);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Initialize form hook
|
||||
|
||||
@@ -18,7 +18,7 @@ import {FormTextInput} from 'src/components/forms/FormTextInput';
|
||||
import {FormCheckbox} from 'src/components/forms/FormCheckbox';
|
||||
import EntitySearch from 'src/components/EntitySearch';
|
||||
import {Entity} from 'src/resources/UserResource';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
import {
|
||||
MirroringConfigResponse,
|
||||
getMirrorConfig,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
import CreateRobotAccountModal from 'src/components/modals/CreateRobotAccountModal';
|
||||
import {CreateTeamModal} from 'src/routes/OrganizationsList/Organization/Tabs/DefaultPermissions/createPermissionDrawer/CreateTeamModal';
|
||||
import {Entity} from 'src/resources/UserResource';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import {Divider, Button} from '@patternfly/react-core';
|
||||
import {StatusDisplay} from 'src/components/StatusDisplay';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant} from 'src/contexts/UIContext';
|
||||
import {
|
||||
MirroringConfigResponse,
|
||||
getMirrorConfig,
|
||||
|
||||
@@ -15,13 +15,12 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import {useLocation, useNavigate, useSearchParams} from 'react-router-dom';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {QuayBreadcrumb} from 'src/components/breadcrumb/Breadcrumb';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import ErrorBoundary from 'src/components/errors/ErrorBoundary';
|
||||
import RequestError from 'src/components/errors/RequestError';
|
||||
import CreateRobotAccountModal from 'src/components/modals/CreateRobotAccountModal';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useQuayConfig} from 'src/hooks/UseQuayConfig';
|
||||
import {useRepository} from 'src/hooks/UseRepository';
|
||||
import {useFetchTeams} from 'src/hooks/UseTeams';
|
||||
@@ -73,7 +72,7 @@ export default function RepositoryDetails() {
|
||||
);
|
||||
const [isCreateRobotModalOpen, setIsCreateRobotModalOpen] = useState(false);
|
||||
const [selectedEntity, setSelectedEntity] = useState<Entity>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [err, setErr] = useState<string>();
|
||||
|
||||
const drawerRef = useRef<HTMLDivElement>();
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import {Button, Spinner, Title} from '@patternfly/react-core';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import RequestError from 'src/components/errors/RequestError';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useNamespaceAutoPrunePolicies} from 'src/hooks/UseNamespaceAutoPrunePolicies';
|
||||
import {useOrganization} from 'src/hooks/UseOrganization';
|
||||
import {
|
||||
@@ -23,7 +22,7 @@ import {getErrorMessageFromUnknown} from 'src/resources/ErrorHandling';
|
||||
|
||||
export default function RepositoryAutoPruning(props: RepositoryAutoPruning) {
|
||||
const [policies, setPolicies] = useState([]);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {organization} = useOrganization(props.organizationName);
|
||||
const {user} = useCurrentUser();
|
||||
const config = useQuayConfig();
|
||||
|
||||
@@ -3,13 +3,12 @@ import {TagAction, TagEntry} from './types';
|
||||
import ManifestDigest from 'src/components/ManifestDigest';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {usePermanentlyDeleteTag} from 'src/hooks/UseTags';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {InfoCircleIcon} from '@patternfly/react-icons';
|
||||
|
||||
export default function PermanentlyDeleteTag(props: RestoreTagProps) {
|
||||
const {tagEntry} = props;
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const {permanentlyDeleteTag, success, error} = usePermanentlyDeleteTag(
|
||||
props.org,
|
||||
|
||||
@@ -3,12 +3,11 @@ import {TagAction, TagEntry} from './types';
|
||||
import {ReactElement, useEffect, useState} from 'react';
|
||||
import {Alert, Button, Label, Modal} from '@patternfly/react-core';
|
||||
import {useRestoreTag} from 'src/hooks/UseTags';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
export default function RestoreTag(props: RestoreTagProps) {
|
||||
const {tagEntry, org, repo} = props;
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const {restoreTag, success, error} = useRestoreTag(org, repo);
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ import './Tags.css';
|
||||
import {isNullOrUndefined} from 'src/libs/utils';
|
||||
import Conditional from 'src/components/empty/Conditional';
|
||||
import {useDeleteTag} from 'src/hooks/UseTags';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertDetails, AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertDetails, AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
export interface ModalOptions {
|
||||
isOpen: boolean;
|
||||
@@ -26,7 +25,7 @@ export function DeleteModal(props: ModalProps) {
|
||||
errorDeleteTags,
|
||||
errorDeleteTagDetails,
|
||||
} = useDeleteTag(props.org, props.repo);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const isReadonly: boolean = props.repoDetails?.state !== 'NORMAL';
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -6,14 +6,13 @@ import {
|
||||
Title,
|
||||
} from '@patternfly/react-core';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useCreateTag} from 'src/hooks/UseTags';
|
||||
import {isNullOrUndefined} from 'src/libs/utils';
|
||||
|
||||
export default function AddTagModal(props: AddTagModalProps) {
|
||||
const [value, setValue] = useState('');
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {createTag, successCreateTag, errorCreateTag} = useCreateTag(
|
||||
props.org,
|
||||
props.repo,
|
||||
|
||||
@@ -14,14 +14,13 @@ import {
|
||||
TimePicker,
|
||||
} from '@patternfly/react-core';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
import {useSetExpiration} from 'src/hooks/UseTags';
|
||||
import {formatDate, isNullOrUndefined} from 'src/libs/utils';
|
||||
|
||||
export default function EditExpirationModal(props: EditExpirationModalProps) {
|
||||
const [date, setDate] = useState<Date>(null);
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const {
|
||||
setExpiration,
|
||||
successSetExpiration,
|
||||
|
||||
@@ -39,6 +39,7 @@ import {OAuthError} from 'src/routes/OAuthCallback/OAuthError';
|
||||
import SystemStatusBanner from 'src/components/SystemStatusBanner';
|
||||
import {GlobalMessages} from 'src/components/GlobalMessages';
|
||||
import {LoadingPage} from 'src/components/LoadingPage';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
|
||||
// Lazy load route components for better performance
|
||||
const OrganizationsList = lazy(
|
||||
@@ -212,9 +213,16 @@ export function StandaloneMain() {
|
||||
|
||||
const quayConfig = useQuayConfig();
|
||||
const {loading, error} = useCurrentUser();
|
||||
const location = useLocation();
|
||||
const {clearAllAlerts} = useUI();
|
||||
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
|
||||
// Clear alerts when navigating to a different route
|
||||
useEffect(() => {
|
||||
clearAllAlerts();
|
||||
}, [location.pathname, clearAllAlerts]);
|
||||
|
||||
const toggleDrawer = () => {
|
||||
setIsDrawerOpen((prev) => !prev);
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
HelperTextItem,
|
||||
} from '@patternfly/react-core';
|
||||
import {useCreateServiceKey} from 'src/hooks/UseCreateServiceKey';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {useUI} from 'src/contexts/UIContext';
|
||||
import FormError from 'src/components/errors/FormError';
|
||||
|
||||
interface CreateServiceKeyFormProps {
|
||||
@@ -26,7 +26,7 @@ export const CreateServiceKeyForm: React.FC<CreateServiceKeyFormProps> = ({
|
||||
onClose,
|
||||
onSuccess,
|
||||
}) => {
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
|
||||
const formHook = useCreateServiceKey(addAlert, setError, () => {
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
|
||||
import {exportLogs} from 'src/hooks/UseUsageLogs';
|
||||
import {useAlerts} from 'src/hooks/UseAlerts';
|
||||
import {AlertVariant} from 'src/atoms/AlertState';
|
||||
import {AlertVariant, useUI} from 'src/contexts/UIContext';
|
||||
|
||||
export default function ExportLogsModal(props: ExportLogsModalProps) {
|
||||
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
||||
@@ -22,7 +21,7 @@ export default function ExportLogsModal(props: ExportLogsModalProps) {
|
||||
const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => {
|
||||
setIsModalOpen(!isModalOpen);
|
||||
};
|
||||
const {addAlert} = useAlerts();
|
||||
const {addAlert} = useUI();
|
||||
|
||||
const exportLogsClick = (callback: string) => {
|
||||
return exportLogs(
|
||||
|
||||
Reference in New Issue
Block a user