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] feat: Add content sidebar in library home #38

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
4191ecb
feat: Add lib v2/legacy tabs in studio home
yusuf-musleh May 27, 2024
15c678b
feat: Add `LIBRARY_MODE` config variable
yusuf-musleh May 28, 2024
14b8b3a
feat: Add url paths/navigation for each tab
yusuf-musleh May 28, 2024
515cc71
feat: LibraryV2 redirect to lib mfe or placeholder
yusuf-musleh May 30, 2024
9c6e1e6
feat: Add pagination support for lib v2s
yusuf-musleh May 30, 2024
da189c1
fix: Redirect to placeholder create lib in v2/mixed disabled mfe
yusuf-musleh Jun 3, 2024
85d9ff2
temp: This removes TS code to get tests to run
yusuf-musleh Jun 3, 2024
c6b7bf8
test: Update existing tests to support changes
yusuf-musleh Jun 3, 2024
14933d2
temp: Rename .tsx -> .jsx & .ts -> .js for tests
yusuf-musleh Jun 3, 2024
8b96268
fix: Fix lint issues
yusuf-musleh Jun 3, 2024
f8db853
feat: library home page bare bones
rpenido Jun 4, 2024
7a8488d
test: Add tests for new functionality
yusuf-musleh Jun 4, 2024
7842ce0
fix: update search modal for new library urls
rpenido Jun 5, 2024
462cda9
feat: Add lib v2/legacy tabs in studio home
yusuf-musleh May 27, 2024
be8b2f4
feat: Add `LIBRARY_MODE` config variable
yusuf-musleh May 28, 2024
27b2581
feat: Add url paths/navigation for each tab
yusuf-musleh May 28, 2024
4ffd651
feat: LibraryV2 redirect to lib mfe or placeholder
yusuf-musleh May 30, 2024
7f97243
feat: Add pagination support for lib v2s
yusuf-musleh May 30, 2024
c86b85a
fix: Redirect to placeholder create lib in v2/mixed disabled mfe
yusuf-musleh Jun 3, 2024
efbc625
temp: This removes TS code to get tests to run
yusuf-musleh Jun 3, 2024
21da6f8
test: Update existing tests to support changes
yusuf-musleh Jun 3, 2024
79e6516
temp: Rename .tsx -> .jsx & .ts -> .js for tests
yusuf-musleh Jun 3, 2024
262cb3f
fix: Fix lint issues
yusuf-musleh Jun 3, 2024
1ea229f
test: Add tests for new functionality
yusuf-musleh Jun 4, 2024
a0a30b7
refactor: Change /legacy-libraries -> /libraries-v1
yusuf-musleh Jun 6, 2024
4deaea9
fix: add i18n messages
rpenido Jun 6, 2024
c2bdecf
fix: libraryAuthoring enabled check
rpenido Jun 6, 2024
5213eff
Merge branch 'yusuf-musleh/lib-v2-tab-studio-home' into rpenido/fal-3…
rpenido Jun 6, 2024
a24b3ba
fix: add Create Library placeholder
rpenido Jun 6, 2024
2859741
refactor: Remove hardcoded mfe path
yusuf-musleh Jun 6, 2024
d853f29
refactor: rename .ts files to .js
rpenido Jun 6, 2024
567dcb4
feat: Add function to construct Lib Auth MFE URL
yusuf-musleh Jun 6, 2024
094086e
feat: Make URL /library-v1 when referencing legacy
yusuf-musleh Jun 6, 2024
a95c990
fix: Add missing part of path
yusuf-musleh Jun 6, 2024
e3ebc55
fix: type and lint errors
rpenido Jun 6, 2024
8ed168d
fix: Issue with destinationUrl
yusuf-musleh Jun 6, 2024
beda37f
test: Add checks for Tab.eventKey in tests
yusuf-musleh Jun 6, 2024
2e3fa43
fix: Revert card item url changes to keep simple
yusuf-musleh Jun 7, 2024
6931998
fix: add tests
rpenido Jun 7, 2024
e6f73bd
feat: Add content drawer in library home
ChrisChV May 31, 2024
ac65976
feat: Creating library Drawer & Add content container
ChrisChV Jun 3, 2024
db2b843
feat: Connect new sidebar with API
ChrisChV Jun 4, 2024
fad191e
refactor: Add new content sidebar work into library-authoring page
ChrisChV Jun 5, 2024
60398b9
feat: Permissions to create new content
ChrisChV Jun 7, 2024
a6b5df4
refactor: Nits to solve rebase conflicts
ChrisChV Jun 7, 2024
72edfac
fix: add tests
rpenido Jun 7, 2024
8086ebf
Merge branch 'yusuf-musleh/lib-v2-tab-studio-home' into rpenido/fal-3…
rpenido Jun 7, 2024
91443e9
fix: removing unused file
rpenido Jun 7, 2024
a29cf7e
fix: add ts-check
rpenido Jun 7, 2024
4deab76
fix: removing deleted file references
rpenido Jun 7, 2024
e8bca34
chore: trigger CI
rpenido Jun 7, 2024
c15b570
test: Added for Add content sidebar
ChrisChV Jun 7, 2024
6c9b477
style: Nits on library authoring code
ChrisChV Jun 10, 2024
388c40e
fix: fixes from review
rpenido Jun 13, 2024
7d6096e
fix: fix default parameter syntax
rpenido Jun 14, 2024
fcfa848
feat: Global Toast & ToastContext. Refactor library redux to LibraryC…
ChrisChV Jun 17, 2024
4532a50
refactor: ToastContext
bradenmacdonald Jun 18, 2024
a593f88
Merge pull request #39 from open-craft/braden/chrisFAL-3754-library-h…
ChrisChV Jun 18, 2024
853bdf6
refactor: LibraryProvided created
ChrisChV Jun 18, 2024
c63bc2f
fix: new library redirect
rpenido Jun 18, 2024
efe0bed
Revert "fix: new library redirect"
rpenido Jun 19, 2024
942cbff
chore: trigger CI
rpenido Jun 19, 2024
2d3be09
fix: new library redirect
rpenido Jun 20, 2024
e8f9f78
fix: remove warning on library home
rpenido Jun 20, 2024
f9920f4
fix: remove unused import
rpenido Jun 20, 2024
7fd6c27
Merge branch 'master' into rpenido/fal-3753-library-home-page-bare-bones
rpenido Jun 20, 2024
94f483b
fix: merging nits
rpenido Jun 20, 2024
b455f97
fix: change version to slug in header
rpenido Jun 20, 2024
3ae6fe8
fix: header outline link for libraries
rpenido Jun 20, 2024
e972fb0
Merge branch 'master' into rpenido/fal-3753-library-home-page-bare-bones
rpenido Jun 21, 2024
55acb06
refactor: test renaming to ts
rpenido Jun 21, 2024
a1a0ad8
refactor: renaming files js -> ts
rpenido Jun 24, 2024
87358b7
fix: update typescript code
rpenido Jun 24, 2024
0b4e90e
Merge branch 'master' into rpenido/fal-3753-library-home-page-bare-bones
rpenido Jun 24, 2024
51d36ce
fix: remove @ts-check
rpenido Jun 25, 2024
fbd418d
fix: remove unused file
rpenido Jun 25, 2024
37f2124
chore: Fix merge conflicts
ChrisChV Jun 26, 2024
dee7c0b
Merge branch 'master' into rpenido/fal-3753-library-home-page-bare-bones
rpenido Jun 30, 2024
2a5d42b
fix: optional parameters
rpenido Jun 30, 2024
62fe7f5
chore: trigger CI
rpenido Jun 30, 2024
d37ffbf
refactor: Fixing some nits in the code about TS migration in library …
ChrisChV Jul 1, 2024
b721ff9
style: Lint on library authoring
ChrisChV Jul 1, 2024
7a7c0d7
Merge branch 'rpenido/fal-3753-library-home-page-bare-bones' into chr…
ChrisChV Jul 1, 2024
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
33 changes: 5 additions & 28 deletions src/CourseAuthoringPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,6 @@ import { getCourseAppsApiStatus } from './pages-and-resources/data/selectors';
import { RequestStatus } from './data/constants';
import Loading from './generic/Loading';

