Skip to content

Commit

Permalink
Merge pull request #330 from node-real/feat/share-bucket
Browse files Browse the repository at this point in the history
feat(dcellar-web-ui): add share bucket
  • Loading branch information
aiden-cao authored Jan 18, 2024
2 parents 4b6306c + f6d99f7 commit 8138d5d
Show file tree
Hide file tree
Showing 16 changed files with 238 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DisconnectWalletModal } from '@/components/layout/Header/DisconnectWall
import { ObjectOperations } from '@/modules/object/components/ObjectOperations';
import Head from 'next/head';
import { useAppSelector } from '@/store';
import { BucketOperations } from '@/modules/bucket/components/BucketOperations';

interface GlobalManagementsProps {}

Expand All @@ -32,6 +33,7 @@ export const GlobalManagements = memo<GlobalManagementsProps>(function GlobalMan
<DisconnectWalletModal />
{/* for global download confirm modal */}
<ObjectOperations level={1} />
<BucketOperations level={1} />
</>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const Actions: MenuOption[] = [
value: 'marketplace',
},
{ label: 'View Details', value: 'detail' },
{ label: 'Share', value: 'share' },
{ label: 'Delete', value: 'delete', variant: 'danger' },
];

Expand Down Expand Up @@ -72,7 +73,7 @@ export const BucketList = memo<BucketListProps>(function BucketList() {
openLink(link);
return;
}
return dispatch(setBucketOperation([record.BucketName, menu]));
return dispatch(setBucketOperation({ operation: [record.BucketName, menu] }));
};

