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

[FC-0059] UI fixes on create content #1198

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
14 changes: 10 additions & 4 deletions src/library-authoring/EmptyStates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@ import { ClearFiltersButton } from '../search-manager';
import messages from './messages';
import { LibraryContext } from './common/context';

export const NoComponents = () => {
interface NoComponentsPorps {
ChrisChV marked this conversation as resolved.
Show resolved Hide resolved
canEditLibrary: boolean
}

export const NoComponents = ({ canEditLibrary } : NoComponentsPorps) => {
const { openAddContentSidebar } = useContext(LibraryContext);

return (
<Stack direction="horizontal" gap={3} className="mt-6 justify-content-center">
<FormattedMessage {...messages.noComponents} />
<Button iconBefore={Add} onClick={() => openAddContentSidebar()}>
<FormattedMessage {...messages.addComponent} />
</Button>
{canEditLibrary && (
<Button iconBefore={Add} onClick={() => openAddContentSidebar()}>
<FormattedMessage {...messages.addComponent} />
</Button>
)}
</Stack>
);
};
Expand Down
33 changes: 33 additions & 0 deletions src/library-authoring/LibraryAuthoringPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,24 @@ describe('<LibraryAuthoringPage />', () => {
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(2, searchEndpoint, 'post'); });

expect(getByText('You have not added any content to this library yet.')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /add component/i })).toBeInTheDocument();
});

it('show library without components without permission', async () => {
const data = {
...libraryData,
canEditLibrary: false,
};
mockUseParams.mockReturnValue({ libraryId: libraryData.id });
axiosMock.onGet(getContentLibraryApiUrl(libraryData.id)).reply(200, data);
fetchMock.post(searchEndpoint, returnEmptyResult, { overwriteRoutes: true });

render(<RootWrapper />);

expect(await screen.findByText('Content library')).toBeInTheDocument();

expect(screen.getByText('You have not added any content to this library yet.')).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /add component/i })).not.toBeInTheDocument();
});

it('show new content button', async () => {
Expand All @@ -245,6 +263,21 @@ describe('<LibraryAuthoringPage />', () => {
expect(screen.getByRole('button', { name: /new/i })).toBeInTheDocument();
});

it('read only state of library', async () => {
const data = {
...libraryData,
canEditLibrary: false,
};
mockUseParams.mockReturnValue({ libraryId: libraryData.id });
axiosMock.onGet(getContentLibraryApiUrl(libraryData.id)).reply(200, data);

render(<RootWrapper />);
expect(await screen.findByRole('heading')).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /new/i })).not.toBeInTheDocument();

expect(screen.getByText('Read Only')).toBeInTheDocument();
});

