diff --git a/packages/asset-collections/src/components/AddTagButton.tsx b/packages/asset-collections/src/components/AddTagButton.tsx index 8152764a2..1554a47bb 100644 --- a/packages/asset-collections/src/components/AddTagButton.tsx +++ b/packages/asset-collections/src/components/AddTagButton.tsx @@ -6,6 +6,7 @@ import { Button, Icon } from '@neos-project/react-ui-components'; import { useIntl } from '@media-ui/core'; import { useConfigQuery } from '@media-ui/core/src/hooks'; import { createTagDialogState, selectedTagIdState } from '@media-ui/feature-asset-tags'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import classes from './AddTagButton.module.css'; @@ -13,7 +14,8 @@ const AddTagButton: React.FC = () => { const { translate } = useIntl(); const { config } = useConfigQuery(); const setCreateTagDialogState = useSetRecoilState(createTagDialogState); - const selectedTagId = useRecoilValue(selectedTagIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectedTagId = useRecoilValue(selectedTagIdState(assetSourceId)); const onClickCreate = useCallback(() => { setCreateTagDialogState({ diff --git a/packages/asset-collections/src/components/AssetCollectionTreeNode.tsx b/packages/asset-collections/src/components/AssetCollectionTreeNode.tsx index 88b05259e..035849227 100644 --- a/packages/asset-collections/src/components/AssetCollectionTreeNode.tsx +++ b/packages/asset-collections/src/components/AssetCollectionTreeNode.tsx @@ -7,7 +7,7 @@ import dndTypes from '@media-ui/core/src/constants/dndTypes'; import { selectedAssetCollectionAndTagState } from '@media-ui/core/src/state'; import { IconStack } from '@media-ui/core/src/components'; import { useConfigQuery } from '@media-ui/core/src/hooks'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import TagTreeNode from './TagTreeNode'; import { useAssetCollectionQuery, UNASSIGNED_COLLECTION_ID } from '../hooks/useAssetCollectionQuery'; @@ -33,14 +33,14 @@ const AssetCollectionTreeNode: React.FC = ({ renderChildCollections = true, }) => { const { config } = useConfigQuery(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); - const { assetCollection } = useAssetCollectionQuery(assetCollectionId, selectedAssetSourceId); - const { assetCollections } = useAssetCollectionsQuery(selectedAssetSourceId); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const { assetCollection } = useAssetCollectionQuery(assetCollectionId, assetSourceId); + const { assetCollections } = useAssetCollectionsQuery(assetSourceId); const [collapsed, setCollapsed] = useRecoilState(assetCollectionTreeCollapsedItemState(assetCollectionId)); - const selectAssetCollectionAndTag = useSetRecoilState(selectedAssetCollectionAndTagState); - const isFocused = useRecoilValue(assetCollectionFocusedState(assetCollectionId)); + const selectAssetCollectionAndTag = useSetRecoilState(selectedAssetCollectionAndTagState(assetSourceId)); + const isFocused = useRecoilValue(assetCollectionFocusedState({ assetCollectionId, assetSourceId })); const isFavourite = useRecoilValue(assetCollectionFavouriteState(assetCollectionId)); - const isActive = useRecoilValue(assetCollectionActiveState(assetCollectionId)); + const isActive = useRecoilValue(assetCollectionActiveState({ assetCollectionId, assetSourceId })); const { currentlyDraggedNodes, handeEndDrag, handleDrag, handleDrop, acceptsDraggedNode } = useAssetCollectionDnd(); diff --git a/packages/asset-collections/src/components/DeleteButton.tsx b/packages/asset-collections/src/components/DeleteButton.tsx index 44053a7ba..957fc7f7e 100644 --- a/packages/asset-collections/src/components/DeleteButton.tsx +++ b/packages/asset-collections/src/components/DeleteButton.tsx @@ -7,7 +7,7 @@ import { useIntl, useMediaUi, useNotify } from '@media-ui/core'; import { useConfigQuery } from '@media-ui/core/src/hooks'; import { selectedAssetCollectionAndTagState } from '@media-ui/core/src/state'; import { useDeleteTag, useSelectedTag } from '@media-ui/feature-asset-tags'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import useDeleteAssetCollection from '../hooks/useDeleteAssetCollection'; import useSelectedAssetCollection from '../hooks/useSelectedAssetCollection'; @@ -17,12 +17,14 @@ const DeleteButton: React.FC = () => { const { config } = useConfigQuery(); const Notify = useNotify(); const { approvalAttainmentStrategy } = useMediaUi(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const selectedAssetCollection = useSelectedAssetCollection(); const selectedTag = useSelectedTag(); const { deleteTag } = useDeleteTag(); const { deleteAssetCollection } = useDeleteAssetCollection(); - const setSelectedAssetCollectionAndTag = useSetRecoilState(selectedAssetCollectionAndTagState); + const setSelectedAssetCollectionAndTag = useSetRecoilState( + selectedAssetCollectionAndTagState(selectedAssetSourceId) + ); const onClickDelete = useCallback(async () => { if (selectedTag) { diff --git a/packages/asset-collections/src/components/FavouriteButton.tsx b/packages/asset-collections/src/components/FavouriteButton.tsx index e4846d64c..d0910e6c7 100644 --- a/packages/asset-collections/src/components/FavouriteButton.tsx +++ b/packages/asset-collections/src/components/FavouriteButton.tsx @@ -7,10 +7,12 @@ import { useIntl } from '@media-ui/core'; import { selectedAssetCollectionIdState } from '../state/selectedAssetCollectionIdState'; import { assetCollectionFavouriteState } from '../state/assetCollectionFavouritesState'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; const FavouriteButton: React.FC = () => { const { translate } = useIntl(); - const selectedAssetCollectionId = useRecoilValue(selectedAssetCollectionIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectedAssetCollectionId = useRecoilValue(selectedAssetCollectionIdState(assetSourceId)); const [isFavourite, setIsFavourite] = useRecoilState(assetCollectionFavouriteState(selectedAssetCollectionId)); const toggleFavourite = useCallback(() => { diff --git a/packages/asset-collections/src/components/TagTreeNode.tsx b/packages/asset-collections/src/components/TagTreeNode.tsx index da9286728..359938b07 100644 --- a/packages/asset-collections/src/components/TagTreeNode.tsx +++ b/packages/asset-collections/src/components/TagTreeNode.tsx @@ -7,6 +7,7 @@ import dndTypes from '@media-ui/core/src/constants/dndTypes'; import { selectedAssetCollectionAndTagState } from '@media-ui/core/src/state'; import { selectedAssetCollectionIdState } from '@media-ui/feature-asset-collections'; import { selectedTagIdState } from '@media-ui/feature-asset-tags'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; export interface TagTreeNodeProps extends TreeNodeProps { tagId: string; @@ -18,12 +19,16 @@ export interface TagTreeNodeProps extends TreeNodeProps { } // This state selector provides the focused state for each individual asset collection -const tagFocusedState = selectorFamily({ +const tagFocusedState = selectorFamily< + boolean, + { assetCollectionId: string; tagId: string; assetSourceId: AssetSourceId } +>({ key: 'TagFocusedState', get: - ({ assetCollectionId, tagId }) => + ({ assetCollectionId, tagId, assetSourceId }) => ({ get }) => - get(selectedAssetCollectionIdState) === assetCollectionId && get(selectedTagIdState) === tagId, + get(selectedAssetCollectionIdState(assetSourceId)) === assetCollectionId && + get(selectedTagIdState(assetSourceId)) === tagId, }); const TagTreeNode: React.FC = ({ @@ -34,8 +39,9 @@ const TagTreeNode: React.FC = ({ icon = 'tag', customIconComponent, }: TagTreeNodeProps) => { - const selectAssetCollectionAndTag = useSetRecoilState(selectedAssetCollectionAndTagState); - const isFocused = useRecoilValue(tagFocusedState({ assetCollectionId, tagId })); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectAssetCollectionAndTag = useSetRecoilState(selectedAssetCollectionAndTagState(assetSourceId)); + const isFocused = useRecoilValue(tagFocusedState({ assetCollectionId, tagId, assetSourceId })); return ( diff --git a/packages/asset-collections/src/hooks/useSelectedAssetCollection.ts b/packages/asset-collections/src/hooks/useSelectedAssetCollection.ts index 2b0541f4b..25695eec4 100644 --- a/packages/asset-collections/src/hooks/useSelectedAssetCollection.ts +++ b/packages/asset-collections/src/hooks/useSelectedAssetCollection.ts @@ -1,6 +1,8 @@ import { useRecoilValue } from 'recoil'; import { useQuery } from '@apollo/client'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; + import { selectedAssetCollectionIdState } from '../state/selectedAssetCollectionIdState'; import { ASSET_COLLECTION } from '../queries/assetCollection'; @@ -10,8 +12,8 @@ interface AssetCollectionQueryResult { } const useSelectedAssetCollection = (): AssetCollection => { - const assetSourceId = useRecoilValue(selectedAssetCollectionIdState); - const selectedAssetCollectionId = useRecoilValue(selectedAssetCollectionIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectedAssetCollectionId = useRecoilValue(selectedAssetCollectionIdState(assetSourceId)); const { data } = useQuery(ASSET_COLLECTION, { variables: { id: selectedAssetCollectionId, assetSourceId }, diff --git a/packages/asset-collections/src/provider/AssetCollectionTreeDndProvider.tsx b/packages/asset-collections/src/provider/AssetCollectionTreeDndProvider.tsx index 6a05f0b7e..a3b59fb76 100644 --- a/packages/asset-collections/src/provider/AssetCollectionTreeDndProvider.tsx +++ b/packages/asset-collections/src/provider/AssetCollectionTreeDndProvider.tsx @@ -4,7 +4,7 @@ import HTML5Backend from 'react-dnd-html5-backend'; import { useRecoilValue } from 'recoil'; import { useIntl, useNotify } from '@media-ui/core'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { useSetAssetCollectionParent } from '../hooks/useSetAssetCollectionParent'; import useAssetCollectionsQuery from '../hooks/useAssetCollectionsQuery'; @@ -29,7 +29,7 @@ export const useAssetCollectionDnd = (): AssetCollectionTreeDndProviderValues => export function AssetCollectionTreeDndProvider({ children }: AssetCollectionTreeDndProviderProps) { const { translate } = useIntl(); const Notify = useNotify(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const { assetCollections } = useAssetCollectionsQuery(selectedAssetSourceId); const [currentlyDraggedNodes, setCurrentlyDraggedNodes] = useState([]); const { setAssetCollectionParent } = useSetAssetCollectionParent(); diff --git a/packages/asset-collections/src/state/assetCollectionActiveState.ts b/packages/asset-collections/src/state/assetCollectionActiveState.ts index 90b2607c9..a81258026 100644 --- a/packages/asset-collections/src/state/assetCollectionActiveState.ts +++ b/packages/asset-collections/src/state/assetCollectionActiveState.ts @@ -3,13 +3,16 @@ import { selectorFamily } from 'recoil'; import { selectedAssetCollectionAndTagState } from '@media-ui/core/src/state'; // This state selector provides the active state for each individual asset collection based on its tags -export const assetCollectionActiveState = selectorFamily({ +export const assetCollectionActiveState = selectorFamily< + boolean, + { assetCollectionId: AssetCollectionId; assetSourceId: AssetSourceId } +>({ key: 'AssetCollectionActiveState', get: - (assetCollectionId) => + ({ assetCollectionId, assetSourceId }) => ({ get }) => { const { assetCollectionId: selectedAssetCollectionId, tagId: selectedTagId } = get( - selectedAssetCollectionAndTagState + selectedAssetCollectionAndTagState(assetSourceId) ); return assetCollectionId === selectedAssetCollectionId && !!selectedTagId; }, diff --git a/packages/asset-collections/src/state/assetCollectionFocusedState.ts b/packages/asset-collections/src/state/assetCollectionFocusedState.ts index 55e69fb73..cc8f4a81a 100644 --- a/packages/asset-collections/src/state/assetCollectionFocusedState.ts +++ b/packages/asset-collections/src/state/assetCollectionFocusedState.ts @@ -3,10 +3,13 @@ import { selectorFamily } from 'recoil'; import { selectedAssetCollectionIdState } from './selectedAssetCollectionIdState'; // This state selector provides the focused state for each individual asset collection -export const assetCollectionFocusedState = selectorFamily({ +export const assetCollectionFocusedState = selectorFamily< + boolean, + { assetCollectionId: AssetCollectionId; assetSourceId: AssetSourceId } +>({ key: 'AssetCollectionFocusedState', get: - (assetCollectionId) => + ({ assetCollectionId, assetSourceId }) => ({ get }) => - get(selectedAssetCollectionIdState) === assetCollectionId, + get(selectedAssetCollectionIdState(assetSourceId)) === assetCollectionId, }); diff --git a/packages/asset-collections/src/state/selectedAssetCollectionIdState.ts b/packages/asset-collections/src/state/selectedAssetCollectionIdState.ts index f9359e0f6..32c2fe7eb 100644 --- a/packages/asset-collections/src/state/selectedAssetCollectionIdState.ts +++ b/packages/asset-collections/src/state/selectedAssetCollectionIdState.ts @@ -1,7 +1,7 @@ -import { atom } from 'recoil'; +import { atomFamily } from 'recoil'; import { localStorageEffect } from '@media-ui/core/src/state'; -export const selectedAssetCollectionIdState = atom({ +export const selectedAssetCollectionIdState = atomFamily({ key: 'SelectedAssetCollectionIdState', default: null, effects: [localStorageEffect('SelectedAssetCollectionIdState')], diff --git a/packages/asset-sources/src/components/AssetSourceList.tsx b/packages/asset-sources/src/components/AssetSourceList.tsx index 8e7ee2edd..18b21874b 100644 --- a/packages/asset-sources/src/components/AssetSourceList.tsx +++ b/packages/asset-sources/src/components/AssetSourceList.tsx @@ -9,7 +9,7 @@ import { IconLabel } from '@media-ui/core/src/components'; import { selectedAssetIdState } from '@media-ui/core/src/state'; import { selectedAssetCollectionIdState } from '@media-ui/feature-asset-collections'; -import { selectedAssetSourceState } from '../state/selectedAssetSourceState'; +import { selectedAssetSourceIdState } from '../state/selectedAssetSourceIdState'; import { useAssetSourcesQuery } from '../hooks/useAssetSourcesQuery'; import classes from './AssetSourceList.module.css'; @@ -17,9 +17,9 @@ import classes from './AssetSourceList.module.css'; const AssetSourceList: React.FC = () => { const { assetSources } = useAssetSourcesQuery(); const { translate } = useIntl(); - const [selectedAssetSourceId, setSelectedAssetSourceId] = useRecoilState(selectedAssetSourceState); + const [selectedAssetSourceId, setSelectedAssetSourceId] = useRecoilState(selectedAssetSourceIdState); const setSelectedAsset = useSetRecoilState(selectedAssetIdState); - const setSelectedAssetCollection = useSetRecoilState(selectedAssetCollectionIdState); + const setSelectedAssetCollection = useSetRecoilState(selectedAssetCollectionIdState(selectedAssetSourceId)); const chooseSelectedAssetSource = useCallback( (assetSourceId: AssetSourceId) => { diff --git a/packages/asset-sources/src/hooks/useSelectedAssetSource.ts b/packages/asset-sources/src/hooks/useSelectedAssetSource.ts index c7b6f0a95..cc15bfc7a 100644 --- a/packages/asset-sources/src/hooks/useSelectedAssetSource.ts +++ b/packages/asset-sources/src/hooks/useSelectedAssetSource.ts @@ -2,10 +2,10 @@ import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { useAssetSourcesQuery } from './useAssetSourcesQuery'; -import { selectedAssetSourceState } from '../state/selectedAssetSourceState'; +import { selectedAssetSourceIdState } from '../state/selectedAssetSourceIdState'; export const useSelectedAssetSource = (): AssetSource => { - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const { assetSources } = useAssetSourcesQuery(); return useMemo( () => assetSources.find((assetSource) => assetSource.id === selectedAssetSourceId), diff --git a/packages/asset-sources/src/index.ts b/packages/asset-sources/src/index.ts index 447fb58e0..8442963e6 100644 --- a/packages/asset-sources/src/index.ts +++ b/packages/asset-sources/src/index.ts @@ -3,4 +3,4 @@ export { default as AssetSourceList } from './components/AssetSourceList'; export { ASSET_SOURCE_FRAGMENT } from './fragments/assetSource'; export { useAssetSourcesQuery } from './hooks/useAssetSourcesQuery'; export { useSelectedAssetSource } from './hooks/useSelectedAssetSource'; -export { selectedAssetSourceState, NEOS_ASSET_SOURCE } from './state/selectedAssetSourceState'; +export { selectedAssetSourceIdState, NEOS_ASSET_SOURCE } from './state/selectedAssetSourceIdState'; diff --git a/packages/asset-sources/src/state/selectedAssetSourceState.ts b/packages/asset-sources/src/state/selectedAssetSourceIdState.ts similarity index 69% rename from packages/asset-sources/src/state/selectedAssetSourceState.ts rename to packages/asset-sources/src/state/selectedAssetSourceIdState.ts index 45fc0fb9b..65f306cdb 100644 --- a/packages/asset-sources/src/state/selectedAssetSourceState.ts +++ b/packages/asset-sources/src/state/selectedAssetSourceIdState.ts @@ -5,16 +5,19 @@ import { clipboardVisibleState } from '@media-ui/feature-clipboard'; export const NEOS_ASSET_SOURCE = 'neos'; -const selectedAssetSourceIdState = atom({ - key: 'SelectedAssetSourceIdState', +const selectedAssetSourceIdInternalState = atom({ + key: 'SelectedAssetSourceIdInternalState', default: NEOS_ASSET_SOURCE, effects: [localStorageEffect('SelectedAssetSourceIdState')], }); -export const selectedAssetSourceState = selector({ - key: 'SelectedAssetSourceState', +/** + * Provides the selected asset source id with a fallback based on the constraints + */ +export const selectedAssetSourceIdState = selector({ + key: 'SelectedAssetSourceIdState', get: ({ get }) => { - const selectedAssetSourceId = get(selectedAssetSourceIdState); + const selectedAssetSourceId = get(selectedAssetSourceIdInternalState); const constraints = get(constraintsState); if (constraints.assetSources?.length > 0 && !constraints.assetSources.includes(selectedAssetSourceId)) { @@ -23,7 +26,7 @@ export const selectedAssetSourceState = selector({ return selectedAssetSourceId; }, set: ({ set }, newValue) => { - set(selectedAssetSourceIdState, newValue); + set(selectedAssetSourceIdInternalState, newValue); // Reset the current page to 1 when switching asset sources set(currentPageState, 1); // Hide the clipboard when switching asset sources diff --git a/packages/asset-tags/src/components/CreateTagDialog.tsx b/packages/asset-tags/src/components/CreateTagDialog.tsx index d46f1927a..5b382be6d 100644 --- a/packages/asset-tags/src/components/CreateTagDialog.tsx +++ b/packages/asset-tags/src/components/CreateTagDialog.tsx @@ -12,12 +12,12 @@ import { Dialog } from '@media-ui/core/src/components'; import createTagDialogState from '../state/createTagDialogState'; import classes from './CreateTagDialog.module.css'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; const CreateTagDialog: React.FC = () => { const { translate } = useIntl(); const Notify = useNotify(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const selectedAssetCollection = useSelectedAssetCollection(); const [dialogState, setDialogState] = useRecoilState(createTagDialogState); const { createTag } = useCreateTag(); diff --git a/packages/asset-tags/src/hooks/useDeleteTag.ts b/packages/asset-tags/src/hooks/useDeleteTag.ts index 47920d0ed..8af1c31f0 100644 --- a/packages/asset-tags/src/hooks/useDeleteTag.ts +++ b/packages/asset-tags/src/hooks/useDeleteTag.ts @@ -1,7 +1,8 @@ import { useMutation } from '@apollo/client'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { ASSET_COLLECTIONS } from '@media-ui/feature-asset-collections'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import selectedTagIdState from '../state/selectedTagIdState'; import TAGS from '../queries/tags'; @@ -14,7 +15,8 @@ interface DeleteTagVariables { export default function useDeleteTag() { const [action, { error, data }] = useMutation<{ deleteTag: MutationResult }, DeleteTagVariables>(DELETE_TAG); - const [selectedTagId, setSelectedTagId] = useRecoilState(selectedTagIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const [selectedTagId, setSelectedTagId] = useRecoilState(selectedTagIdState(assetSourceId)); const deleteTag = (id: TagId, assetSourceId: AssetSourceId) => action({ diff --git a/packages/asset-tags/src/hooks/useSelectedTag.ts b/packages/asset-tags/src/hooks/useSelectedTag.ts index d8e751f8a..c5dbb46c6 100644 --- a/packages/asset-tags/src/hooks/useSelectedTag.ts +++ b/packages/asset-tags/src/hooks/useSelectedTag.ts @@ -3,7 +3,7 @@ import { useQuery } from '@apollo/client'; import selectedTagIdState from '../state/selectedTagIdState'; import TAG from '../queries/tag'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; interface TagQueryResult { tag: Tag; @@ -11,8 +11,8 @@ interface TagQueryResult { } const useSelectedTag = (): Tag => { - const assetSourceId = useRecoilValue(selectedAssetSourceState); - const selectedTagId = useRecoilValue(selectedTagIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectedTagId = useRecoilValue(selectedTagIdState(assetSourceId)); const { data } = useQuery(TAG, { variables: { id: selectedTagId, assetSourceId }, diff --git a/packages/asset-tags/src/state/selectedTagIdState.ts b/packages/asset-tags/src/state/selectedTagIdState.ts index 39b8ddbbd..f7fa46442 100644 --- a/packages/asset-tags/src/state/selectedTagIdState.ts +++ b/packages/asset-tags/src/state/selectedTagIdState.ts @@ -1,7 +1,7 @@ -import { atom } from 'recoil'; +import { atomFamily } from 'recoil'; import { localStorageEffect } from '@media-ui/core/src/state'; -const selectedTagIdState = atom({ +const selectedTagIdState = atomFamily({ key: 'SelectedTagIdState', default: null, effects: [localStorageEffect('SelectedTagIdState')], diff --git a/packages/asset-upload/src/hooks/useUploadFile.ts b/packages/asset-upload/src/hooks/useUploadFile.ts index dfefe3615..be8cb10ba 100644 --- a/packages/asset-upload/src/hooks/useUploadFile.ts +++ b/packages/asset-upload/src/hooks/useUploadFile.ts @@ -3,13 +3,15 @@ import { useRecoilValue } from 'recoil'; import { selectedTagIdState } from '@media-ui/feature-asset-tags'; import { selectedAssetCollectionIdState } from '@media-ui/feature-asset-collections'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { UPLOAD_FILE } from '../mutations'; export default function useUploadFile() { const [action, { error, data, loading }] = useMutation<{ uploadFile: FileUploadResult }>(UPLOAD_FILE); - const tagId = useRecoilValue(selectedTagIdState); - const assetCollectionId = useRecoilValue(selectedAssetCollectionIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const tagId = useRecoilValue(selectedTagIdState(assetSourceId)); + const assetCollectionId = useRecoilValue(selectedAssetCollectionIdState(assetSourceId)); const uploadFile = (file: File) => action({ diff --git a/packages/asset-upload/src/hooks/useUploadFiles.ts b/packages/asset-upload/src/hooks/useUploadFiles.ts index 6e1f0058a..9fbb000dd 100644 --- a/packages/asset-upload/src/hooks/useUploadFiles.ts +++ b/packages/asset-upload/src/hooks/useUploadFiles.ts @@ -3,13 +3,15 @@ import { useRecoilValue } from 'recoil'; import { selectedTagIdState } from '@media-ui/feature-asset-tags'; import { selectedAssetCollectionIdState } from '@media-ui/feature-asset-collections'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { UPLOAD_FILES } from '../mutations'; export default function useUploadFiles() { const [action, { error, data, loading }] = useMutation<{ uploadFiles: FileUploadResult[] }>(UPLOAD_FILES); - const tagId = useRecoilValue(selectedTagIdState); - const assetCollectionId = useRecoilValue(selectedAssetCollectionIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const tagId = useRecoilValue(selectedTagIdState(assetSourceId)); + const assetCollectionId = useRecoilValue(selectedAssetCollectionIdState(assetSourceId)); const uploadFiles = (files: File[]) => action({ diff --git a/packages/asset-usage/src/hooks/useUnusedAssetsQuery.ts b/packages/asset-usage/src/hooks/useUnusedAssetsQuery.ts index 71b32fca9..e4b841e14 100644 --- a/packages/asset-usage/src/hooks/useUnusedAssetsQuery.ts +++ b/packages/asset-usage/src/hooks/useUnusedAssetsQuery.ts @@ -3,7 +3,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { useLazyQuery } from '@apollo/client'; import { currentPageState, featureFlagsState, loadingState } from '@media-ui/core/src/state'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import UNUSED_ASSETS from '../queries/unusedAssets'; import showUnusedAssetsState from '../state/showUnusedAssetsState'; @@ -23,7 +23,7 @@ const useUnusedAssetsQuery = () => { pagination: { assetsPerPage }, } = useRecoilValue(featureFlagsState); const currentPage = useRecoilValue(currentPageState); - const assetSourceId = useRecoilValue(selectedAssetSourceState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); const [isLoading, setIsLoading] = useRecoilState(loadingState); const showUnusedAssets = useRecoilValue(showUnusedAssetsState); const [assets, setAssets] = useState([]); diff --git a/packages/clipboard/src/state/clipboardState.ts b/packages/clipboard/src/state/clipboardState.ts index 2a233add9..d6165e719 100644 --- a/packages/clipboard/src/state/clipboardState.ts +++ b/packages/clipboard/src/state/clipboardState.ts @@ -1,4 +1,4 @@ -import { atom, selector, selectorFamily } from 'recoil'; +import { atom, selectorFamily } from 'recoil'; import { localStorageEffect } from '@media-ui/core/src/state/localStorageEffect'; import { selectedAssetIdsState } from '@media-ui/core/src/state'; @@ -50,35 +50,40 @@ export const clipboardItemState = selectorFamily({ +export const clipboardItemsState = selectorFamily({ key: 'ClipboardItemsState', - get: ({ get }) => { - const selectedAssets = get(selectedAssetIdsState); - if (selectedAssets.length === 0) return false; - const clipboard = get(clipboardState); - return selectedAssets.every((selected) => - clipboard.some((c) => c.assetId === selected.assetId && c.assetSourceId === selected.assetSourceId) - ); - }, - set: ({ get, set }) => { - const selectedAssets = get(selectedAssetIdsState); - const clipboard = get(clipboardState); - const allInClipboard = selectedAssets.every((selected) => - clipboard.some((c) => c.assetId === selected.assetId && c.assetSourceId === selected.assetSourceId) - ); - - if (allInClipboard) { - set( - clipboardState, - clipboard.filter( - (c) => !selectedAssets.some((s) => s.assetId === c.assetId && s.assetSourceId === c.assetSourceId) - ) + get: + (assetSourceId: AssetSourceId) => + ({ get }) => { + const selectedAssets = get(selectedAssetIdsState(assetSourceId)); + if (selectedAssets.length === 0) return false; + const clipboard = get(clipboardState); + return selectedAssets.every((selected) => + clipboard.some((c) => c.assetId === selected.assetId && c.assetSourceId === selected.assetSourceId) ); - } else { - const toAdd = selectedAssets.filter( - (s) => !clipboard.some((c) => c.assetId === s.assetId && c.assetSourceId === s.assetSourceId) + }, + set: + (assetSourceId: AssetSourceId) => + ({ get, set }) => { + const selectedAssets = get(selectedAssetIdsState(assetSourceId)); + const clipboard = get(clipboardState); + const allInClipboard = selectedAssets.every((selected) => + clipboard.some((c) => c.assetId === selected.assetId && c.assetSourceId === selected.assetSourceId) ); - set(clipboardState, [...clipboard, ...toAdd]); - } - }, + + if (allInClipboard) { + set( + clipboardState, + clipboard.filter( + (c) => + !selectedAssets.some((s) => s.assetId === c.assetId && s.assetSourceId === c.assetSourceId) + ) + ); + } else { + const toAdd = selectedAssets.filter( + (s) => !clipboard.some((c) => c.assetId === s.assetId && c.assetSourceId === s.assetSourceId) + ); + set(clipboardState, [...clipboard, ...toAdd]); + } + }, }); diff --git a/packages/core/src/hooks/useAssetCountQuery.ts b/packages/core/src/hooks/useAssetCountQuery.ts index d3040afbb..7cbc8220d 100644 --- a/packages/core/src/hooks/useAssetCountQuery.ts +++ b/packages/core/src/hooks/useAssetCountQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@apollo/client'; import { useRecoilValue } from 'recoil'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { ASSET_COUNT } from '../queries'; import { @@ -26,8 +26,8 @@ interface AssetCountVariables { export default function useAssetCountQuery(total = false) { const searchTerm = useRecoilValue(searchTermState); - const { tagId, assetCollectionId } = useRecoilValue(selectedAssetCollectionAndTagState); - const assetSourceId = useRecoilValue(selectedAssetSourceState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const { tagId, assetCollectionId } = useRecoilValue(selectedAssetCollectionAndTagState(assetSourceId)); const mediaType = useRecoilValue(selectedMediaTypeState); const assetType = useRecoilValue(selectedAssetTypeState); const { data, loading } = useQuery(ASSET_COUNT, { diff --git a/packages/core/src/hooks/useAssetsQuery.ts b/packages/core/src/hooks/useAssetsQuery.ts index adc5ce848..904c240b1 100644 --- a/packages/core/src/hooks/useAssetsQuery.ts +++ b/packages/core/src/hooks/useAssetsQuery.ts @@ -4,7 +4,7 @@ import { useLazyQuery } from '@apollo/client'; import { selectedTagIdState } from '@media-ui/feature-asset-tags'; import { selectedAssetCollectionIdState } from '@media-ui/feature-asset-collections'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { SORT_BY, SORT_DIRECTION } from '../state/selectedSortOrderState'; import { @@ -46,9 +46,9 @@ const useAssetsQuery = () => { pagination: { assetsPerPage }, } = useRecoilValue(featureFlagsState); const searchTerm = useRecoilValue(searchTermState); - const assetCollectionId = useRecoilValue(selectedAssetCollectionIdState); - const assetSourceId = useRecoilValue(selectedAssetSourceState); - const selectedTagId = useRecoilValue(selectedTagIdState); + const assetSourceId = useRecoilValue(selectedAssetSourceIdState); + const assetCollectionId = useRecoilValue(selectedAssetCollectionIdState(assetSourceId)); + const selectedTagId = useRecoilValue(selectedTagIdState(assetSourceId)); const mediaType = useRecoilValue(selectedMediaTypeState); const assetType = useRecoilValue(selectedAssetTypeState); const sortOrderState = useRecoilValue(selectedSortOrderState); diff --git a/packages/core/src/state/index.ts b/packages/core/src/state/index.ts index f2e0dd150..46412a29b 100644 --- a/packages/core/src/state/index.ts +++ b/packages/core/src/state/index.ts @@ -13,4 +13,4 @@ export { selectedMediaTypeState } from './selectedMediaTypeState'; export { selectedAssetTypeState } from './selectedAssetTypeState'; export { selectedSortOrderState } from './selectedSortOrderState'; export { applicationContextState } from './applicationContextState'; -export { selectedAssetIdsState, isAssetSelectedState } from './selectedAssetIdsState'; +export { selectedAssetIdsState, isAssetSelectedState, multiSelectionState } from './selectedAssetIdsState'; diff --git a/packages/core/src/state/selectedAssetCollectionAndTagState.ts b/packages/core/src/state/selectedAssetCollectionAndTagState.ts index fa5d18f4f..b3856f737 100644 --- a/packages/core/src/state/selectedAssetCollectionAndTagState.ts +++ b/packages/core/src/state/selectedAssetCollectionAndTagState.ts @@ -1,4 +1,4 @@ -import { selector } from 'recoil'; +import { selectorFamily } from 'recoil'; import { selectedTagIdState } from '@media-ui/feature-asset-tags'; import { selectedAssetCollectionIdState } from '@media-ui/feature-asset-collections'; @@ -11,21 +11,28 @@ import { selectedAssetIdsState } from './selectedAssetIdsState'; // This is a proxy for setting the selected tag id, which also executes side effects to update other state // By setting the other state in a selector, we can ensure that the state is updated all at once -export const selectedAssetCollectionAndTagState = selector<{ tagId: string | null; assetCollectionId: string | null }>({ +export const selectedAssetCollectionAndTagState = selectorFamily< + { tagId: string | null; assetCollectionId: string | null }, + AssetSourceId +>({ key: 'SelectedTagIdProxySelector', - get: ({ get }) => ({ - tagId: get(selectedTagIdState), - assetCollectionId: get(selectedAssetCollectionIdState), - }), - set: ({ get, set }, props: { tagId: string | null; assetCollectionId: string | null }) => { - const isMultiSelection = get(selectedAssetIdsState).length > 1; - if (!isMultiSelection) { - set(selectedInspectorViewState, props.tagId ? 'tag' : 'assetCollection'); - } - set(selectedTagIdState, props.tagId); - set(selectedAssetIdState, null); - set(currentPageState, 1); - set(selectedAssetCollectionIdState, props.assetCollectionId); - set(clipboardVisibleState, false); - }, + get: + (assetSourceId: AssetSourceId) => + ({ get }) => ({ + tagId: get(selectedTagIdState(assetSourceId)), + assetCollectionId: get(selectedAssetCollectionIdState(assetSourceId)), + }), + set: + (assetSourceId: AssetSourceId) => + ({ get, set }, props: { tagId: string | null; assetCollectionId: string | null }) => { + const isMultiSelection = get(selectedAssetIdsState(assetSourceId)).length > 1; + if (!isMultiSelection) { + set(selectedInspectorViewState, props.tagId ? 'tag' : 'assetCollection'); + } + set(selectedTagIdState(assetSourceId), props.tagId); + set(selectedAssetIdState, null); + set(currentPageState, 1); + set(selectedAssetCollectionIdState(assetSourceId), props.assetCollectionId); + set(clipboardVisibleState, false); + }, }); diff --git a/packages/core/src/state/selectedAssetIdState.ts b/packages/core/src/state/selectedAssetIdState.ts index 8b5ac6702..933f64638 100644 --- a/packages/core/src/state/selectedAssetIdState.ts +++ b/packages/core/src/state/selectedAssetIdState.ts @@ -11,7 +11,7 @@ const selectedAssetIdForContextState = atomFamily({ +export const selectedAssetIdState = selector({ key: 'selectedAssetIdState', get: ({ get }) => get(selectedAssetIdForContextState(get(applicationContextState))), set: ({ get, set }, assetIdentity) => diff --git a/packages/core/src/state/selectedAssetIdsState.ts b/packages/core/src/state/selectedAssetIdsState.ts index d79c793f6..5bc6cace8 100644 --- a/packages/core/src/state/selectedAssetIdsState.ts +++ b/packages/core/src/state/selectedAssetIdsState.ts @@ -1,4 +1,4 @@ -import { atom, selector, selectorFamily } from 'recoil'; +import { atomFamily, selectorFamily } from 'recoil'; import { selectedAssetIdState } from './selectedAssetIdState'; import { selectedInspectorViewState } from './selectedInspectorViewState'; @@ -7,15 +7,17 @@ import { selectedInspectorViewState } from './selectedInspectorViewState'; * Default value: if a single asset was persisted via selectedAssetIdState, * initialize the selection array with it on first load. */ -const selectedAssetIdsDefaultState = selector({ +const selectedAssetIdsDefaultState = selectorFamily({ key: 'SelectedAssetIdsDefaultState', - get: ({ get }) => { - const selectedAsset = get(selectedAssetIdState); - return selectedAsset ? [selectedAsset] : []; - }, + get: + (assetSourceId: AssetSourceId) => + ({ get }) => { + const selectedAsset = get(selectedAssetIdState); + return selectedAsset && selectedAsset.assetSourceId === assetSourceId ? [selectedAsset.assetId] : []; + }, }); -const selectedAssetIdsInternalState = atom({ +const selectedAssetIdsInternalState = atomFamily({ key: 'SelectedAssetIdsInternalState', default: selectedAssetIdsDefaultState, }); @@ -26,24 +28,38 @@ const selectedAssetIdsInternalState = atom({ * - 1 asset: set it as the active asset in the inspector * - 0 or >1: clear the active asset */ -export const selectedAssetIdsState = selector({ +export const selectedAssetIdsState = selectorFamily({ key: 'SelectedAssetIdsState', - get: ({ get }) => get(selectedAssetIdsInternalState), - set: ({ set }, newValue: AssetIdentity[]) => { - set(selectedAssetIdsInternalState, newValue); - if (newValue.length === 1) { - set(selectedAssetIdState, newValue[0]); - set(selectedInspectorViewState, 'asset'); - } else { - set(selectedAssetIdState, null); - } - }, + get: + (assetSourceId: AssetSourceId) => + ({ get }) => + get(selectedAssetIdsInternalState(assetSourceId)).map((assetId) => ({ assetId, assetSourceId })), + set: + (assetSourceId) => + ({ set }, newValue: AssetIdentity[]) => { + set( + selectedAssetIdsInternalState(assetSourceId), + newValue.map(({ assetId }) => assetId) + ); + if (newValue.length === 1) { + set(selectedAssetIdState, newValue[0]); + set(selectedInspectorViewState, 'asset'); + } else { + set(selectedAssetIdState, null); + } + }, +}); + +export const multiSelectionState = selectorFamily({ + key: 'isMultiSelection', + get: (assetSourceId: AssetSourceId) => + ({get}) => get(selectedAssetIdsInternalState(assetSourceId)).length > 0, }); -export const isAssetSelectedState = selectorFamily({ +export const isAssetSelectedState = selectorFamily({ key: 'IsAssetSelectedState', get: - (assetId) => + (assetIdentity: AssetIdentity) => ({ get }) => - get(selectedAssetIdsState).some((a) => a.assetId === assetId), + get(selectedAssetIdsState(assetIdentity.assetSourceId)).some((a) => a.assetId === assetIdentity.assetId), }); diff --git a/packages/core/typings/Asset.d.ts b/packages/core/typings/Asset.d.ts index bef55ae74..38e6b0230 100644 --- a/packages/core/typings/Asset.d.ts +++ b/packages/core/typings/Asset.d.ts @@ -1,8 +1,10 @@ type AssetEntityType = 'Asset'; +type AssetId = string; + interface Asset extends GraphQlEntity { __typename: AssetEntityType; - readonly id: string; + readonly id: AssetId; readonly localId?: string; readonly assetSource: { readonly id: AssetSourceId; diff --git a/packages/core/typings/AssetIdentity.d.ts b/packages/core/typings/AssetIdentity.d.ts index fda12e6bb..423b6f89b 100644 --- a/packages/core/typings/AssetIdentity.d.ts +++ b/packages/core/typings/AssetIdentity.d.ts @@ -1,4 +1,4 @@ interface AssetIdentity { - assetId: string; - assetSourceId: string; + assetId: AssetId; + assetSourceId: AssetSourceId; } diff --git a/packages/media-module/src/components/App.tsx b/packages/media-module/src/components/App.tsx index 603636407..9347cfc2a 100644 --- a/packages/media-module/src/components/App.tsx +++ b/packages/media-module/src/components/App.tsx @@ -18,7 +18,7 @@ import { CreateAssetCollectionDialog, createAssetCollectionDialogVisibleState, } from '@media-ui/feature-asset-collections'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import SideBarLeft from './SideBarLeft/SideBarLeft'; import { SideBarRight } from './SideBarRight'; @@ -42,7 +42,7 @@ const App = () => { const showSimilarAssetsModal = useRecoilValue(similarAssetsModalState); const searchTerm = useRecoilValue(searchTermState); const selectAsset = useSelectAsset(); - const selectAssetSource = useSetRecoilState(selectedAssetSourceState); + const selectAssetSource = useSetRecoilState(selectedAssetSourceIdState); // TODO: Implement asset source selection via recoil an atom effect in `searchTermState` to avoid this dangerous effect React.useEffect(() => { diff --git a/packages/media-module/src/components/Main/ListViewItem.tsx b/packages/media-module/src/components/Main/ListViewItem.tsx index 39e40f668..306c91e77 100644 --- a/packages/media-module/src/components/Main/ListViewItem.tsx +++ b/packages/media-module/src/components/Main/ListViewItem.tsx @@ -32,7 +32,7 @@ const ListViewItem: React.FC = ({ assetIdentity, onSelect, on const { dummyImage, isAssetSelectable, selectionMode } = useMediaUi(); const { asset, loading } = useAssetQuery(assetIdentity); const applicationContext = useRecoilValue(applicationContextState); - const isMultiSelected = useRecoilValue(isAssetSelectedState(assetIdentity.assetId)); + const isMultiSelected = useRecoilValue(isAssetSelectedState(assetIdentity)); const canBeSelected = useMemo(() => isAssetSelectable(asset), [asset, isAssetSelectable]); const isBrowserContext = applicationContext === 'browser'; diff --git a/packages/media-module/src/components/Main/Thumbnail.tsx b/packages/media-module/src/components/Main/Thumbnail.tsx index c38363279..a0777b3f6 100644 --- a/packages/media-module/src/components/Main/Thumbnail.tsx +++ b/packages/media-module/src/components/Main/Thumbnail.tsx @@ -25,7 +25,7 @@ const Thumbnail: React.FC = ({ assetIdentity, onSelect, onMultiS const { asset, loading } = useAssetQuery(assetIdentity); const applicationContext = useRecoilValue(applicationContextState); const isSelected = useRecoilValue(isFocusedAssetState(assetIdentity.assetId)); - const isMultiSelected = useRecoilValue(isAssetSelectedState(assetIdentity.assetId)); + const isMultiSelected = useRecoilValue(isAssetSelectedState(assetIdentity)); const canBeSelected = useMemo(() => isAssetSelectable(asset), [asset, isAssetSelectable]); const isBrowserContext = applicationContext === 'browser'; diff --git a/packages/media-module/src/components/SideBarRight/CurrentSelection.tsx b/packages/media-module/src/components/SideBarRight/CurrentSelection.tsx index d3c727803..94d9fa37e 100644 --- a/packages/media-module/src/components/SideBarRight/CurrentSelection.tsx +++ b/packages/media-module/src/components/SideBarRight/CurrentSelection.tsx @@ -12,17 +12,19 @@ import { useSelectedAssetCollection, } from '@media-ui/feature-asset-collections'; import { useSelectedTag } from '@media-ui/feature-asset-tags'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import classes from './CurrentSelection.module.css'; const CurrentSelection = () => { + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const selectedAssetCollection = useSelectedAssetCollection(); const selectedTag = useSelectedTag(); - const setSelectedAssetCollectionAndTag = useSetRecoilState(selectedAssetCollectionAndTagState); + const setSelectedAssetCollectionAndTag = useSetRecoilState( + selectedAssetCollectionAndTagState(selectedAssetSourceId) + ); const selectedInspectorView = useRecoilValue(selectedInspectorViewState); const { translate } = useIntl(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); const { assetCollections } = useAssetCollectionsQuery(selectedAssetSourceId); const selection = useMemo(() => { diff --git a/packages/media-module/src/components/SideBarRight/Inspector/AssetCollectionInspector.tsx b/packages/media-module/src/components/SideBarRight/Inspector/AssetCollectionInspector.tsx index d3cb10b48..0c199eda1 100644 --- a/packages/media-module/src/components/SideBarRight/Inspector/AssetCollectionInspector.tsx +++ b/packages/media-module/src/components/SideBarRight/Inspector/AssetCollectionInspector.tsx @@ -7,7 +7,7 @@ import { useIntl, useNotify } from '@media-ui/core'; import { selectedInspectorViewState } from '@media-ui/core/src/state'; import { useConfigQuery } from '@media-ui/core/src/hooks'; import { useSelectedAssetCollection, useUpdateAssetCollection } from '@media-ui/feature-asset-collections'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { TagSelectBoxAssetCollection } from '.'; import Actions from './Actions'; @@ -18,7 +18,7 @@ import ParentCollectionSelectBox from './ParentCollectionSelectBox'; // TASK: Move into media module package const AssetCollectionInspector = () => { const { config } = useConfigQuery(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const selectedAssetCollection = useSelectedAssetCollection(); const selectedInspectorView = useRecoilValue(selectedInspectorViewState); const Notify = useNotify(); diff --git a/packages/media-module/src/components/SideBarRight/Inspector/AssetInspector.tsx b/packages/media-module/src/components/SideBarRight/Inspector/AssetInspector.tsx index 154cd02a7..9e5e2bc2f 100644 --- a/packages/media-module/src/components/SideBarRight/Inspector/AssetInspector.tsx +++ b/packages/media-module/src/components/SideBarRight/Inspector/AssetInspector.tsx @@ -5,11 +5,12 @@ import { Tabs } from '@neos-project/react-ui-components'; import { featureFlagsState, - selectedAssetIdsState, + multiSelectionState, selectedAssetIdState, selectedInspectorViewState, } from '@media-ui/core/src/state'; import VariantsInspector from '@media-ui/feature-asset-variants/src/components/VariantsInspector'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import PropertyInspector from './PropertyInspector'; @@ -17,9 +18,10 @@ import classes from './AssetInspector.module.css'; const AssetInspector = () => { const selectedAssetId = useRecoilValue(selectedAssetIdState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const { showVariantsEditor } = useRecoilValue(featureFlagsState); const selectedInspectorView = useRecoilValue(selectedInspectorViewState); - const isMultiSelection = useRecoilValue(selectedAssetIdsState).length > 1; + const isMultiSelection = useRecoilValue(multiSelectionState(selectedAssetSourceId)); if ((!selectedAssetId && !isMultiSelection) || selectedInspectorView !== 'asset') return null; diff --git a/packages/media-module/src/components/SideBarRight/Inspector/CollectionSelectBox.tsx b/packages/media-module/src/components/SideBarRight/Inspector/CollectionSelectBox.tsx index da016ee1d..e9b8839e2 100644 --- a/packages/media-module/src/components/SideBarRight/Inspector/CollectionSelectBox.tsx +++ b/packages/media-module/src/components/SideBarRight/Inspector/CollectionSelectBox.tsx @@ -9,7 +9,7 @@ import { useFailedAssetLabels } from '@media-ui/media-module/src/hooks'; import { IconLabel } from '@media-ui/core/src/components'; import { featureFlagsState, selectedAssetIdsState } from '@media-ui/core/src/state'; import { collectionPath, useAssetCollectionsQuery } from '@media-ui/feature-asset-collections'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { AssetCollectionOptionPreviewElement, CollectionOption } from './AssetCollectionOptionPreviewElement'; @@ -20,7 +20,8 @@ const collectionsMatchAsset = (assetCollectionIds: string[], asset: Asset) => { }; const CollectionSelectBox: React.FC = () => { - const selectedAssets = useRecoilValue(selectedAssetIdsState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectedAssets = useRecoilValue(selectedAssetIdsState(selectedAssetSourceId)); const isMultiSelection = selectedAssets.length > 1; const Notify = useNotify(); const { translate } = useIntl(); @@ -28,7 +29,6 @@ const CollectionSelectBox: React.FC = () => { const { approvalAttainmentStrategy: { obtainApprovalToSetAssetCollections, obtainApprovalToShiftAssetsToCollection }, } = useMediaUi(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); const { assetCollections } = useAssetCollectionsQuery(selectedAssetSourceId); const { setAssetCollections, loading } = useSetAssetCollections(); const { getFailedAssetLabels } = useFailedAssetLabels(); diff --git a/packages/media-module/src/components/SideBarRight/Inspector/ParentCollectionSelectBox.tsx b/packages/media-module/src/components/SideBarRight/Inspector/ParentCollectionSelectBox.tsx index 50bbeed6a..71cb4b641 100644 --- a/packages/media-module/src/components/SideBarRight/Inspector/ParentCollectionSelectBox.tsx +++ b/packages/media-module/src/components/SideBarRight/Inspector/ParentCollectionSelectBox.tsx @@ -14,14 +14,14 @@ import { import { AssetCollectionOptionPreviewElement, CollectionOption } from './AssetCollectionOptionPreviewElement'; import * as classes from './ParentCollectionSelectBox.module.css'; -import { selectedAssetSourceState } from '@media-ui/feature-asset-sources'; +import { selectedAssetSourceIdState } from '@media-ui/feature-asset-sources'; import { useRecoilValue } from 'recoil'; const ParentCollectionSelectBox = () => { const Notify = useNotify(); const { translate } = useIntl(); const { approvalAttainmentStrategy } = useMediaUi(); - const selectedAssetSourceId = useRecoilValue(selectedAssetSourceState); + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); const { assetCollections } = useAssetCollectionsQuery(selectedAssetSourceId); const selectedAssetCollection = useSelectedAssetCollection(); const { setAssetCollectionParent, loading } = useSetAssetCollectionParent(); diff --git a/packages/media-module/src/components/SideBarRight/Inspector/PropertyInspector.tsx b/packages/media-module/src/components/SideBarRight/Inspector/PropertyInspector.tsx index e4967039f..6708b6839 100644 --- a/packages/media-module/src/components/SideBarRight/Inspector/PropertyInspector.tsx +++ b/packages/media-module/src/components/SideBarRight/Inspector/PropertyInspector.tsx @@ -8,9 +8,10 @@ import { useIntl, useNotify, useMediaUi } from '@media-ui/core'; import { useSelectedAsset, useUpdateAsset } from '@media-ui/core/src/hooks'; import { useFailedAssetLabels } from '@media-ui/media-module/src/hooks'; import { IconLabel } from '@media-ui/core/src/components'; -import { featureFlagsState, selectedAssetIdsState } from '@media-ui/core/src/state'; +import { featureFlagsState, multiSelectionState, selectedAssetIdsState } from '@media-ui/core/src/state'; import { UPDATE_ASSET } from '@media-ui/core/src/mutations'; import { useInteraction } from '@media-ui/core/src/provider'; +import { selectedAssetSourceIdState, useSelectedAssetSource } from '@media-ui/feature-asset-sources'; import { CollectionSelectBox, MetadataView, TagSelectBoxAsset } from './index'; import TagSelectBoxMulti from './TagSelectBoxMulti'; @@ -20,13 +21,13 @@ import InspectorContainer from './InspectorContainer'; import Tasks from './Tasks'; import classes from './PropertyInspector.module.css'; -import { useAssetSourcesQuery } from '@media-ui/feature-asset-sources'; const PropertyInspector = () => { - const selectedAssets = useRecoilValue(selectedAssetIdsState); - const isMultiSelection = selectedAssets.length > 1; + const selectedAssetSourceId = useRecoilValue(selectedAssetSourceIdState); + const selectedAssets = useRecoilValue(selectedAssetIdsState(selectedAssetSourceId)); + const isMultiSelection = useRecoilValue(multiSelectionState(selectedAssetSourceId)); + const selectedAssetSource = useSelectedAssetSource(); const selectedAsset = useSelectedAsset(); - const { assetSources } = useAssetSourcesQuery(); const Notify = useNotify(); const { translate } = useIntl(); const { @@ -46,7 +47,8 @@ const PropertyInspector = () => { const { updateAsset, loading } = useUpdateAsset(); - const isEditable = isMultiSelection ? !multiLoading : selectedAsset?.localId && !loading; + const isReadOnly = selectedAssetSource ? selectedAssetSource.readOnly : true; + const isEditable = !isReadOnly && (isMultiSelection ? !multiLoading : selectedAsset?.localId && !loading); const hasUnpublishedChanges = isMultiSelection ? copyrightNotice !== '' && copyrightNotice !== null : selectedAsset && @@ -54,10 +56,6 @@ const PropertyInspector = () => { caption !== selectedAsset.caption || copyrightNotice !== selectedAsset.copyrightNotice); - const assetSourceForSelectedAsset = selectedAsset - ? assetSources.find(({ id }) => id === selectedAsset.assetSource.id) - : null; - const handleDiscard = useCallback(() => { if (isMultiSelection) { setCopyrightNotice(''); @@ -158,73 +156,78 @@ const PropertyInspector = () => { } }, [isMultiSelection]); - if (!selectedAsset && !isMultiSelection) return null; + if (!selectedAssetSource || (!selectedAsset && !isMultiSelection)) return null; return ( - setPropertyEditorCollapsed((prev) => !prev)} - > - - - - - {!isMultiSelection && ( - <> - - - - -