♻️ front: moved driveitem access entities editing to a helper file (#50)

This commit is contained in:
Eric Doughty-Papassideris
2024-04-21 22:10:36 +02:00
committed by ericlinagora
parent ecf106c5f8
commit fc3ebaa911
10 changed files with 225 additions and 131 deletions
@@ -25,6 +25,7 @@ import RouterServices from '@features/router/services/router-service';
import useRouterCompany from '@features/router/hooks/use-router-company';
import _ from 'lodash';
import Languages from 'features/global/services/languages-service';
import { hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
/**
* This will build the context menu in different contexts
@@ -50,7 +51,7 @@ export const useOnBuildContextMenu = (children: DriveItem[], initialParentId?: s
const { open: preview } = useDrivePreview();
const { viewId } = useRouteState();
const company = useRouterCompany();
function getIdsFromArray(arr: DriveItem[]): string[] {
return arr.map((obj) => obj.id);
}
@@ -309,9 +310,7 @@ export const useOnBuildContextMenu = (children: DriveItem[], initialParentId?: s
{
type: 'menu',
text: Languages.t('components.item_context_menu.copy_link'),
hide:
!parent?.item?.access_info?.public?.level ||
parent?.item?.access_info?.public?.level === 'none',
hide: !hasAnyPublicLinkAccess(item),
onClick: () => {
copyToClipboard(getPublicLink(item || parent?.item));
ToasterService.success(
@@ -13,6 +13,7 @@ import { useHistory } from 'react-router-dom';
import RouterServices from '@features/router/services/router-service';
import useRouteState from 'app/features/router/hooks/use-route-state';
import { DocumentIcon } from './document-icon';
import { hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
export const DocumentRow = ({
item,
@@ -79,7 +80,7 @@ export const DocumentRow = ({
<Base className="flex maxWidth100">{item.name}</Base>
</div>
<div className="shrink-0 ml-4">
{item?.access_info?.public?.level !== 'none' && (
{hasAnyPublicLinkAccess(item) && (
<PublicIcon className="h-5 w-5 text-blue-500" />
)}
</div>
@@ -7,6 +7,7 @@ import { formatBytes } from '@features/drive/utils';
import { useState } from 'react';
import { PublicIcon } from '../components/public-icon';
import { CheckableIcon, DriveItemProps } from './common';
import { hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
import './style.scss';
export const FolderRow = ({
@@ -49,7 +50,7 @@ export const FolderRow = ({
<Base className="!font-semibold flex maxWidth100">{item.name}</Base>
</div>
<div className="shrink-0 ml-4">
{item?.access_info?.public?.level !== 'none' && (
{hasAnyPublicLinkAccess(item) && (
<PublicIcon className="h-5 w-5 text-blue-500" />
)}
</div>
@@ -10,6 +10,7 @@ import Languages from 'features/global/services/languages-service';
import { useHistory } from 'react-router-dom';
import useRouterCompany from '@features/router/hooks/use-router-company';
import RouterServices from '@features/router/services/router-service';
import { hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
export default ({
path: livePath,
@@ -193,7 +194,7 @@ const PathItem = ({
})()}
</Title>
</a>
{item?.access_info?.public?.level && item?.access_info?.public?.level !== 'none' && (
{hasAnyPublicLinkAccess(item) && (
<PublicIcon className="h-5 w-5 ml-2" />
)}
{first && !!user?.id && viewId?.includes('trash') && (
@@ -15,6 +15,7 @@ import { ArrowLeftIcon, LockClosedIcon } from '@heroicons/react/outline';
import { PublicLinkAccessOptions } from './public-link-access-options';
import { CuteDepictionOfFolderHierarchy } from './cute-depiction-of-folder-hierarchy';
import { InheritAccessOptions } from './inherit-access-options';
import { changePublicLink, hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
export type AccessModalType = {
open: boolean;
@@ -94,20 +95,9 @@ const AccessModalContent = (props: {
refresh(id);
refreshCompany();
}, []);
const havePublicLink = (item?.access_info?.public?.level || 'none') !== 'none';
const havePublicLink = hasAnyPublicLinkAccess(item);
const haveAdvancedSettings = parentItem?.parent_id !== null || havePublicLink;
const updatePublicAccess = (key: string, value: string | number, skipLoading?: true) =>
update({
access_info: {
entities: item?.access_info.entities || [],
public: {
...item!.access_info!.public!,
[key]: value || '',
},
},
}, skipLoading);
return (
<ModalContent
title={
@@ -138,10 +128,10 @@ const AccessModalContent = (props: {
password={item?.access_info?.public?.password}
expiration={item?.access_info?.public?.expiration}
onChangePassword={(password: string) => {
updatePublicAccess('password', password || '', true);
item && changePublicLink(item, { password: password || '' });
}}
onChangeExpiration={(expiration: number) => {
updatePublicAccess('expiration', expiration || 0);
item && changePublicLink(item, { expiration: expiration || 0 });
}}
/>}
{ parentItem?.parent_id !== null && <>
@@ -1,6 +1,14 @@
import Languages from 'features/global/services/languages-service';
import type { DriveItem } from 'app/features/drive/types';
import {
changeAllChannelAccessLevels,
changeCompanyAccessLevel,
changeInheritedAccess,
getCompanyAccessLevel,
getFirstChannelAccessLevel,
getInheritedAccessLevel,
} from '@features/files/utils/access-info-helpers';
import { Base, Info, Subtitle } from '@atoms/text';
import { Checkbox } from '@atoms/input/input-checkbox';
@@ -12,21 +20,17 @@ export const InheritAccessOptions = (props: {
disabled: boolean,
onUpdate: (item: Partial<DriveItem>) => void,
}) => {
const folderEntity = props.item?.access_info.entities.filter(a => a.type === 'folder')?.[0] || {
type: 'folder',
id: 'parent',
level: 'manage',
};
const companyEntity = props.item?.access_info.entities.filter(a => a.type === 'company')?.[0];
const channelEntities = props.item?.access_info.entities.filter(a => a.type === 'channel') || [];
// TODO: The default to 'manage' surprises me but it's what previous code did, as this commit is a refactoring, aim is to not affect function
const folderEntityLevel = getInheritedAccessLevel(props.item) || 'manage';
const companyEntityLevel = getCompanyAccessLevel(props.item);
const channelEntitiesLevel = getFirstChannelAccessLevel(props.item);
return (
<>
{(companyEntity || folderEntity?.level === 'none' || channelEntities.length > 0) &&
{(companyEntityLevel || folderEntityLevel === 'none' || channelEntitiesLevel) &&
<Subtitle className="block mt-4 mb-1">{Languages.t('components.internal-access_access_manage')}</Subtitle>}
{folderEntity && (
<div className="p-4 flex flex-row items-center justify-center">
{ <div className="p-4 flex flex-row items-center justify-center">
<div className="grow">
<Base>{Languages.t('components.internal-access_inherit_parent')}</Base>
<br />
@@ -36,23 +40,15 @@ export const InheritAccessOptions = (props: {
<Checkbox
disabled={props.disabled}
onChange={status => {
props.onUpdate({
access_info: {
entities: [
...(props.item?.access_info.entities.filter(a => a.type !== 'folder') || []),
{ ...folderEntity, level: status ? 'manage' : 'none' },
],
public: props.item?.access_info.public,
},
});
props.item && props.onUpdate(changeInheritedAccess(props.item, status ? 'manage' : 'none'));
}}
value={folderEntity.level === 'manage'}
value={folderEntityLevel === 'manage'}
/>
</div>
</div>
)}
}
{companyEntity && folderEntity.level === 'none' && (
{ companyEntityLevel && folderEntityLevel === 'none' && (
<div className="p-4 flex flex-row items-center justify-center">
<div className="grow">
<Base>{Languages.t('components.internal-access_company_member')}</Base>
@@ -61,29 +57,21 @@ export const InheritAccessOptions = (props: {
<AccessLevelDropdown
disabled={props.disabled}
onChange={level => {
props.onUpdate({
access_info: {
entities: [
...(props.item?.access_info.entities.filter(a => a.type !== 'company') || []),
...(level !== 'remove' ? [{ ...companyEntity, level }] : []),
],
public: props.item?.access_info.public,
},
});
props.item && props.onUpdate(changeCompanyAccessLevel(props.item, level === 'remove' ? false : level));
}}
level={companyEntity.level}
level={companyEntityLevel}
/>
</div>
</div>
)}
{channelEntities.length > 0 && (
{channelEntitiesLevel && (
<div className="p-4 border-b flex flex-row items-center justify-center">
<div className="grow">
<Base>{Languages.t('components.internal-access_cannal')}</Base>
<br />
<Info>
{channelEntities.length} {Languages.t('components.internal-access_cannal_info')}
{channelEntitiesLevel.length} {Languages.t('components.internal-access_cannal_info')}
</Info>
</div>
<div className="shrink-0 ml-2">
@@ -92,41 +80,21 @@ export const InheritAccessOptions = (props: {
hiddenLevels={['none']}
canRemove
onChange={level => {
if (level === 'remove') {
if (level === 'remove')
AlertManager.confirm(
async () => {
//Remove channel access
props.onUpdate({
access_info: {
entities:
props.item?.access_info?.entities.filter(e => e.type !== 'channel') || [],
public: props.item?.access_info.public,
},
});
},
() => {
//Do nothing
props.item && props.onUpdate(changeAllChannelAccessLevels(props.item, false));
},
() => { /* Do nothing */ },
{
text: Languages.t('components.internal-access_cannal_info_give_back'),
},
);
} else {
props.onUpdate({
access_info: {
entities:
props.item?.access_info?.entities.map(e => {
if (e.type === 'channel') {
return { ...e, level };
}
return e;
}) || [],
public: props.item?.access_info.public,
},
});
}
else
props.item && props.onUpdate(changeAllChannelAccessLevels(props.item, level));
}}
level={channelEntities[0].level}
level={channelEntitiesLevel}
/>
</div>
</div>
@@ -9,11 +9,11 @@ import { useState } from 'react';
import SelectUsers from '../../components/select-users';
import { AccessLevelDropdown } from './access-level-dropdown';
import Languages from 'features/global/services/languages-service';
import { changeUserAccess, getUserAccessLevel, getAllUserAccesses } from '@features/files/utils/access-info-edits';
export const InternalAccessManager = ({ id, disabled }: { id: string; disabled: boolean }) => {
const { item } = useDriveItem(id);
const userEntities = item?.access_info.entities.filter(a => a.type === 'user') || [];
return (
<>
@@ -21,11 +21,9 @@ export const InternalAccessManager = ({ id, disabled }: { id: string; disabled:
<div className="rounded-md border mt-2 dark:border-zinc-700">
<UserAccessSelector id={id} disabled={disabled} />
{userEntities
?.sort((a, b) => a?.id?.localeCompare(b?.id))
?.map(user => (
<UserAccessLevel key={user.id} id={id} userId={user?.id} disabled={disabled} />
))}
{item && getAllUserAccesses(item)?.map(user =>
<UserAccessLevel key={user.id} id={id} userId={user?.id} disabled={disabled} />
)}
<div className="-mb-px" />
</div>
</>
@@ -43,18 +41,8 @@ const UserAccessSelector = ({ id, disabled }: { id: string; disabled: boolean })
className="rounded-r-none"
level={level}
onChange={(users: UserType[]) => {
const id = users[0]?.id;
update({
access_info: {
entities: [
//Add or replace existing user
...(item?.access_info.entities.filter(a => a.type !== 'user' || a.id !== id) ||
[]),
...((id ? [{ type: 'user', id, level }] : []) as any),
],
public: item?.access_info.public,
},
});
const id = users[0]?.id; //TODO: all others ignored
item && id && update(changeUserAccess(item, id, level));
}}
initialUsers={[]}
/>
@@ -83,7 +71,6 @@ const UserAccessLevel = ({
const { item, loading, update } = useDriveItem(id);
const user = useUser(userId);
const { user: currentUser } = useCurrentUser();
const level = item?.access_info.entities.filter(a => a.type === 'user' && a.id === userId)?.[0]?.level || 'none';
return (
<UserBlock
className="p-4 border-t dark:border-zinc-700"
@@ -92,26 +79,9 @@ const UserAccessLevel = ({
suffix={
<AccessLevelDropdown
disabled={loading || disabled || user?.id === currentUser?.id}
level={level}
level={(item && getUserAccessLevel(item, userId)) || "none"}
canRemove={true}
onChange={
level =>
update({
access_info: {
entities:
level === 'remove'
? item?.access_info?.entities.filter(
e => e.type !== 'user' || e.id !== userId,
) || []
: item?.access_info?.entities.map(e => {
if (e.type === 'user' && e.id === userId)
return { ...e, level };
return e;
}) || [],
public: item?.access_info.public,
},
})
}
onChange={level => item && update(changeUserAccess(item, userId, level === 'remove' ? false : level))}
/>
}
/>
@@ -7,7 +7,8 @@ import { AccessLevelDropdown } from './access-level-dropdown';
import Languages from 'features/global/services/languages-service';
import { Button } from '@atoms/button/button';
import { LinkIcon, UserGroupIcon, CheckCircleIcon } from '@heroicons/react/outline';
import type { DriveFileAccessLevel } from 'app/features/drive/types';
import type { DriveFileAccessLevelForPublicLink } from 'app/features/drive/types';
import { changePublicLink } from '@features/files/utils/access-info-helpers';
export const PublicLinkManager = ({ id, disabled }: { id: string; disabled?: boolean }) => {
const { item, loading, update } = useDriveItem(id);
@@ -15,15 +16,10 @@ export const PublicLinkManager = ({ id, disabled }: { id: string; disabled?: boo
const defaultPublicLinkLevel = 'read';
const publicLinkLevel = item?.access_info?.public?.level || 'none';
const havePublicLink = publicLinkLevel !== 'none';
const [publicLinkCreationLevel, setPublicLinkCreationLevel] = useState<DriveFileAccessLevel>(defaultPublicLinkLevel);
const [publicLinkCreationLevel, setPublicLinkCreationLevel] = useState<DriveFileAccessLevelForPublicLink>(defaultPublicLinkLevel);
const publicLinkCreationLevelSafe = havePublicLink ? publicLinkLevel || defaultPublicLinkLevel : publicLinkCreationLevel;
const updatePublicLinkLevel = (level: DriveFileAccessLevel) => {
update({
access_info: {
entities: item?.access_info.entities || [],
public: { ...(item?.access_info?.public || { token: '' }), level },
},
});
const updatePublicLinkLevel = (level: DriveFileAccessLevelForPublicLink) => {
item && update(changePublicLink(item, { level }));
if (level === 'none')
setPublicLinkCreationLevel(defaultPublicLinkLevel);
};
@@ -57,9 +53,8 @@ export const PublicLinkManager = ({ id, disabled }: { id: string; disabled?: boo
setDidJustCompleteACopy(true);
setTimeout(() => setDidJustCompleteACopy(false), 1500);
}
} else {
} else
updatePublicLinkLevel(publicLinkCreationLevel);
}
}}
theme={didJustCompleteACopy ? "green" : "primary"}
className="absolute top-0 right-0 justify-center"