* Add flow in course outline sidebar. Allows author to add new section/subsection/unit or any container from existing libraries via sidebar. * Adds library dropdown filter and collections dropdown filter in add sidebar. Allows authors to filter containers by selected libraries and collections.
149 lines
5.2 KiB
TypeScript
149 lines
5.2 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { getConfig } from '@edx/frontend-platform';
|
|
import { useIntl } from '@edx/frontend-platform/i18n';
|
|
import { Collapsible, Icon, Stack } from '@openedx/paragon';
|
|
import {
|
|
BookOpen, ExpandLess, ExpandMore, Tag,
|
|
} from '@openedx/paragon/icons';
|
|
|
|
import { useOptionalLibraryContext } from '../common/context/LibraryContext';
|
|
import { SidebarActions, useSidebarContext } from '../common/context/SidebarContext';
|
|
import { ContentTagsDrawer, useContentTaxonomyTagsData } from '../../content-tags-drawer';
|
|
import { useLibraryBlockMetadata, useUpdateComponentCollections } from '../data/apiHooks';
|
|
import StatusWidget from '../generic/status-widget';
|
|
import { ManageCollections } from '../generic/manage-collections';
|
|
import messages from './messages';
|
|
|
|
const ComponentManagement = () => {
|
|
const intl = useIntl();
|
|
const { readOnly, isLoadingLibraryData } = useOptionalLibraryContext();
|
|
const { sidebarItemInfo, sidebarAction, resetSidebarAction } = useSidebarContext();
|
|
const jumpToCollections = sidebarAction === SidebarActions.JumpToManageCollections;
|
|
const jumpToTags = sidebarAction === SidebarActions.JumpToManageTags;
|
|
const [tagsCollapseIsOpen, setTagsCollapseOpen] = React.useState(!jumpToCollections);
|
|
const [collectionsCollapseIsOpen, setCollectionsCollapseOpen] = React.useState(true);
|
|
|
|
useEffect(() => {
|
|
if (jumpToCollections) {
|
|
setTagsCollapseOpen(false);
|
|
setCollectionsCollapseOpen(true);
|
|
} else if (jumpToTags) {
|
|
setTagsCollapseOpen(true);
|
|
setCollectionsCollapseOpen(false);
|
|
}
|
|
}, [jumpToCollections, jumpToTags]);
|
|
|
|
useEffect(() => {
|
|
// This is required to redo actions.
|
|
if (tagsCollapseIsOpen || !collectionsCollapseIsOpen) {
|
|
resetSidebarAction();
|
|
}
|
|
}, [tagsCollapseIsOpen, collectionsCollapseIsOpen]);
|
|
|
|
const usageKey = sidebarItemInfo?.id;
|
|
// istanbul ignore if: this should never happen
|
|
if (!usageKey) {
|
|
throw new Error('usageKey is required');
|
|
}
|
|
|
|
const { data: componentMetadata } = useLibraryBlockMetadata(usageKey);
|
|
const { data: componentTags } = useContentTaxonomyTagsData(usageKey);
|
|
|
|
const collectionsCount = React.useMemo(() => componentMetadata?.collections?.length || 0, [componentMetadata]);
|
|
const tagsCount = React.useMemo(() => {
|
|
if (!componentTags) {
|
|
return 0;
|
|
}
|
|
let result = 0;
|
|
componentTags.taxonomies.forEach((taxonomy) => {
|
|
const countedTags : string[] = [];
|
|
taxonomy.tags.forEach((tagData) => {
|
|
tagData.lineage.forEach((tag) => {
|
|
if (!countedTags.includes(tag)) {
|
|
result += 1;
|
|
countedTags.push(tag);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
return result;
|
|
}, [componentTags]);
|
|
|
|
// istanbul ignore if: this should never happen
|
|
if (isLoadingLibraryData) {
|
|
return null;
|
|
}
|
|
|
|
// istanbul ignore if: this should never happen
|
|
if (!componentMetadata) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Stack gap={3}>
|
|
<StatusWidget
|
|
{...componentMetadata}
|
|
/>
|
|
{[true, 'true'].includes(getConfig().ENABLE_TAGGING_TAXONOMY_PAGES)
|
|
&& (
|
|
<Collapsible.Advanced
|
|
open={tagsCollapseIsOpen}
|
|
className="collapsible-card border-0"
|
|
>
|
|
<Collapsible.Trigger
|
|
onClick={() => setTagsCollapseOpen((prev) => !prev)}
|
|
className="collapsible-trigger d-flex justify-content-between p-2"
|
|
>
|
|
<Stack gap={1} direction="horizontal">
|
|
<Icon src={Tag} />
|
|
{intl.formatMessage(messages.manageTabTagsTitle, { count: tagsCount })}
|
|
</Stack>
|
|
<Collapsible.Visible whenClosed>
|
|
<Icon src={ExpandMore} />
|
|
</Collapsible.Visible>
|
|
<Collapsible.Visible whenOpen>
|
|
<Icon src={ExpandLess} />
|
|
</Collapsible.Visible>
|
|
</Collapsible.Trigger>
|
|
<Collapsible.Body className="collapsible-body">
|
|
<ContentTagsDrawer
|
|
id={usageKey}
|
|
variant="component"
|
|
readOnly={readOnly}
|
|
/>
|
|
</Collapsible.Body>
|
|
</Collapsible.Advanced>
|
|
)}
|
|
<Collapsible.Advanced
|
|
open={collectionsCollapseIsOpen}
|
|
className="collapsible-card border-0"
|
|
>
|
|
<Collapsible.Trigger
|
|
onClick={() => setCollectionsCollapseOpen((prev) => !prev)}
|
|
className="collapsible-trigger d-flex justify-content-between p-2"
|
|
>
|
|
<Stack gap={1} direction="horizontal">
|
|
<Icon src={BookOpen} />
|
|
{intl.formatMessage(messages.manageTabCollectionsTitle, { count: collectionsCount })}
|
|
</Stack>
|
|
<Collapsible.Visible whenClosed>
|
|
<Icon src={ExpandMore} />
|
|
</Collapsible.Visible>
|
|
<Collapsible.Visible whenOpen>
|
|
<Icon src={ExpandLess} />
|
|
</Collapsible.Visible>
|
|
</Collapsible.Trigger>
|
|
<Collapsible.Body className="collapsible-body">
|
|
<ManageCollections
|
|
opaqueKey={usageKey}
|
|
collections={componentMetadata.collections}
|
|
useUpdateCollectionsHook={useUpdateComponentCollections}
|
|
/>
|
|
</Collapsible.Body>
|
|
</Collapsible.Advanced>
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
export default ComponentManagement;
|