const AppHeader = ({
courseNumber, courseOrg, courseTitle, courseId,
}) => (
<Header
courseNumber={courseNumber}
courseOrg={courseOrg}
courseTitle={courseTitle}
courseId={courseId}
/>
);

AppHeader.propTypes = {
courseId: PropTypes.string.isRequired,
courseNumber: PropTypes.string,
courseOrg: PropTypes.string,
courseTitle: PropTypes.string.isRequired,
};

AppHeader.defaultProps = {
courseNumber: null,
courseOrg: null,
};

const CourseAuthoringPage = ({ courseId, children }) => {
const dispatch = useDispatch();

Expand Down Expand Up @@ -74,11 +51,11 @@ const CourseAuthoringPage = ({ courseId, children }) => {
This functionality will be removed in TNL-9591 */}
{inProgress ? !isEditor && <Loading />
: (!isEditor && (
<AppHeader
courseNumber={courseNumber}
courseOrg={courseOrg}
courseTitle={courseTitle}
courseId={courseId}
<Header
number={courseNumber}
org={courseOrg}
title={courseTitle}
contentId={courseId}
/>
)
)}
Expand Down
50 changes: 50 additions & 0 deletions src/generic/toast-context/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* eslint-disable react/prop-types */
// @ts-check
import { Toast } from '@openedx/paragon';
import React from 'react';

/**
* Global context to keep track of popup message(s) that appears to user after
* they take an action like creating or deleting something.
*/
export const ToastContext = React.createContext({
toastMessage: /** @type{null|string} */ (null),
showToast: /** @type{function} */ (() => {}),
closeToast: /** @type{function} */ (() => {}),

Check warning on line 13 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L13

Added line #L13 was not covered by tests
});

/**
* React component to provide `ToastContext` to the app
* @param {{children?: React.ReactNode}} props The components to wrap
*/
export const ToastProvider = (props) => {
// TODO, We can convert this to a queue of messages,
// see: https://github.com/open-craft/frontend-app-course-authoring/pull/38#discussion_r1638990647

const [toastMessage, setToastMessage] = React.useState(/** @type{null|string} */ (null));

Check warning on line 24 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L24

Added line #L24 was not covered by tests

React.useEffect(() => () => {

Check warning on line 26 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L26

Added line #L26 was not covered by tests
// Cleanup function to avoid updating state on unmounted component
setToastMessage(null);

Check warning on line 28 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L28

Added line #L28 was not covered by tests
}, []);

const showToast = React.useCallback((message) => setToastMessage(message), [setToastMessage]);
const closeToast = React.useCallback(() => setToastMessage(null), [setToastMessage]);

Check warning on line 32 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L31-L32

Added lines #L31 - L32 were not covered by tests

const context = React.useMemo(() => ({

Check warning on line 34 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L34

Added line #L34 was not covered by tests
toastMessage,
showToast,
closeToast,
}), [toastMessage, showToast, closeToast]);

return (

Check warning on line 40 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L40

Added line #L40 was not covered by tests
<ToastContext.Provider value={context}>
{props.children}
{ toastMessage && (
<Toast show={toastMessage !== null} onClose={closeToast}>

Check warning on line 44 in src/generic/toast-context/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/toast-context/index.jsx#L44

Added line #L44 was not covered by tests
{toastMessage}
</Toast>
)}
</ToastContext.Provider>
);
};
51 changes: 27 additions & 24 deletions src/header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,58 @@ import { useIntl } from '@edx/frontend-platform/i18n';
import { StudioHeader } from '@edx/frontend-component-header';
import { useToggle } from '@openedx/paragon';

import SearchModal from '../search-modal/SearchModal';
import { SearchModal } from '../search-modal';
import { getContentMenuItems, getSettingMenuItems, getToolsMenuItems } from './utils';
import messages from './messages';

const Header = ({
courseId,
courseOrg,
courseNumber,
courseTitle,
contentId,
org,
number,
title,
isHiddenMainMenu,
isLibrary,
}) => {
const intl = useIntl();

const [isShowSearchModalOpen, openSearchModal, closeSearchModal] = useToggle(false);

const studioBaseUrl = getConfig().STUDIO_BASE_URL;
const meiliSearchEnabled = [true, 'true'].includes(getConfig().MEILISEARCH_ENABLED);
const mainMenuDropdowns = [
const mainMenuDropdowns = !isLibrary ? [
{
id: `${intl.formatMessage(messages['header.links.content'])}-dropdown-menu`,
buttonTitle: intl.formatMessage(messages['header.links.content']),
items: getContentMenuItems({ studioBaseUrl, courseId, intl }),
items: getContentMenuItems({ studioBaseUrl, courseId: contentId, intl }),
},
{
id: `${intl.formatMessage(messages['header.links.settings'])}-dropdown-menu`,
buttonTitle: intl.formatMessage(messages['header.links.settings']),
items: getSettingMenuItems({ studioBaseUrl, courseId, intl }),
items: getSettingMenuItems({ studioBaseUrl, courseId: contentId, intl }),
},
{
id: `${intl.formatMessage(messages['header.links.tools'])}-dropdown-menu`,
buttonTitle: intl.formatMessage(messages['header.links.tools']),
items: getToolsMenuItems({ studioBaseUrl, courseId, intl }),
items: getToolsMenuItems({ studioBaseUrl, courseId: contentId, intl }),
},
];
const outlineLink = `${studioBaseUrl}/course/${courseId}`;
] : [];
const outlineLink = !isLibrary ? `${studioBaseUrl}/course/${contentId}` : `/course-authoring/library/${contentId}`;

return (
<>
<StudioHeader
org={courseOrg}
number={courseNumber}
title={courseTitle}
org={org}
number={number}
title={title}
isHiddenMainMenu={isHiddenMainMenu}
mainMenuDropdowns={mainMenuDropdowns}
outlineLink={outlineLink}
searchButtonAction={meiliSearchEnabled && openSearchModal}
searchButtonAction={meiliSearchEnabled ? openSearchModal : undefined}
/>
{ meiliSearchEnabled && (
<SearchModal
isOpen={isShowSearchModalOpen}
courseId={courseId}
courseId={isLibrary ? undefined : contentId}
onClose={closeSearchModal}
/>
)}
Expand All @@ -65,19 +66,21 @@ const Header = ({
};

Header.propTypes = {
courseId: PropTypes.string,
courseNumber: PropTypes.string,
courseOrg: PropTypes.string,
courseTitle: PropTypes.string,
contentId: PropTypes.string,
number: PropTypes.string,
org: PropTypes.string,
title: PropTypes.string,
isHiddenMainMenu: PropTypes.bool,
isLibrary: PropTypes.bool,
};

Header.defaultProps = {
courseId: '',
courseNumber: '',
courseOrg: '',
courseTitle: '',
contentId: '',
number: '',
org: '',
title: '',
isHiddenMainMenu: false,
isLibrary: false,
};

export default Header;
16 changes: 10 additions & 6 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ import { initializeHotjar } from '@edx/frontend-enterprise-hotjar';
import { logError } from '@edx/frontend-platform/logging';
import messages from './i18n';

import { CreateLibrary, LibraryLayout } from './library-authoring';
import initializeStore from './store';
import CourseAuthoringRoutes from './CourseAuthoringRoutes';
import Head from './head/Head';
import { StudioHome } from './studio-home';
import LibraryV2Placeholder from './studio-home/tabs-section/LibraryV2Placeholder';
import CourseRerun from './course-rerun';
import { TaxonomyLayout, TaxonomyDetailPage, TaxonomyListPage } from './taxonomy';
import { ContentTagsDrawer } from './content-tags-drawer';
import AccessibilityPage from './accessibility-page';
import { ToastProvider } from './generic/toast-context';

import 'react-datepicker/dist/react-datepicker.css';
import './index.scss';
Expand Down Expand Up @@ -55,7 +56,8 @@ const App = () => {
<Route path="/home" element={<StudioHome />} />
<Route path="/libraries" element={<StudioHome />} />
<Route path="/libraries-v1" element={<StudioHome />} />
<Route path="/library/:libraryId" element={<LibraryV2Placeholder />} />
<Route path="/library/create" element={<CreateLibrary />} />
<Route path="/library/:libraryId/*" element={<LibraryLayout />} />
<Route path="/course/:courseId/*" element={<CourseAuthoringRoutes />} />
<Route path="/course_rerun/:courseId" element={<CourseRerun />} />
{getConfig().ENABLE_ACCESSIBILITY_PAGE === 'true' && (
Expand Down Expand Up @@ -84,10 +86,12 @@ const App = () => {

return (
<AppProvider store={initializeStore()} wrapWithRouter={false}>
<QueryClientProvider client={queryClient}>
<Head />
<RouterProvider router={router} />
</QueryClientProvider>
<ToastProvider>
<QueryClientProvider client={queryClient}>
<Head />
<RouterProvider router={router} />
</QueryClientProvider>
</ToastProvider>
</AppProvider>
);
};
Expand Down
27 changes: 27 additions & 0 deletions src/library-authoring/CreateLibrary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { Container } from '@openedx/paragon';

import Header from '../header';
import SubHeader from '../generic/sub-header/SubHeader';

import messages from './messages';

/* istanbul ignore next This is only a placeholder component */
const CreateLibrary = () => (
<>
<Header isHiddenMainMenu />
<Container size="xl" className="p-4 mt-3">
<SubHeader
title={<FormattedMessage {...messages.createLibrary} />}
/>
<div className="d-flex my-6 justify-content-center">
<FormattedMessage
{...messages.createLibraryTempPlaceholder}
/>
</div>
</Container>
</>
);

export default CreateLibrary;
27 changes: 27 additions & 0 deletions src/library-authoring/EmptyStates.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useContext } from 'react';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import {
Button, Stack,
} from '@openedx/paragon';
import { Add } from '@openedx/paragon/icons';
import messages from './messages';
import { LibraryContext } from './common/context';

export const NoComponents = () => {
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>
</Stack>
);
};

export const NoSearchResults = () => (
<div className="d-flex mt-6 justify-content-center">
<FormattedMessage {...messages.noSearchResults} />
</div>
);
Loading
Loading