Skip to content

Commit

Permalink
Merge pull request #3363 from uktrade/feat/managed-data-tile
Browse files Browse the repository at this point in the history
Feat/managed data tile
  • Loading branch information
JamesPRobinson authored Nov 25, 2024
2 parents 8fdd3a1 + 6515b53 commit 5fb80ef
Show file tree
Hide file tree
Showing 14 changed files with 324 additions and 21 deletions.
21 changes: 21 additions & 0 deletions cypress/e2e/homepage/dashboard.cy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const endpoints = {
managedData: "/api/v2/managed_data/stats/",
recentItems: "/api/v2/recent_items/*",
recentCollections: "/api/v2/collections/*",
recentTools: "/api/v2/recent_tools/*",
Expand Down Expand Up @@ -45,6 +46,7 @@ describe("Homepage dashboard", () => {

context("When a user visits the page for the first time", () => {
beforeEach(() => {
cy.intercept(endpoints.managedData, { count: 0, managed_data_url: 'such-and-such'}).as("managedData");
cy.intercept(endpoints.recentItems, { results: [] }).as("recentItems");
cy.intercept(endpoints.recentCollections, { results: [] }).as(
"recentCollections"
Expand All @@ -56,6 +58,11 @@ describe("Homepage dashboard", () => {
cy.visit("/");
});

it("should not show the managed data tile", () => {
cy.wait("@managedData");
cy.get('article').contains("You're the owner or manager of ").should('not.exist');
});

it("should show the 'Your recent items' section with NO items", () => {
cy.wait("@recentItems");
cy.findByRole("heading", {
Expand Down Expand Up @@ -112,6 +119,10 @@ describe("Homepage dashboard", () => {

context("When an exisiting user visits the page", () => {
beforeEach(() => {
cy.intercept(endpoints.managedData, {
"count": 50,
"managed_data_url": "/datasets/?q=&sort=relevance&my_datasets=owned"
}).as("managedData");
cy.intercept(endpoints.recentItems, {
results: [
{
Expand Down Expand Up @@ -171,6 +182,16 @@ describe("Homepage dashboard", () => {
cy.visit("/");
});

it("should show the 'Managed Data' section with with a figure", () => {
cy.wait("@managedData");
cy.findByRole("heading", {
level: 2,
name: "You're the owner or manager of 50 datasets",
}).should("be.visible");
cy.findByRole("link", { name: "View and manage your data" }).should('have.attr', 'href', '/datasets/?q=&sort=relevance&my_datasets=owned');
cy.findByRole("link", { name: /Learn how to maintain and manage data/i }).should('have.attr', 'href', 'https://data-services-help.trade.gov.uk/data-workspace/how-to/data-owner-basics/managing-data-key-tasks-and-responsibilities');
});

it("should show the 'Your recent items' section with items", () => {
cy.wait("@recentItems");
cy.findByRole("heading", {
Expand Down
7 changes: 7 additions & 0 deletions dataworkspace/dataworkspace/apps/api_v2/managed_data/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from rest_framework.routers import DefaultRouter

from dataworkspace.apps.api_v2.managed_data.views import ManagedDataViewSet

router = DefaultRouter()
router.register(r"managed_data", ManagedDataViewSet)
urlpatterns = router.urls
38 changes: 38 additions & 0 deletions dataworkspace/dataworkspace/apps/api_v2/managed_data/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django.db.models import Q
from django.urls import reverse
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from dataworkspace.apps.api_v1.mixins import TimestampFilterMixin
from dataworkspace.apps.datasets.models import DataSet


class TimestampPageNumberPagination(PageNumberPagination):
page_size_query_param = "page_size"
max_page_size = 100


class ManagedDataViewSet(TimestampFilterMixin, viewsets.ModelViewSet):
queryset = DataSet.objects.live()
pagination_class = TimestampPageNumberPagination
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]

def get_queryset(self):
user_id = self.request.user.id
return (
super()
.get_queryset()
.filter(Q(information_asset_manager=user_id) | Q(information_asset_owner=user_id))
)

@action(detail=False, methods=["get"], url_path="stats")
def stats(self, request, *args, **kwargs):
kwargs = "?q=&sort=relevance&my_datasets=owned"
managed_data_url = f"{reverse('datasets:find_datasets')}{kwargs}"
count = self.get_queryset().count()
return Response({"count": count, "managed_data_url": managed_data_url})
7 changes: 7 additions & 0 deletions dataworkspace/dataworkspace/apps/api_v2/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@
namespace="inline_feedback",
),
),
path(
"",
include(
("dataworkspace.apps.api_v2.managed_data.urls", "api_v2"),
namespace="managed_data",
),
),
]
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react';

import { FONT_SIZE, SPACING_POINTS } from '@govuk-react/constants';
import { SPACING_POINTS } from '@govuk-react/constants';
import { Button, H2, Link } from 'govuk-react';
import styled from 'styled-components';

Expand All @@ -21,6 +21,12 @@ const Dialog = styled('dialog')`
width: 660px;
`;

const StyledLink = styled(Link)`
display: inline-block;
font-size: 20px;
margin-top: 5px;
`;

export const ConfirmDialog = (props: ConfirmDialogProps) => {
const refModal = useRef<HTMLDialogElement>(null);
const closeModal = function () {
Expand Down Expand Up @@ -50,17 +56,9 @@ export const ConfirmDialog = (props: ConfirmDialogProps) => {
>
{props.buttonText}
</Button>
<Link
href="javascript:;"
onClick={props.onClose}
style={{
display: 'inline-block',
fontSize: FONT_SIZE.SIZE_24,
marginTop: SPACING_POINTS[1]
}}
>
<StyledLink href="javascript:;" onClick={props.onClose}>
Cancel
</Link>
</StyledLink>
</form>
</ContainerButtonGroup>
</Dialog>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type TileProps = {
as?: React.ElementType;
headerSize?: number;
headerLevel?: 1 | 2 | 3 | 4 | 5;
contentWrapper?: boolean;
children: ReactNode;
dataTest?: string;
};
Expand All @@ -38,11 +39,16 @@ const Header: React.FC<HeaderProps> = ({
return header[headerLevel];
};

const ContentWrapper = styled('div')`
margin-top: 30px;
`;

const Tile: React.FC<TileProps> = ({
title,
headerSize = 27,
headerLevel = 2,
as,
contentWrapper = false,
children,
dataTest
}) => {
Expand All @@ -53,7 +59,13 @@ const Tile: React.FC<TileProps> = ({
<Header headerLevel={headerLevel} headerSize={headerSize}>
{title}
</Header>
{children}
{contentWrapper ? (
<>
<ContentWrapper>{children}</ContentWrapper>{' '}
</>
) : (
<>{children} </>
)}
</InnerContainer>
</Component>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@ import styled from 'styled-components';

import ConfirmDialog from '../../components/ConfirmDialog/';

const RemoveUserTableCell = styled(Table.Cell)`
vertical-align: middle;
text-align: right;
`;

const SpanBold = styled('span')`
font-weight: bold;
`;

const UserNameTableCell = styled(Table.Cell)`
padding-bottom: 1px;
`;

type User = {
data_catalogue_editor: boolean;
email: string;
Expand Down Expand Up @@ -54,20 +63,15 @@ const ConfirmRemoveUser = ({
<Table>
{data.map((user) => (
<Table.Row key={user.id}>
<Table.Cell style={{ paddingBottom: '1px' }}>
<UserNameTableCell>
<SpanBold>{`${user.first_name} ${user.last_name} `}</SpanBold>
<UserTypeSuffix user={user} />
<Paragraph>{user.email}</Paragraph>
</Table.Cell>
</UserNameTableCell>
{[user.iam, user.iao].some((x) => x == true) ? (
<Table.Cell></Table.Cell>
) : (
<Table.Cell
style={{
verticalAlign: 'middle',
textAlign: 'right'
}}
>
<RemoveUserTableCell>
<Button
buttonColour="#f3f2f1"
buttonTextColour="#0b0c0c"
Expand All @@ -76,7 +80,7 @@ const ConfirmRemoveUser = ({
>
Remove user
</Button>
</Table.Cell>
</RemoveUserTableCell>
)}
</Table.Row>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import styled from 'styled-components';
import { FetchDataContainer, InnerContainer } from '../../components';
import { GREY_4 } from '../../constants';
import {
fetchManageData,
fetchRecentCollections,
fetchRecentItems,
fetchYourBookmarks,
fetchYourRecentTools
} from '../../services';
import SupportYou from '../support/Support';
import ManagedData from './components/ManageData';
import RecentCollections from './components/RecentCollections';
import RecentItems from './components/RecentItems';
import RecentTools from './components/RecentTools';
Expand All @@ -36,6 +38,12 @@ const YourSection = styled('div')`
}
`;

const LandscapeYourSection = styled('div')`
display: grid;
grid-column: 1 / span 2;
grid-row: 1;
`;

const SupportSection = styled('section')`
padding: ${SPACING_POINTS['6']}px 0 ${SPACING_POINTS['9']}px 0;
`;
Expand All @@ -44,6 +52,11 @@ const HomePage = () => (
<main role="main" id="main-content">
<YourSection>
<InnerContainer>
<LandscapeYourSection>
<FetchDataContainer fetchApi={() => fetchManageData()}>
{(data) => <ManagedData managed_data_stats={data} />}
</FetchDataContainer>
</LandscapeYourSection>
<div>
<FetchDataContainer fetchApi={() => fetchRecentItems()}>
{(data) => <RecentItems items={data} />}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { render } from '@testing-library/react';

import { ManagedDataResponse } from '../../../../types';
import ManagedData from '.';

describe('RecentCollections', () => {
const managed_data_stats_multiple_datasets: ManagedDataResponse = {
count: 5,
managed_data_url: '/datasets?q='
};

const managed_data_stats_single_dataset: ManagedDataResponse = {
count: 1,
managed_data_url: '/datasets?q='
};

const managed_data_stats_no_dataset: ManagedDataResponse = {
count: 0,
managed_data_url: '/datasets?q='
};

describe('With results', () => {
it('should render a title', () => {
const { getByRole } = render(
<ManagedData
managed_data_stats={managed_data_stats_multiple_datasets}
/>
);
expect(
getByRole('heading', {
level: 2,
// eslint-disable-next-line quotes
name: "You're the owner or manager of 5 datasets"
})
);
});
it('should render a title in the singular', () => {
const { getByRole } = render(
<ManagedData managed_data_stats={managed_data_stats_single_dataset} />
);
expect(
getByRole('heading', {
level: 2,
// eslint-disable-next-line quotes
name: "You're the owner or manager of 1 dataset"
})
);
});
it('should not render at all', () => {
const { queryByRole } = render(
<ManagedData managed_data_stats={managed_data_stats_no_dataset} />
);
expect(
queryByRole('heading', {
level: 2,
// eslint-disable-next-line quotes
name: "You're the owner or manager of 0 dataset"
})
).not.toBeInTheDocument();
});
it('should render a link to the manage data page', () => {
const { getByRole } = render(
<ManagedData managed_data_stats={managed_data_stats_single_dataset} />
);
expect(
getByRole('link', { name: 'View and manage your data' })
).toHaveAttribute('href', '/datasets?q=');
});
it('should render a link to helpcentre guidance', () => {
const { getByRole } = render(
<ManagedData managed_data_stats={managed_data_stats_single_dataset} />
);
expect(
getByRole('link', {
// eslint-disable-next-line quotes
name: "Learn how to maintain and manage data you're responsible for on Data Workspace"
})
).toHaveAttribute(
'href',
'https://data-services-help.trade.gov.uk/data-workspace/how-to/data-owner-basics/managing-data-key-tasks-and-responsibilities'
);
});
it('should not render a link to helpcentre guidance', () => {
const { queryByRole } = render(
<ManagedData managed_data_stats={managed_data_stats_no_dataset} />
);
expect(
queryByRole('link', {
// eslint-disable-next-line quotes
name: "Learn how to maintain and manage data you're responsible for on Data Workspace"
})
).not.toBeInTheDocument();
});
});
});
Loading

0 comments on commit 5fb80ef

Please sign in to comment.