Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve loading of apps and data models on Dashboard #13137

Merged
merged 17 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export const DataModelsReposList = ({ user, organizations }: DataModelsReposList
const { data: dataModelRepos, isPending: hasPendingDataModels } = useSearchReposQuery({
uid: uid as number,
keyword: DATA_MODEL_REPO_IDENTIFIER,
page: 1,
});

const dataModelsIncludingStarredData = useAugmentReposWithStarred({
Expand Down
1 change: 0 additions & 1 deletion frontend/dashboard/components/OrgRepoList/OrgReposList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const OrgReposList = ({ user, organizations }: OrgReposListProps) => {
const { data: dataModelsResults, isPending: hasPendingDataModels } = useSearchReposQuery({
uid: uid as number,
keyword: DATA_MODEL_REPO_IDENTIFIER,
page: 1,
});
const totalRows = repoResults?.totalCount - dataModelsResults?.totalCount ?? 0;

Expand Down
11 changes: 9 additions & 2 deletions frontend/dashboard/components/RepoList/ActionLinks.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
}

.giteaButton {
margin-right: 0.7rem;
margin-right: 0.45rem;
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
}

.giteaIcon {
font-size: 2rem;
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
padding-top: 0.1rem;
padding-right: 0.1rem;
color: var(--fds-semantic-text-success-default);
}

.nativeActionIcon {
.editButton {
padding-top: 0.4rem;
}

.nativeIcon {
font-size: 1.7rem;
color: var(--fds-semantic-text-action-default);
}
4 changes: 2 additions & 2 deletions frontend/dashboard/components/RepoList/ActionLinks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ describe('ActionLinks', () => {
it('should render the three buttons', () => {
render(<ActionLinks repo={repo} />);

const giteaButton = screen.getByRole('link', {
const giteaButton = screen.getByRole('button', {
name: textMock('dashboard.show_repo', { appName: repoName }),
});
const editButton = screen.getByRole('link', {
const editButton = screen.getByRole('button', {
name: textMock('dashboard.edit_app', { appName: repoName }),
});
const dropdownButton = screen.getByRole('button', {
Expand Down
92 changes: 48 additions & 44 deletions frontend/dashboard/components/RepoList/ActionLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Button, DropdownMenu } from '@digdir/designsystemet-react';
import { StudioButton, StudioDropdownMenu } from '@studio/components';
import type { StudioButtonProps } from '@studio/components';
import React, { useRef, useState } from 'react';
import classes from './ActionLinks.module.css';
import cn from 'classnames';
Expand All @@ -12,7 +13,6 @@ import { useTranslation } from 'react-i18next';
import { getRepoEditUrl } from '../../utils/urlUtils';
import type { Repository } from 'app-shared/types/Repository';
import { MakeCopyModal } from '../MakeCopyModal';
import { DATA_MODEL_REPO_IDENTIFIER } from '../../constants';

type ActionLinksProps = {
repo: Repository;
Expand All @@ -36,52 +36,56 @@ export const ActionLinks = ({ repo }: ActionLinksProps): React.ReactElement => {

const repoFullName = repo.full_name;
const [org, repoName] = repoFullName.split('/');
const isDataModelRepo = repoFullName.endsWith(DATA_MODEL_REPO_IDENTIFIER);
const editUrl = getRepoEditUrl({ org, repo: repoName });
const editTextKey = t(isDataModelRepo ? 'dashboard.edit_data_models' : 'dashboard.edit_app', {
appName: repoName,
});

const giteaIconWithLink = (
<a href={repo.html_url}>
<span className={cn('fa fa-gitea', classes.giteaIcon)} />
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
</a>
);

const editIconWithLink = (
<a href={editUrl}>
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
<PencilIcon className={classes.nativeIcon} />
</a>
);

const dropdownAnchorButtonProps = {
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
variant: 'tertiary' as StudioButtonProps['variant'],
icon: <MenuElipsisVerticalIcon className={classes.nativeIcon} />,
title: t('dashboard.app_dropdown', {
appName: repoName,
}),
};

return (
<div className={classes.actionLinksContainer} ref={copyModalAnchorRef}>
<Button variant={'tertiary'} className={classes.giteaButton} icon asChild>
<a
href={repo.html_url}
title={t('dashboard.show_repo', {
appName: repoName,
})}
>
<i className={cn('fa fa-gitea', classes.giteaIcon)} />
</a>
</Button>
<Button variant={'tertiary'} icon asChild>
<a href={editUrl} title={editTextKey}>
<PencilIcon className={classes.nativeActionIcon} />
</a>
</Button>
<DropdownMenu size={'small'}>
<DropdownMenu.Trigger
variant={'tertiary'}
title={t('dashboard.app_dropdown', {
appName: repoName,
})}
asChild
>
<Button variant={'tertiary'} icon>
<MenuElipsisVerticalIcon className={classes.nativeActionIcon} />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item onClick={() => handleOpenCopyModal(repoFullName)}>
{<FilesIcon />}
{t('dashboard.make_copy')}
</DropdownMenu.Item>
<DropdownMenu.Item onClick={() => window.open(editUrl, '_blank')}>
{<ExternalLinkIcon />}
{t('dashboard.open_in_new')}
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
<StudioButton
title={t('dashboard.show_repo', {
appName: repoName,
})}
variant={'tertiary'}
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
className={classes.giteaButton}
icon={giteaIconWithLink}
/>
<StudioButton
title={t('dashboard.edit_app', {
appName: repoName,
})}
variant={'tertiary'}
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
className={classes.editButton}
icon={editIconWithLink}
/>
<StudioDropdownMenu size={'small'} anchorButtonProps={dropdownAnchorButtonProps}>
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
<StudioDropdownMenu.Item onClick={() => handleOpenCopyModal(repoFullName)}>
{<FilesIcon />}
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
{t('dashboard.make_copy')}
</StudioDropdownMenu.Item>
<StudioDropdownMenu.Item onClick={() => window.open(editUrl, '_blank')}>
{<ExternalLinkIcon />}
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
{t('dashboard.open_in_new')}
</StudioDropdownMenu.Item>
</StudioDropdownMenu>
{copyCurrentRepoName && (
<MakeCopyModal
ref={copyModalAnchorRef}
Expand Down
24 changes: 15 additions & 9 deletions frontend/dashboard/components/RepoList/FavoriteButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { StarFillIcon, StarIcon } from '@navikt/aksel-icons';
import { Button } from '@digdir/designsystemet-react';
import { StudioButton } from '@studio/components';
import React from 'react';
import { useSetStarredRepoMutation, useUnsetStarredRepoMutation } from '../../hooks/mutations';
import type { RepoIncludingStarredData } from '../../utils/repoUtils/repoUtils';
Expand Down Expand Up @@ -27,14 +27,20 @@ export const FavoriteButton = ({ repo }: FavoriteButtonProps): React.ReactElemen
appName: repo.name,
});

return (
<Button title={title} onClick={handleToggleFav} variant={'tertiary'} icon>
{repo.hasStarred ? (
<StarFillIcon className={classes.favoriteIcon} />
) : (
<StarIcon className={classes.favoriteIcon} />
)}
</Button>
return repo.hasStarred ? (
<StudioButton
title={title}
onClick={handleToggleFav}
variant='tertiary'
icon={<StarFillIcon className={classes.favoriteIcon} />}
/>
) : (
<StudioButton
title={title}
onClick={handleToggleFav}
variant='tertiary'
icon={<StarIcon className={classes.favoriteIcon} />}
/>
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
);
};

Expand Down
17 changes: 8 additions & 9 deletions frontend/dashboard/components/RepoList/RepoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ import type { RepoIncludingStarredData } from 'dashboard/utils/repoUtils/repoUti
import { useTranslation } from 'react-i18next';
import type { DATAGRID_PAGE_SIZE_TYPE } from '../../constants';
import { DATAGRID_DEFAULT_PAGE_SIZE, DATAGRID_PAGE_SIZE_OPTIONS } from '../../constants';
import {
StudioSpinner,
StudioTableLocalPagination,
StudioTableRemotePagination,
} from '@studio/components';
import { StudioTableLocalPagination, StudioTableRemotePagination } from '@studio/components';
import type { Columns, PaginationTexts, RemotePaginationProps } from '@studio/components';
import { ActionLinks } from './ActionLinks';
import { FavoriteButton } from './FavoriteButton';
Expand Down Expand Up @@ -84,7 +80,8 @@ export const RepoList = ({
},
];

// The local table can sort all columns, but Gitea API does not support sorting by createdBy or description
// The local table can sort all columns, but the Gitea API does not support sorting by createdBy or description
// Therefore, we remove the sortable property from these columns when using server-side sorting
const nonSortableAccessors = ['createdBy', 'description'];
const remotePaginationColumns = columns.map((column) => ({
...column,
Expand All @@ -101,9 +98,7 @@ export const RepoList = ({
actionIcons: <ActionLinks repo={repo} />,
}));

const emptyTableFallback = isLoading ? (
<StudioSpinner spinnerTitle={t('general.loading')} />
) : (
const emptyTableFallback = (
<Paragraph size={tableSize}>{t('dashboard.no_repos_result')}</Paragraph>
);

Expand Down Expand Up @@ -133,6 +128,8 @@ export const RepoList = ({
columns={remotePaginationColumns}
rows={rows}
size={tableSize}
isLoading={isLoading}
loadingText={t('general.loading')}
emptyTableFallback={emptyTableFallback}
pagination={paginationProps}
onSortClick={onSortClick}
Expand All @@ -142,6 +139,8 @@ export const RepoList = ({
columns={columns}
rows={rows}
size={tableSize}
isLoading={isLoading}
loadingText={t('general.loading')}
emptyTableFallback={emptyTableFallback}
pagination={paginationProps}
/>
Expand Down
13 changes: 7 additions & 6 deletions frontend/dashboard/components/RepoList/RepoNameWithLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Link } from '@digdir/designsystemet-react';
import classes from './RepoNameWithLink.module.css';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { DATA_MODEL_REPO_IDENTIFIER } from '../../constants';

type RepoNameWithLinkProps = {
repoFullName: string;
Expand All @@ -13,14 +12,16 @@ export const RepoNameWithLink = ({ repoFullName }: RepoNameWithLinkProps): React
const { t } = useTranslation();

const [org, repoName] = repoFullName.split('/');
const isDataModelRepo = repoFullName.endsWith(DATA_MODEL_REPO_IDENTIFIER);
const editUrl = getRepoEditUrl({ org, repo: repoName });
const editTextKey = t(isDataModelRepo ? 'dashboard.edit_data_models' : 'dashboard.edit_app', {
appName: repoName,
});

return (
<Link className={classes.repoLink} href={editUrl} title={editTextKey}>
<Link
className={classes.repoLink}
href={editUrl}
title={t('dashboard.edit_app', {
appName: repoName,
})}
>
{repoName}
</Link>
);
Expand Down
9 changes: 9 additions & 0 deletions frontend/dashboard/hooks/useReposSearch/useRepoSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ export const useReposSearch = ({
const { data: searchResults, isPending: isLoadingSearchResults } =
useSearchReposQuery(cleanFilter);

const getNextExistingPageNumber = () => {
const numberOfPages = Math.ceil(searchResults?.totalCount / pageSize);
const nextPageNumber = pageNumber + 1;
return nextPageNumber <= numberOfPages ? nextPageNumber : pageNumber;
};

// Prefetch and cache the next page, if it exists
useSearchReposQuery({ ...cleanFilter, page: getNextExistingPageNumber() });

return {
searchResults,
isLoadingSearchResults,
Expand Down
1 change: 0 additions & 1 deletion frontend/language/src/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
"dashboard.data_models": "Data models",
"dashboard.description": "Description",
"dashboard.edit_app": "Edit {{appName}} in Studio",
"dashboard.edit_data_models": "Edit {{appName}} in Studio",
"dashboard.favorite_status": "Favorite status",
"dashboard.favourites": "Favourites",
"dashboard.field_cannot_be_empty": "Field cannot be empty",
Expand Down
5 changes: 2 additions & 3 deletions frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@
"dashboard.creating_your_service": "Oppretter appen din",
"dashboard.data_models": "Datamodeller",
"dashboard.description": "Beskrivelse",
"dashboard.edit_app": "Rediger {{appName}} i Studio",
"dashboard.edit_data_models": "Rediger {{appName}} i Studio",
"dashboard.edit_app": "Endre {{appName}} i Studio",
"dashboard.favorite_status": "Favorittstatus",
"dashboard.favourites": "Favoritter",
"dashboard.field_cannot_be_empty": "Dette feltet kan ikke være tomt",
Expand Down Expand Up @@ -154,7 +153,7 @@
"dashboard.show_repo": "Vis repoet til {{appName}}",
"dashboard.star": "Legg til {{appName}} i favoritter",
"dashboard.total_count": "Rader totalt:",
"dashboard.unstar": "Fjern {{appName}} fra favoritter",
"dashboard.unstar": "Slett {{appName}} fra favoritter",
"dashboard.view_apps_error_title": "Kan ikke vise listen over applikasjoner",
"dashboard.view_data_models_error_title": "Kan ikke vise listen over datamodeller",
"dashboard.view_favorites_error_title": "Kan ikke vise listen over favoritter",
Expand Down
Loading