diff --git a/frontend/src/component/common/Search/Search.tsx b/frontend/src/component/common/Search/Search.tsx index 7dba5a3aab..66db56540c 100644 --- a/frontend/src/component/common/Search/Search.tsx +++ b/frontend/src/component/common/Search/Search.tsx @@ -81,6 +81,7 @@ export const Search = ({ containerStyles, expandable = false, debounceTime = 200, + ...rest }: ISearchProps) => { const searchInputRef = useRef(null); const searchContainerRef = useRef(null); @@ -126,6 +127,7 @@ export const Search = ({ ref={searchContainerRef} style={containerStyles} active={expandable && showSuggestions} + {...rest} > ({ }) => ( {headerGroups.map((headerGroup) => ( - + {headerGroup.headers.map((column: HeaderGroup) => { const content = column.render('Header'); diff --git a/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx b/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx index 6d85342a3b..a181ba0d65 100644 --- a/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx +++ b/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx @@ -8,6 +8,7 @@ interface IFeatureSeenCellProps { export const FeatureEnvironmentSeenCell: VFC = ({ feature, + ...rest }) => { const environments = feature.environments ? Object.values(feature.environments) @@ -17,6 +18,7 @@ export const FeatureEnvironmentSeenCell: VFC = ({ ); }; diff --git a/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx index 18c7b6d986..0bc9563edd 100644 --- a/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx +++ b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx @@ -72,7 +72,7 @@ export const LastSeenTooltip = ({ Boolean(environment.lastSeenAt), ); return ( - + Last usage reported diff --git a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx index 8e2253674c..9b62625dfd 100644 --- a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx @@ -74,6 +74,7 @@ export const FeatureEnvironmentSeen = ({ featureLastSeen, environments, sx, + ...rest }: IFeatureEnvironmentSeenProps) => { const getColor = useLastSeenColors(); @@ -95,6 +96,7 @@ export const FeatureEnvironmentSeen = ({ } color={color} diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx index f84c3eeb41..718202199a 100644 --- a/frontend/src/component/project/Project/Project.tsx +++ b/frontend/src/component/project/Project/Project.tsx @@ -228,6 +228,7 @@ export const Project = () => { {filteredTabs.map((tab) => { return ( = ({ }; return ( - + ({ whiteSpace: 'nowrap', @@ -73,6 +74,7 @@ interface IPaginatedProjectFeatureTogglesProps { loading: boolean; onChange: () => void; total?: number; + initialLoad: boolean; searchValue: string; setSearchValue: React.Dispatch>; paginationBar: JSX.Element; @@ -87,6 +89,7 @@ const defaultSort: SortingRule & { export const PaginatedProjectFeatureToggles = ({ features, loading, + initialLoad, environments: newEnvironments = [], onChange, total, @@ -95,6 +98,8 @@ export const PaginatedProjectFeatureToggles = ({ paginationBar, }: IPaginatedProjectFeatureTogglesProps) => { const { classes: styles } = useStyles(); + const bodyLoadingRef = useLoading(loading); + const headerLoadingRef = useLoading(initialLoad); const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const [strategiesDialogState, setStrategiesDialogState] = useState({ @@ -198,7 +203,10 @@ export const PaginatedProjectFeatureToggles = ({ accessor: 'lastSeenAt', Cell: ({ value, row: { original: feature } }: any) => { return showEnvironmentLastSeen ? ( - + ) : ( ); @@ -355,15 +363,20 @@ export const PaginatedProjectFeatureToggles = ({ ); const data = useMemo(() => { - if (loading) { - return Array(6).fill({ - type: '-', - name: 'Feature name', - createdAt: new Date(), - environments: { - production: { name: 'production', enabled: false }, - }, - }) as FeatureSchema[]; + if (initialLoad || loading) { + const loadingData = Array(15) + .fill(null) + .map((_, index) => ({ + id: index, // Assuming `id` is a required property + type: '-', + name: `Feature name ${index}`, + createdAt: new Date().toISOString(), + environments: { + production: { name: 'production', enabled: false }, + }, + })); + // Coerce loading data to FeatureSchema[] + return loadingData as unknown as FeatureSchema[]; } return featuresData; }, [loading, featuresData]); @@ -491,168 +504,193 @@ export const PaginatedProjectFeatureToggles = ({ return ( <> - setShowTitle(false)} - onBlur={() => setShowTitle(true)} - hasFilters - getSearchContext={getSearchContext} - id='projectFeatureToggles' - /> - } - /> - - - - - setShowExportDialog(true) - } - sx={(theme) => ({ - marginRight: - theme.spacing(2), - })} - > - - - - } - /> - - navigate(getCreateTogglePath(projectId)) - } - maxWidth='960px' - Icon={Add} - projectId={projectId} - permission={CREATE_FEATURE} - data-testid='NAVIGATE_TO_CREATE_FEATURE' - > - New feature toggle - - - } - > - +
+ - + actions={ + <> + + setShowTitle(false) + } + onBlur={() => + setShowTitle(true) + } + hasFilters + getSearchContext={ + getSearchContext + } + id='projectFeatureToggles' + /> + } + /> + + + + + setShowExportDialog( + true, + ) + } + sx={(theme) => ({ + marginRight: + theme.spacing(2), + })} + > + + + + } + /> + + navigate( + getCreateTogglePath(projectId), + ) + } + maxWidth='960px' + Icon={Add} + projectId={projectId} + permission={CREATE_FEATURE} + data-testid='NAVIGATE_TO_CREATE_FEATURE' + > + New feature toggle + + + } + > + + } + /> + +
} > - - + + + + + 0} + show={ + + No feature toggles found matching + “ + {searchValue} + ” + + } + elseShow={ + + No feature toggles available. Get + started by adding a new feature toggle. + + } + /> + } /> - - 0} - show={ - - No feature toggles found matching “ - {searchValue} - ” - - } - elseShow={ - - No feature toggles available. Get started by - adding a new feature toggle. - - } - /> - } - /> - - setStrategiesDialogState((prev) => ({ - ...prev, - open: false, - })) - } - projectId={projectId} - {...strategiesDialogState} - /> - { - setFeatureStaleDialogState({}); - onChange(); - }} - featureId={featureStaleDialogState.featureId || ''} - projectId={projectId} - /> - { - setFeatureArchiveState(undefined); - }} - featureIds={[featureArchiveState || '']} - projectId={projectId} - /> - setShowExportDialog(false)} - environments={environments} - /> - } - /> - {featureToggleModals} + + setStrategiesDialogState((prev) => ({ + ...prev, + open: false, + })) + } + projectId={projectId} + {...strategiesDialogState} + /> + { + setFeatureStaleDialogState({}); + onChange(); + }} + featureId={featureStaleDialogState.featureId || ''} + projectId={projectId} + /> + { + setFeatureArchiveState(undefined); + }} + featureIds={[featureArchiveState || '']} + projectId={projectId} + /> + setShowExportDialog(false)} + environments={environments} + /> + } + /> + {featureToggleModals} + {paginationBar} diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/RowSelectCell/RowSelectCell.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/RowSelectCell/RowSelectCell.tsx index 4636a2cd40..a77672ba08 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/RowSelectCell/RowSelectCell.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/RowSelectCell/RowSelectCell.tsx @@ -20,7 +20,7 @@ export const RowSelectCell: FC = ({ checked, title, }) => ( - + ); diff --git a/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx index d70a01ec48..30ee7b1c2c 100644 --- a/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx @@ -40,7 +40,7 @@ export const HealthWidget = ({ projectId, health }: IHealthWidgetProps) => { gap: (theme) => theme.spacing(2), }} > - + diff --git a/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx index 69404315b1..3043e4fc1d 100644 --- a/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx @@ -24,8 +24,8 @@ const StyledIDContainer = styled('div')(({ theme }) => ({ export const MetaWidget: FC = ({ id, description }) => { return ( - Project Meta - + Project Meta + = ({ id, description }) => { condition={Boolean(description)} show={ theme.spacing(1.5), diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx index eba45e5ce8..82fade8b04 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx @@ -30,6 +30,7 @@ export const ProjectMembersWidget = ({ Project members - View all members + + View all members + ); }; diff --git a/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx index fb41a0ab5e..ff052ba828 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx @@ -84,7 +84,9 @@ export const ToggleTypesWidget = ({ features }: IToggleTypesWidgetProps) => { theme.spacing(3) }} > - Toggle types used + + Toggle types used + {Object.keys(featureTypeStats).map((type) => ( = ({ }) => { return ( { const { project, loading: projectLoading } = useProject(projectId, { refreshInterval, }); - const [pageLimit, setPageLimit] = useState(10); + const [pageLimit, setPageLimit] = useState(25); const [currentOffset, setCurrentOffset] = useState(0); const [searchValue, setSearchValue] = useState( @@ -57,6 +57,7 @@ const PaginatedProjectOverview = () => { total, refetch, loading, + initialLoad, } = useFeatureSearch(currentOffset, pageLimit, projectId, searchValue, { refreshInterval, }); @@ -96,6 +97,7 @@ const PaginatedProjectOverview = () => { } features={searchFeatures} environments={environments} + initialLoad={initialLoad && searchFeatures.length === 0} loading={loading && searchFeatures.length === 0} onChange={refetch} total={total} @@ -128,7 +130,7 @@ const StyledStickyBar = styled('div')(({ theme }) => ({ backgroundColor: theme.palette.background.paper, padding: theme.spacing(2), marginLeft: theme.spacing(2), - zIndex: theme.zIndex.mobileStepper, + zIndex: 9999, borderBottomLeftRadius: theme.shape.borderRadiusMedium, borderBottomRightRadius: theme.shape.borderRadiusMedium, borderTop: `1px solid ${theme.palette.divider}`, diff --git a/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx b/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx index 50de0f9c67..c703f98118 100644 --- a/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx +++ b/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx @@ -65,7 +65,11 @@ export const StatusBox: FC = ({ <> {title}} + show={ + + {title} + + } /> {children} = ({ width: 'auto', }} > - {boxText} + + {boxText} + + {customChangeElement} } @@ -87,7 +93,7 @@ export const StatusBox: FC = ({ + = ({ } elseShow={ - + No change diff --git a/frontend/src/component/tags/TagTypeList/__tests__/__snapshots__/TagTypeList.test.tsx.snap b/frontend/src/component/tags/TagTypeList/__tests__/__snapshots__/TagTypeList.test.tsx.snap index fae6e1c8b6..1ea15d7bf7 100644 --- a/frontend/src/component/tags/TagTypeList/__tests__/__snapshots__/TagTypeList.test.tsx.snap +++ b/frontend/src/component/tags/TagTypeList/__tests__/__snapshots__/TagTypeList.test.tsx.snap @@ -119,6 +119,7 @@ exports[`renders an empty list correctly 1`] = ` > void; } @@ -26,38 +27,52 @@ const fallbackData: { total: 0, }; -export const useFeatureSearch = ( - offset: number, - limit: number, - projectId = '', - searchValue = '', - options: SWRConfiguration = {}, -): IUseFeatureSearchOutput => { - const { KEY, fetcher } = getFeatureSearchFetcher( - projectId, - offset, - limit, - searchValue, - ); - const { data, error, mutate } = useSWR( - KEY, - fetcher, - options, - ); +const createFeatureSearch = () => { + let total = 0; + let initialLoad = true; - const refetch = useCallback(() => { - mutate(); - }, [mutate]); + return ( + offset: number, + limit: number, + projectId = '', + searchValue = '', + options: SWRConfiguration = {}, + ): IUseFeatureSearchOutput => { + const { KEY, fetcher } = getFeatureSearchFetcher( + projectId, + offset, + limit, + searchValue, + ); + const { data, error, mutate, isLoading } = + useSWR(KEY, fetcher, options); - const returnData = data || fallbackData; - return { - ...returnData, - loading: false, - error, - refetch, + const refetch = useCallback(() => { + mutate(); + }, [mutate]); + + if (data?.total) { + total = data.total; + } + + if (!isLoading && initialLoad) { + initialLoad = false; + } + + const returnData = data || fallbackData; + return { + ...returnData, + loading: isLoading, + error, + refetch, + total, + initialLoad: isLoading && initialLoad, + }; }; }; +export const useFeatureSearch = createFeatureSearch(); + const getFeatureSearchFetcher = ( projectId: string, offset: number, diff --git a/frontend/src/hooks/useLoading.ts b/frontend/src/hooks/useLoading.ts index a0c207c2aa..194091bff3 100644 --- a/frontend/src/hooks/useLoading.ts +++ b/frontend/src/hooks/useLoading.ts @@ -12,7 +12,7 @@ const useLoading = (loading: boolean, selector = '[data-loading=true]') => { if (loading) { element.classList.add('skeleton'); } else { - element.classList.remove('skeleton'); + setTimeout(() => element.classList.remove('skeleton'), 10); } }); } diff --git a/frontend/src/themes/app.css b/frontend/src/themes/app.css index f353d22e22..6bfe9b5a98 100644 --- a/frontend/src/themes/app.css +++ b/frontend/src/themes/app.css @@ -36,7 +36,7 @@ button { .skeleton { position: relative; overflow: hidden; - z-index: 9999; + z-index: 9990; box-shadow: none; fill: none; pointer-events: none;