mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-01 01:18:10 +02:00
Sticky batch actions bar (#3366)
This commit is contained in:
parent
e03307e286
commit
5585a9bed0
@ -1,6 +1,6 @@
|
|||||||
import { FC, useState } from 'react';
|
import { FC, useState } from 'react';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { Undo } from '@mui/icons-material';
|
import { Delete, Undo } from '@mui/icons-material';
|
||||||
import {
|
import {
|
||||||
DELETE_FEATURE,
|
DELETE_FEATURE,
|
||||||
UPDATE_FEATURE,
|
UPDATE_FEATURE,
|
||||||
@ -69,7 +69,7 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
|
|||||||
{({ hasAccess }) => (
|
{({ hasAccess }) => (
|
||||||
<Button
|
<Button
|
||||||
disabled={!hasAccess}
|
disabled={!hasAccess}
|
||||||
startIcon={<Undo />}
|
startIcon={<Delete />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={onDelete}
|
onClick={onDelete}
|
||||||
|
@ -294,6 +294,7 @@ export const ArchiveTable = ({
|
|||||||
}, [loading, sortBy, searchValue]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [loading, sortBy, searchValue]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<PageContent
|
<PageContent
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
header={
|
header={
|
||||||
@ -334,7 +335,8 @@ export const ArchiveTable = ({
|
|||||||
}
|
}
|
||||||
elseShow={
|
elseShow={
|
||||||
<TablePlaceholder>
|
<TablePlaceholder>
|
||||||
None of the feature toggles were archived yet.
|
None of the feature toggles were archived
|
||||||
|
yet.
|
||||||
</TablePlaceholder>
|
</TablePlaceholder>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -347,11 +349,12 @@ export const ArchiveTable = ({
|
|||||||
setOpen={setDeleteModalOpen}
|
setOpen={setDeleteModalOpen}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
/>
|
/>
|
||||||
|
</PageContent>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(projectId)}
|
condition={Boolean(projectId)}
|
||||||
show={
|
show={
|
||||||
<BatchSelectionActionsBar
|
<BatchSelectionActionsBar
|
||||||
selectedIds={Object.keys(selectedRowIds)}
|
count={Object.keys(selectedRowIds).length}
|
||||||
>
|
>
|
||||||
<ArchiveBatchActions
|
<ArchiveBatchActions
|
||||||
selectedIds={Object.keys(selectedRowIds)}
|
selectedIds={Object.keys(selectedRowIds)}
|
||||||
@ -360,6 +363,6 @@ export const ArchiveTable = ({
|
|||||||
</BatchSelectionActionsBar>
|
</BatchSelectionActionsBar>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</PageContent>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,14 +2,21 @@ import { FC } from 'react';
|
|||||||
import { Box, Paper, styled, Typography } from '@mui/material';
|
import { Box, Paper, styled, Typography } from '@mui/material';
|
||||||
|
|
||||||
interface IBatchSelectionActionsBarProps {
|
interface IBatchSelectionActionsBarProps {
|
||||||
selectedIds: string[];
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledContainer = styled(Box)(() => ({
|
const StyledStickyContainer = styled('div')(() => ({
|
||||||
|
position: 'sticky',
|
||||||
|
marginTop: 'auto',
|
||||||
|
bottom: 0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledContainer = styled(Box)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
|
paddingBottom: theme.spacing(2),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledBar = styled(Paper)(({ theme }) => ({
|
const StyledBar = styled(Paper)(({ theme }) => ({
|
||||||
@ -40,22 +47,24 @@ const StyledText = styled(Typography)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
export const BatchSelectionActionsBar: FC<IBatchSelectionActionsBarProps> = ({
|
export const BatchSelectionActionsBar: FC<IBatchSelectionActionsBarProps> = ({
|
||||||
selectedIds,
|
count,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
if (selectedIds.length === 0) {
|
if (count === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<StyledStickyContainer>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledBar elevation={4}>
|
<StyledBar elevation={4}>
|
||||||
<StyledText>
|
<StyledText>
|
||||||
<StyledCount>{selectedIds.length}</StyledCount>
|
<StyledCount>{count}</StyledCount>
|
||||||
 selected
|
 selected
|
||||||
</StyledText>
|
</StyledText>
|
||||||
{children}
|
{children}
|
||||||
</StyledBar>
|
</StyledBar>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
|
</StyledStickyContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -91,7 +91,6 @@ export const InstanceStatus: FC = ({ children }) => {
|
|||||||
useInstanceStatus();
|
useInstanceStatus();
|
||||||
const { extendTrial } = useInstanceStatusApi();
|
const { extendTrial } = useInstanceStatusApi();
|
||||||
const { setToastApiError } = useToast();
|
const { setToastApiError } = useToast();
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const onExtendTrial = async () => {
|
const onExtendTrial = async () => {
|
||||||
try {
|
try {
|
||||||
@ -103,12 +102,7 @@ export const InstanceStatus: FC = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
style={{
|
|
||||||
height: '100%',
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={isBilling && Boolean(instanceStatus)}
|
condition={isBilling && Boolean(instanceStatus)}
|
||||||
show={() => (
|
show={() => (
|
||||||
@ -124,7 +118,7 @@ export const InstanceStatus: FC = ({ children }) => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,12 +21,15 @@ interface IMainLayoutProps {
|
|||||||
const MainLayoutContainer = styled(Grid)(() => ({
|
const MainLayoutContainer = styled(Grid)(() => ({
|
||||||
height: '100%',
|
height: '100%',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexGrow: 1,
|
||||||
|
position: 'relative',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const MainLayoutContentWrapper = styled('main')(({ theme }) => ({
|
const MainLayoutContentWrapper = styled('main')(({ theme }) => ({
|
||||||
margin: theme.spacing(0, 'auto'),
|
margin: theme.spacing(0, 'auto'),
|
||||||
overflow: 'auto', // prevent margin collapsing
|
flexGrow: 1,
|
||||||
flex: 1,
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
backgroundColor: theme.palette.background.application,
|
backgroundColor: theme.palette.background.application,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
@ -554,6 +554,7 @@ export const ProjectFeatureToggles = ({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<PageContent
|
<PageContent
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
className={styles.container}
|
className={styles.container}
|
||||||
@ -596,7 +597,8 @@ export const ProjectFeatureToggles = ({
|
|||||||
setShowExportDialog(true)
|
setShowExportDialog(true)
|
||||||
}
|
}
|
||||||
sx={theme => ({
|
sx={theme => ({
|
||||||
marginRight: theme.spacing(2),
|
marginRight:
|
||||||
|
theme.spacing(2),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<FileDownload />
|
<FileDownload />
|
||||||
@ -663,7 +665,10 @@ export const ProjectFeatureToggles = ({
|
|||||||
/>
|
/>
|
||||||
<EnvironmentStrategyDialog
|
<EnvironmentStrategyDialog
|
||||||
onClose={() =>
|
onClose={() =>
|
||||||
setStrategiesDialogState(prev => ({ ...prev, open: false }))
|
setStrategiesDialogState(prev => ({
|
||||||
|
...prev,
|
||||||
|
open: false,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
{...strategiesDialogState}
|
{...strategiesDialogState}
|
||||||
@ -696,15 +701,20 @@ export const ProjectFeatureToggles = ({
|
|||||||
onConfirm={onChangeRequestToggleConfirm}
|
onConfirm={onChangeRequestToggleConfirm}
|
||||||
messageComponent={
|
messageComponent={
|
||||||
<UpdateEnabledMessage
|
<UpdateEnabledMessage
|
||||||
featureName={changeRequestDialogDetails.featureName!}
|
featureName={
|
||||||
|
changeRequestDialogDetails.featureName!
|
||||||
|
}
|
||||||
enabled={changeRequestDialogDetails.enabled!}
|
enabled={changeRequestDialogDetails.enabled!}
|
||||||
environment={changeRequestDialogDetails?.environment!}
|
environment={
|
||||||
|
changeRequestDialogDetails?.environment!
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={
|
||||||
Boolean(uiConfig?.flags?.featuresExportImport) && !loading
|
Boolean(uiConfig?.flags?.featuresExportImport) &&
|
||||||
|
!loading
|
||||||
}
|
}
|
||||||
show={
|
show={
|
||||||
<ExportDialog
|
<ExportDialog
|
||||||
@ -715,13 +725,16 @@ export const ProjectFeatureToggles = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<BatchSelectionActionsBar selectedIds={Object.keys(selectedRowIds)}>
|
</PageContent>
|
||||||
|
<BatchSelectionActionsBar
|
||||||
|
count={Object.keys(selectedRowIds).length}
|
||||||
|
>
|
||||||
<ProjectFeaturesBatchActions
|
<ProjectFeaturesBatchActions
|
||||||
selectedIds={Object.keys(selectedRowIds)}
|
selectedIds={Object.keys(selectedRowIds)}
|
||||||
data={features}
|
data={features}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
/>
|
/>
|
||||||
</BatchSelectionActionsBar>
|
</BatchSelectionActionsBar>
|
||||||
</PageContent>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -9,10 +9,13 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
min-height: 100%;
|
||||||
font-family: 'Sen', sans-serif;
|
font-family: 'Sen', sans-serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-variant-ligatures: none;
|
font-variant-ligatures: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@ -139,7 +142,10 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
height: 100%;
|
flex-grow: 1;
|
||||||
|
min-height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MuiCardHeader-title {
|
.MuiCardHeader-title {
|
||||||
|
Loading…
Reference in New Issue
Block a user