const columns: ColumnProps<BucketItem>[] = [
Expand Down Expand Up @@ -111,6 +112,7 @@ export const BucketList = memo<BucketListProps>(function BucketList() {
: Actions.filter((a) => a.value !== 'marketplace');
return (
<ActionMenu
operations={['share']}
menus={_actions}
onChange={(e) => onMenuClick(e as BucketOperationsType, record)}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
import React, { memo, useMemo } from 'react';
import React, { memo, useCallback, useMemo } from 'react';
import { useAppDispatch, useAppSelector } from '@/store';
import { DCDrawer } from '@/components/common/DCDrawer';
import { TBucket, setBucketOperation } from '@/store/slices/bucket';
import { TBucket, setBucketOperation, BucketOperationsType } from '@/store/slices/bucket';
import { useModalValues } from '@/hooks/useModalValues';
import { DCModal } from '@/components/common/DCModal';
import { DetailBucketOperation } from '@/modules/bucket/components/DetailBucketOperation';
import {
defaultNullObject,
DetailBucketOperation,
} from '@/modules/bucket/components/DetailBucketOperation';
import { CreateBucketOperation } from '@/modules/bucket/components/CreateBucketOperation';
import { useUnmount } from 'ahooks';
import { DeleteBucketOperation } from '@/modules/bucket/components/DeleteBucketOperation';
import { ModalCloseButton } from '@totejs/uikit';
import { ShareOperation } from '@/modules/object/components/ShareOperation';
import { ObjectMeta } from '@bnb-chain/greenfield-js-sdk/dist/esm/types/sp/Common';

interface BucketOperationsProps {}
interface BucketOperationsProps {
level?: 0 | 1;
}

export const BucketOperations = memo<BucketOperationsProps>(function BucketOperations() {
export const BucketOperations = memo<BucketOperationsProps>(function BucketOperations({
level = 0,
}) {
const dispatch = useAppDispatch();
const { bucketOperation, bucketInfo } = useAppSelector((root) => root.bucket);
const [id, operation] = bucketOperation;
const isDrawer = ['detail', 'create'].includes(operation);
const [id, operation] = bucketOperation[level];
const isDrawer = ['detail', 'create', 'share'].includes(operation);
const isModal = ['delete'].includes(operation);
const _operation = useModalValues<BucketOperationsProps>(operation);
const _operation = useModalValues<BucketOperationsType>(operation);
const selectBucketInfo = bucketInfo[id] || {};
const _selectBucketInfo = useModalValues<TBucket>(selectBucketInfo);
const { primarySpInfo } = useAppSelector((root) => root.sp);
const primarySp = useModalValues(primarySpInfo[_selectBucketInfo.BucketName]);

const onClose = () => {
dispatch(setBucketOperation(['', '']));
};
const onClose = useCallback(() => {
dispatch(setBucketOperation({ level, operation: ['', ''] }));
}, [level, dispatch]);

useUnmount(onClose);

Expand All @@ -36,10 +47,21 @@ export const BucketOperations = memo<BucketOperationsProps>(function BucketOpera
return <CreateBucketOperation onClose={onClose} />;
case 'delete':
return <DeleteBucketOperation onClose={onClose} selectedBucketInfo={_selectBucketInfo} />;
case 'share':
const nullObjectMeta: ObjectMeta = {
...defaultNullObject,
ObjectInfo: {
...defaultNullObject.ObjectInfo,
BucketName: _selectBucketInfo.BucketName,
},
};
return (
<ShareOperation selectObjectInfo={nullObjectMeta} primarySp={primarySp} objectName={''} />
);
default:
return null;
}
}, [_operation, _selectBucketInfo]);
}, [_operation, _selectBucketInfo, primarySp]);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { convertObjectKey } from '@/utils/common';
import { ResourceTags_Tag } from '@bnb-chain/greenfield-cosmos-types/greenfield/storage/types';
import { useUnmount } from 'ahooks';
import { DEFAULT_TAG } from '@/components/common/ManageTag';
import { ObjectMeta } from '@bnb-chain/greenfield-js-sdk/dist/esm/types/sp/Common';
import { SharePermission } from '@/modules/object/components/SharePermission';

export const Label = ({ children }: PropsWithChildren) => (
<Text fontSize={'14px'} fontWeight={500} color="readable.tertiary">
Expand All @@ -42,6 +44,24 @@ interface DetailBucketOperationProps {
selectedBucketInfo: TBucket;
}

export const defaultNullObject: ObjectMeta = {
ObjectInfo: {
ObjectName: '',
PayloadSize: 0,
Visibility: 3,
ObjectStatus: 1,
} as any,
LockedBalance: '',
Removed: false,
UpdateAt: 0,
DeleteAt: 0,
DeleteReason: '',
Operator: '',
CreateTxHash: '',
UpdateTxHash: '',
SealTxHash: '',
};

export const DetailBucketOperation = memo<DetailBucketOperationProps>(function DetailDrawer({
selectedBucketInfo,
}) {
Expand Down Expand Up @@ -255,6 +275,14 @@ export const DetailBucketOperation = memo<DetailBucketOperationProps>(function D

useUnmount(() => dispatch(setEditBucketTagsData([DEFAULT_TAG])));

const nullObjectMeta: ObjectMeta = {
...defaultNullObject,
ObjectInfo: {
...defaultNullObject.ObjectInfo,
BucketName: selectedBucketInfo.BucketName,
},
};

return (
<>
<QDrawerHeader>Bucket Detail</QDrawerHeader>
Expand Down Expand Up @@ -318,8 +346,10 @@ export const DetailBucketOperation = memo<DetailBucketOperationProps>(function D
</Text>
</Box>
</Flex>
<Divider marginBottom={24} />
<Divider mb={24} />
{getContent()}
<Divider mb={24} mt={8} />
<SharePermission selectObjectInfo={nullObjectMeta} />
</QDrawerBody>
<QDrawerFooter>
<DCButton size="lg" w={'100%'} onClick={manageQuota}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const NewBucket = memo<NewBucketProps>(function NewBucket({ showRefresh =
leftIcon={<IconFont type="refresh" w={24} />}
/>
)}
<DCButton onClick={() => dispatch(setBucketOperation(['', 'create']))}>
<DCButton onClick={() => dispatch(setBucketOperation({ operation: ['', 'create'] }))}>
Create Bucket
</DCButton>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const NewObject = memo<NewObjectProps>(function NewObject({
[loginAccount, primarySp?.operatorAddress, bucketName],
);

if (!owner)
if (!owner && !shareMode)
return (
<>
{showRefresh && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,10 @@ export const ObjectList = memo<ObjectListProps>(function ObjectList({ shareMode

// if this folder is yours, you only can review it
if (isFolder) {
pruneActions = pickAction(pruneActions, owner ? ['detail', 'share', 'delete'] : ['detail']);
pruneActions = pickAction(
pruneActions,
owner ? ['detail', 'share', 'delete'] : ['detail'],
);
}
// if sealed, remove cancel
if (isSealed) {
Expand Down Expand Up @@ -528,7 +531,7 @@ export const ObjectList = memo<ObjectListProps>(function ObjectList({ shareMode
<ObjectOperations />
<ManageObjectTagsDrawer />
<DCTable
rowSelection={owner ? rowSelection : undefined}
rowSelection={owner || shareMode ? rowSelection : undefined}
loading={loadingComponent}
rowKey="objectName"
columns={columns}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export const ObjectNameColumn = memo<ObjectNameColumnProps>(function NameItem({
}
return;
}
if (!owner) {
if (!owner && !shareMode) {
toast.warning({ description: 'You are browsing a bucket created by someone else. ' });
e.stopPropagation();
e.preventDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,24 @@ interface ShareOperationProps {
objectName: string;
}

// ObjectName '' for share Bucket
export const ShareOperation = memo<ShareOperationProps>(function ShareOperation({
selectObjectInfo,
primarySp,
objectName,
}) {
const dispatch = useAppDispatch();
const { loginAccount } = useAppSelector((root) => root.persist);
const { bucketName, path } = useAppSelector((root) => root.object);
const { bucketName: _bucketName, path } = useAppSelector((root) => root.object);
const { connector } = useAccount();
const { setOpenAuthModal } = useOffChainAuth();
const { hasCopied, onCopy, setValue } = useClipboard('');
const objectInfo = selectObjectInfo.ObjectInfo || {};
// share bucket
const bucketName = selectObjectInfo.ObjectInfo.BucketName || _bucketName;

useMount(async () => {
if (!objectName.endsWith('/')) return;
if (!objectName.endsWith('/') || objectName === '') return;
const _query = new URLSearchParams();
_query.append('delimiter', '/');
_query.append('maxKeys', '2');
Expand Down Expand Up @@ -129,8 +132,11 @@ export const ShareOperation = memo<ShareOperationProps>(function ShareOperation(
// handle folder object info
if (isEmpty(selectObjectInfo) || objectName !== objectInfo?.ObjectName) return <Loading />;

const name = last(trimEnd(objectInfo.ObjectName, '/').split('/'));
const isFolder = objectInfo.ObjectName.endsWith('/');
const name =
objectInfo.ObjectName === ''
? objectInfo.BucketName
: last(trimEnd(objectInfo.ObjectName, '/').split('/'));
const isFolder = objectInfo.ObjectName.endsWith('/') || objectInfo.ObjectName === '';

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ObjectMeta } from '@bnb-chain/greenfield-js-sdk/dist/esm/types/sp/Commo
import { Avatar } from '@/components/Avatar';
import { DCButton } from '@/components/common/DCButton';
import { IconFont } from '@/components/IconFont';
import { setBucketOperation } from '@/store/slices/bucket';

interface SharePermissionProps {
selectObjectInfo: ObjectMeta;
Expand Down Expand Up @@ -40,9 +41,10 @@ export const SharePermission = memo<SharePermissionProps>(function SharePermissi
selectObjectInfo,
}) {
const dispatch = useAppDispatch();
const { bucketName, objectPolicies } = useAppSelector((root) => root.object);
const { bucketName: _bucketName, objectPolicies } = useAppSelector((root) => root.object);
const { owner } = useAppSelector((root) => root.bucket);
const objectInfo = selectObjectInfo.ObjectInfo;
const bucketName = selectObjectInfo.ObjectInfo.BucketName || _bucketName;

useAsyncEffect(async () => {
dispatch(setupObjectPolicies(bucketName, objectInfo.ObjectName));
Expand Down Expand Up @@ -100,14 +102,18 @@ export const SharePermission = memo<SharePermissionProps>(function SharePermissi
{owner && (
<ManageAccess
variant={'ghost'}
onClick={() =>
onClick={() => {
if (objectInfo.ObjectName === '') {
dispatch(setBucketOperation({ level: 1, operation: [bucketName, 'share'] }));
return;
}
dispatch(
setObjectOperation({
level: 1,
operation: [`${bucketName}/${objectInfo.ObjectName}`, 'share'],
}),
)
}
);
}}
>
Manage Access
</ManageAccess>
Expand Down
27 changes: 22 additions & 5 deletions apps/dcellar-web-ui/src/modules/object/components/ViewerList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,13 @@ export const ViewerList = memo<ViewerListProps>(function ViewerList({ selectObje
const [values, setValues] = useState<string[]>([]);
const [searchValue, setSearchValue] = useState('');
const { connector } = useAccount();
const { bucketName, objectPolicies, objectPoliciesPage, selectedShareMembers, policyResources } =
useAppSelector((root) => root.object);
const {
bucketName: _bucketName,
objectPolicies,
objectPoliciesPage,
selectedShareMembers,
policyResources,
} = useAppSelector((root) => root.object);
const { loginAccount } = useAppSelector((root) => root.persist);
const groupList = useAppSelector(selectGroupList(loginAccount));
const { setOpenAuthModal } = useOffChainAuth();
Expand All @@ -79,6 +84,8 @@ export const ViewerList = memo<ViewerListProps>(function ViewerList({ selectObje
const [open, setOpen] = useState(false);
const [invalidIds, setInvalidIds] = useState<string[]>([]);
const objectInfo = selectObjectInfo.ObjectInfo;
// share bucket
const bucketName = objectInfo.BucketName || _bucketName;
const path = [bucketName, objectInfo.ObjectName].join('/');
const memberList = (objectPolicies[path] || []) as Array<PolicyMeta & Partial<ObjectResource>>;
const memberListLoading = !(path in objectPolicies);
Expand All @@ -88,7 +95,7 @@ export const ViewerList = memo<ViewerListProps>(function ViewerList({ selectObje
const [removeAccount, setRemoveAccount] = useState<string[]>([]);
const [error, setError] = useState('');
const [expiration, setExpiration] = useState<Dayjs>();
const isFolder = objectInfo.ObjectName.endsWith('/');
const isFolder = objectInfo.ObjectName.endsWith('/') || objectInfo.ObjectName === '';

const { page, canPrev, canNext } = useTableNav<PolicyMeta>({
list: memberList,
Expand Down Expand Up @@ -219,11 +226,21 @@ export const ViewerList = memo<ViewerListProps>(function ViewerList({ selectObje
resources: isFolder
? _removed
? xor(resource.Resources, [
GRNToString(newObjectGRN(bucketName, escapeRegExp(objectInfo.ObjectName))),
GRNToString(
newObjectGRN(
bucketName,
!objectInfo.ObjectName ? '*' : escapeRegExp(objectInfo.ObjectName),
),
),
])
: uniq([
...resource.Resources,
GRNToString(newObjectGRN(bucketName, escapeRegExp(objectInfo.ObjectName))),
GRNToString(
newObjectGRN(
bucketName,
!objectInfo.ObjectName ? '*' : escapeRegExp(objectInfo.ObjectName),
),
),
])
: [],
},
Expand Down
1 change: 1 addition & 0 deletions apps/dcellar-web-ui/src/modules/share/ShareCTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,5 @@ const Content = styled.div`
justify-content: center;
flex-direction: column;
text-align: center;
flex-shrink: 0;
`;
Loading

0 comments on commit 8138d5d

Please sign in to comment.