it('show library without search results', async () => {
mockUseParams.mockReturnValue({ libraryId: libraryData.id });
axiosMock.onGet(getContentLibraryApiUrl(libraryData.id)).reply(200, libraryData);
Expand Down
75 changes: 52 additions & 23 deletions src/library-authoring/LibraryAuthoringPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import React, { useContext } from 'react';
import { StudioFooter } from '@edx/frontend-component-footer';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Badge,
Button,
Col,
Container,
Icon,
IconButton,
Row,
Stack,
Tab,
Tabs,
} from '@openedx/paragon';
Expand Down Expand Up @@ -42,18 +44,53 @@ enum TabList {
collections = 'collections',
}

const SubHeaderTitle = ({ title }: { title: string }) => {
interface HeaderActionsProps {
canEditLibrary: boolean;
}

const HeaderActions = ({ canEditLibrary }: HeaderActionsProps) => {
const intl = useIntl();
const {
openAddContentSidebar,
} = useContext(LibraryContext);

if (!canEditLibrary) {
return null;
}

return (
<Button
iconBefore={Add}
variant="primary rounded-0"
onClick={() => openAddContentSidebar()}
disabled={!canEditLibrary}
>
{intl.formatMessage(messages.newContentButton)}
</Button>
);
};

const SubHeaderTitle = ({ title, canEditLibrary }: { title: string, canEditLibrary: boolean }) => {
const intl = useIntl();
return (
<>
{title}
<IconButton
src={InfoOutline}
iconAs={Icon}
alt={intl.formatMessage(messages.headingInfoAlt)}
className="mr-2"
/>
</>
<Stack direction="vertical">
<Stack direction="horizontal">
{title}
<IconButton
src={InfoOutline}
iconAs={Icon}
alt={intl.formatMessage(messages.headingInfoAlt)}
className="mr-2"
/>
</Stack>
{ !canEditLibrary && (
<div>
<Badge variant="primary" style={{ fontSize: '50%' }}>
{intl.formatMessage(messages.readOnlyBadge)}
</Badge>
</div>
)}
</Stack>
);
};

Expand All @@ -67,7 +104,7 @@ const LibraryAuthoringPage = () => {

const currentPath = location.pathname.split('/').pop();
const activeKey = (currentPath && currentPath in TabList) ? TabList[currentPath] : TabList.home;
const { sidebarBodyComponent, openAddContentSidebar } = useContext(LibraryContext);
const { sidebarBodyComponent } = useContext(LibraryContext);

const [searchParams] = useSearchParams();

Expand Down Expand Up @@ -102,18 +139,9 @@ const LibraryAuthoringPage = () => {
>
<Container size="xl" className="p-4 mt-3">
<SubHeader
title={<SubHeaderTitle title={libraryData.title} />}
title={<SubHeaderTitle title={libraryData.title} canEditLibrary={libraryData.canEditLibrary} />}
subtitle={intl.formatMessage(messages.headingSubtitle)}
headerActions={[
<Button
iconBefore={Add}
variant="primary rounded-0"
onClick={openAddContentSidebar}
disabled={!libraryData.canEditLibrary}
>
{intl.formatMessage(messages.newContentButton)}
</Button>,
]}
headerActions={<HeaderActions canEditLibrary={libraryData.canEditLibrary} />}
/>
<SearchKeywordsField className="w-50" />
<div className="d-flex mt-3 align-items-center">
Expand Down Expand Up @@ -141,12 +169,13 @@ const LibraryAuthoringPage = () => {
libraryId={libraryId}
tabList={TabList}
handleTabChange={handleTabChange}
canEditLibrary={libraryData.canEditLibrary}
/>
)}
/>
<Route
path={TabList.components}
element={<LibraryComponents libraryId={libraryId} variant="full" />}
element={<LibraryComponents libraryId={libraryId} variant="full" canEditLibrary={libraryData.canEditLibrary} />}
/>
<Route
path={TabList.collections}
Expand Down
14 changes: 10 additions & 4 deletions src/library-authoring/LibraryHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ type LibraryHomeProps = {
libraryId: string,
tabList: { home: string, components: string, collections: string },
handleTabChange: (key: string) => void,
canEditLibrary: boolean,
};

const LibraryHome = ({ libraryId, tabList, handleTabChange } : LibraryHomeProps) => {
const LibraryHome = ({
libraryId,
tabList,
handleTabChange,
canEditLibrary,
} : LibraryHomeProps) => {
const intl = useIntl();
const {
totalHits: componentCount,
Expand All @@ -27,14 +33,14 @@ const LibraryHome = ({ libraryId, tabList, handleTabChange } : LibraryHomeProps)

const renderEmptyState = () => {
if (componentCount === 0) {
return isFiltered ? <NoSearchResults /> : <NoComponents />;
return isFiltered ? <NoSearchResults /> : <NoComponents canEditLibrary={canEditLibrary} />;
}
return null;
};

return (
<Stack gap={3}>
<LibraryRecentlyModified libraryId={libraryId} />
<LibraryRecentlyModified libraryId={libraryId} canEditLibrary={canEditLibrary} />
bradenmacdonald marked this conversation as resolved.
Show resolved Hide resolved
{
renderEmptyState()
|| (
Expand All @@ -51,7 +57,7 @@ const LibraryHome = ({ libraryId, tabList, handleTabChange } : LibraryHomeProps)
contentCount={componentCount}
viewAllAction={() => handleTabChange(tabList.components)}
>
<LibraryComponents libraryId={libraryId} variant="preview" />
<LibraryComponents libraryId={libraryId} variant="preview" canEditLibrary={canEditLibrary} />
</LibrarySection>
</>
)
Expand Down
13 changes: 9 additions & 4 deletions src/library-authoring/LibraryRecentlyModified.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import LibraryComponents from './components/LibraryComponents';
import LibrarySection from './components/LibrarySection';
import messages from './messages';

const RecentlyModified: React.FC<{ libraryId: string }> = ({ libraryId }) => {
interface RecentlyModifiedProps {
libraryId: string,
canEditLibrary: boolean,
}

const RecentlyModified = ({ libraryId, canEditLibrary } : RecentlyModifiedProps) => {
const intl = useIntl();
const { totalHits: componentCount } = useSearchContext();

Expand All @@ -17,18 +22,18 @@ const RecentlyModified: React.FC<{ libraryId: string }> = ({ libraryId }) => {
title={intl.formatMessage(messages.recentlyModifiedTitle)}
contentCount={componentCount}
>
<LibraryComponents libraryId={libraryId} variant="preview" />
<LibraryComponents libraryId={libraryId} variant="preview" canEditLibrary={canEditLibrary} />
</LibrarySection>
)
: null;
};

const LibraryRecentlyModified: React.FC<{ libraryId: string }> = ({ libraryId }) => (
const LibraryRecentlyModified = ({ libraryId, canEditLibrary } : RecentlyModifiedProps) => (
<SearchContextProvider
extraFilter={`context_key = "${libraryId}"`}
overrideSearchSortOrder={SearchSortOption.RECENTLY_MODIFIED}
>
<RecentlyModified libraryId={libraryId} />
<RecentlyModified libraryId={libraryId} canEditLibrary={canEditLibrary} />
</SearchContextProvider>
);

Expand Down
4 changes: 3 additions & 1 deletion src/library-authoring/components/LibraryComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LIBRARY_SECTION_PREVIEW_LIMIT } from './LibrarySection';
type LibraryComponentsProps = {
libraryId: string,
variant: 'full' | 'preview',
canEditLibrary: boolean,
};

/**
Expand All @@ -22,6 +23,7 @@ type LibraryComponentsProps = {
const LibraryComponents = ({
libraryId,
variant,
canEditLibrary,
}: LibraryComponentsProps) => {
const {
hits,
Expand Down Expand Up @@ -68,7 +70,7 @@ const LibraryComponents = ({
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);

if (componentCount === 0) {
return isFiltered ? <NoSearchResults /> : <NoComponents />;
return isFiltered ? <NoSearchResults /> : <NoComponents canEditLibrary={canEditLibrary} />;
}

return (
Expand Down
5 changes: 5 additions & 0 deletions src/library-authoring/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ const messages = defineMessages({
defaultMessage: 'Close',
description: 'Alt text of close button',
},
readOnlyBadge: {
id: 'course-authoring.library-authoring.badge.read-only',
defaultMessage: 'Read Only',
description: 'Text in badge when the user has read only access',
},
});

export default messages;
Loading