Skip to content

Commit

Permalink
Merge pull request #3587 from JoinColony/fix/3551-bring-back-action-t…
Browse files Browse the repository at this point in the history
…able-redo-logic

Fix: Enable Recent Activity Table Item Redo Functionality
  • Loading branch information
rumzledz authored Nov 12, 2024
2 parents b8ea57e + 870d8ad commit 01bf277
Show file tree
Hide file tree
Showing 14 changed files with 439 additions and 151 deletions.
24 changes: 4 additions & 20 deletions src/components/common/ColonyActionsTable/ColonyActionsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { type FC, useEffect } from 'react';
import React, { type FC } from 'react';

import { useActionSidebarContext } from '~context/ActionSidebarContext/ActionSidebarContext.ts';
import { type ColonyAction } from '~types/graphql.ts';
import { formatText } from '~utils/intl.ts';
import Table from '~v5/common/Table/index.ts';
import TableHeader from '~v5/common/TableHeader/TableHeader.tsx';

import { useActionsTableProps } from './hooks/useActionsTableProps.tsx';
import { useHandleRedoAction } from './hooks/useHandleRedoAction.ts';
import ActionsTableFilters from './partials/ActionsTableFilters/index.ts';
import { type ColonyActionsTableProps } from './types.ts';

Expand All @@ -21,24 +21,8 @@ const ColonyActionsTable: FC<ColonyActionsTableProps> = ({
rest,
actionProps.setSelectedAction,
);
const {
actionSidebarToggle: [, { toggleOn: toggleActionSidebarOn }],
} = useActionSidebarContext();

useEffect(() => {
if (actionProps.defaultValues && actionProps.selectedAction) {
toggleActionSidebarOn({ ...actionProps.defaultValues });

setTimeout(() => {
actionProps.setSelectedAction(undefined);
}, 50);
}
}, [
actionProps.defaultValues,
toggleActionSidebarOn,
actionProps.selectedAction,
actionProps,
]);

useHandleRedoAction({ actionProps });

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type ColonyAction } from '~types/graphql.ts';
import Table from '~v5/common/Table/index.ts';

import { useActionsTableProps } from './hooks/useActionsTableProps.tsx';
import { useHandleRedoAction } from './hooks/useHandleRedoAction.ts';
import { type ColonyActionsTableProps } from './types.ts';

const displayName = 'common.RecentActivityTable';
Expand Down Expand Up @@ -34,6 +35,8 @@ const RecentActivityTable: FC<ColonyActionsTableProps> = ({
actionProps.setSelectedAction,
);

useHandleRedoAction({ actionProps });

return (
<Table<ColonyAction>
{...tableProps}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
import {
ArrowSquareOut,
FilePlus,
ShareNetwork,
Binoculars,
Repeat,
} from '@phosphor-icons/react';
import { Binoculars } from '@phosphor-icons/react';
import clsx from 'clsx';
import React from 'react';
import { generatePath, useNavigate } from 'react-router-dom';

import { APP_URL, DEFAULT_NETWORK_INFO } from '~constants';
import { useActionSidebarContext } from '~context/ActionSidebarContext/ActionSidebarContext.ts';
import { useColonyContext } from '~context/ColonyContext/ColonyContext.ts';
import { useMobile } from '~hooks/index.ts';
import { type ActivityFeedColonyAction } from '~hooks/useActivityFeed/types.ts';
import {
COLONY_ACTIVITY_ROUTE,
COLONY_HOME_ROUTE,
TX_SEARCH_PARAM,
} from '~routes';
import TransactionLink from '~shared/TransactionLink/index.ts';
import { type ColonyAction } from '~types/graphql.ts';
import { formatText } from '~utils/intl.ts';
import { merge } from '~utils/lodash.ts';
import EmptyContent from '~v5/common/EmptyContent/index.ts';
import { MEATBALL_MENU_COLUMN_ID } from '~v5/common/Table/consts.ts';
import { type TableProps } from '~v5/common/Table/types.ts';

import { useFiltersContext } from '../FiltersContext/FiltersContext.ts';
import MeatballMenuCopyItem from '../partials/MeatballMenuCopyItem/MeatballMenuCopyItem.tsx';
import { type ColonyActionsTableProps } from '../types.ts';

import useActionsTableData from './useActionsTableData.ts';
import useColonyActionsTableColumns from './useColonyActionsTableColumns.tsx';
import { useGetMenuProps } from './useGetMenuProps.tsx';
import useRenderRowLink from './useRenderRowLink.tsx';
import useRenderSubComponent from './useRenderSubComponent.tsx';

export const useActionsTableProps = (
props: Omit<ColonyActionsTableProps, 'withHeader' | 'actionProps'>,
setAction: (actionHash: string) => void,
setAction: ColonyActionsTableProps['actionProps']['setSelectedAction'],
) => {
const {
className,
Expand All @@ -53,8 +36,8 @@ export const useActionsTableProps = (
const { searchFilter, selectedFiltersCount } = useFiltersContext();

const {
data,
loading,
data: colonyActions,
loading: colonyActionsLoading,
loadingMotionStates,
goToNextPage,
goToPreviousPage,
Expand All @@ -67,86 +50,35 @@ export const useActionsTableProps = (
} = useActionsTableData(pageSize);

const columns = useColonyActionsTableColumns({
loading,
loading: colonyActionsLoading,
loadingMotionStates,
refetchMotionStates,
showUserAvatar,
});
const {
actionSidebarToggle: [, { toggleOn: toggleActionSidebarOn }],
} = useActionSidebarContext();
const navigate = useNavigate();
const {
colony: { name: colonyName },
} = useColonyContext();
const getMenuProps: TableProps<ActivityFeedColonyAction>['getMenuProps'] = ({
original: { transactionHash },
}) => ({
disabled: loading,
dropdownPlacementProps: {
withAutoTopPlacement: true,
top: 10,
},
items: [
{
key: '1',
label: formatText({ id: 'activityFeedTable.menu.view' }),
icon: FilePlus,
onClick: () => {
navigate(
`${window.location.pathname}?${TX_SEARCH_PARAM}=${transactionHash}`,
{
replace: true,
},
);
},
},
{
key: '2',
label: (
<TransactionLink hash={transactionHash}>
{formatText(
{ id: 'activityFeedTable.menu.viewOnNetwork' },
{
blockExplorerName: DEFAULT_NETWORK_INFO.blockExplorerName,
},
)}
</TransactionLink>
),
icon: ArrowSquareOut,
},
{
key: '3',
label: formatText({ id: 'activityFeedTable.menu.share' }),
renderItemWrapper: (itemWrapperProps, children) => (
<MeatballMenuCopyItem
textToCopy={`${APP_URL.origin}/${generatePath(COLONY_HOME_ROUTE, {
colonyName,
})}${COLONY_ACTIVITY_ROUTE}?${TX_SEARCH_PARAM}=${transactionHash}`}
{...itemWrapperProps}
>
{children}
</MeatballMenuCopyItem>
),
icon: ShareNetwork,
onClick: () => false,
},
{
key: '4',
label: formatText({ id: 'completedAction.redoAction' }),
icon: Repeat,
onClick: () => setAction(transactionHash),
},
],

const getMenuProps = useGetMenuProps({
setAction,
colonyActions,
colonyActionsLoading,
});
const isMobile = useMobile();
const renderRowLink = useRenderRowLink(loading, isRecentActivityVariant);

const renderRowLink = useRenderRowLink(
colonyActionsLoading,
isRecentActivityVariant,
);

const renderSubComponent = useRenderSubComponent({
loadingMotionStates,
loading,
loading: colonyActionsLoading,
refetchMotionStates,
getMenuProps,
});

const isMobile = useMobile();

const tableProps = merge(
{
className: clsx(
Expand All @@ -155,7 +87,8 @@ export const useActionsTableProps = (
{
'sm:[&_td]:h-[66px]': isRecentActivityVariant,
'sm:[&_td]:h-[70px]': !isRecentActivityVariant,
'sm:[&_tr:hover]:bg-gray-25': data.length > 0 && !loading,
'sm:[&_tr:hover]:bg-gray-25':
colonyActions.length > 0 && !colonyActionsLoading,
},
),
enableSortingRemoval: false,
Expand All @@ -178,22 +111,22 @@ export const useActionsTableProps = (
pageSize,
},
},
additionalPaginationButtonsContent: loading
additionalPaginationButtonsContent: colonyActionsLoading
? undefined
: additionalPaginationButtonsContent,
onSortingChange: setSorting,
getRowId: (row) => row.transactionHash,
meatBallMenuStaticSize: isRecentActivityVariant ? '2rem' : '3rem',
getMenuProps,
columns,
data,
data: colonyActions,
manualPagination: true,
canNextPage: hasNextPage || loading,
canNextPage: hasNextPage || colonyActionsLoading,
canPreviousPage: hasPrevPage,
showTotalPagesNumber,
nextPage: goToNextPage,
previousPage: goToPreviousPage,
paginationDisabled: loading,
paginationDisabled: colonyActionsLoading,
getRowCanExpand: () => isMobile,
emptyContent: (
<EmptyContent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { useEffect, useState } from 'react';

import { ColonyActionType, useGetColonyHistoricRoleRolesLazyQuery } from '~gql';
import { type ActivityFeedColonyAction } from '~hooks/useActivityFeed/types.ts';
import { ExtendedColonyActionType } from '~types/actions.ts';
import { getHistoricRolesDatabaseId } from '~utils/databaseId.ts';
import { transformActionRolesToColonyRoles } from '~v5/common/CompletedAction/partials/SetUserRoles/utils.ts';

export const useBuildRedoEnabledActionsMap = ({
colonyActions = [],
colonyActionsLoading,
}: {
colonyActions?: ActivityFeedColonyAction[];
colonyActionsLoading: boolean;
}) => {
const [redoEnabledActionsMap, setRedoEnabledActionsMap] = useState<
Record<ActivityFeedColonyAction['transactionHash'], boolean>
>({});

const [getHistoricRoles] = useGetColonyHistoricRoleRolesLazyQuery({
fetchPolicy: 'cache-and-network',
});

// I'm using simple stringification to help the useEffect hook with shallow comparison and avoid unnecessary rerenders
const stringifiedColonyActions = JSON.stringify(colonyActions);

useEffect(() => {
const buildRedoEnabledActionsMap = async () => {
const originalColonyActions = JSON.parse(
stringifiedColonyActions,
) as typeof colonyActions;

if (colonyActionsLoading || originalColonyActions.length === 0) {
return;
}

const updatedActionsMap: typeof redoEnabledActionsMap = {};
const promises: Promise<void>[] = [];

originalColonyActions.forEach((colonyAction) => {
switch (
colonyAction.type as ColonyActionType | ExtendedColonyActionType
) {
case ColonyActionType.SetUserRoles:
case ColonyActionType.SetUserRolesMotion:
case ColonyActionType.SetUserRolesMultisig: {
const {
blockNumber,
colonyAddress,
fromDomain,
recipientAddress,
rolesAreMultiSig,
roles,
motionData,
multiSigData,
} = colonyAction;

const promise = async () => {
const result = await getHistoricRoles({
variables: {
id: getHistoricRolesDatabaseId({
blockNumber,
colonyAddress,
nativeId: fromDomain?.nativeId,
recipientAddress,
isMultiSig: rolesAreMultiSig,
}),
},
});

const dbPermissionsNew = transformActionRolesToColonyRoles(
result?.data?.getColonyHistoricRole || roles,
);

const isMotion = !!motionData;
const isMultiSig = !!multiSigData;

const shouldShowRedoItem =
!!dbPermissionsNew.length ||
(isMotion && !motionData?.isFinalized) ||
(isMultiSig && !multiSigData?.isExecuted);

updatedActionsMap[colonyAction.transactionHash] =
shouldShowRedoItem;
};

promises.push(promise());
break;
}

case ColonyActionType.AddVerifiedMembers:
case ColonyActionType.AddVerifiedMembersMotion:
case ColonyActionType.AddVerifiedMembersMultisig:
case ColonyActionType.CreateDecisionMotion:
case ColonyActionType.ColonyEdit:
case ColonyActionType.ColonyEditMotion:
case ColonyActionType.ColonyEditMultisig:
case ColonyActionType.CreateDomain:
case ColonyActionType.CreateDomainMotion:
case ColonyActionType.CreateDomainMultisig:
case ColonyActionType.EditDomain:
case ColonyActionType.EditDomainMotion:
case ColonyActionType.EditDomainMultisig:
case ColonyActionType.RemoveVerifiedMembers:
case ColonyActionType.RemoveVerifiedMembersMotion:
case ColonyActionType.RemoveVerifiedMembersMultisig:
case ColonyActionType.UnlockToken:
case ColonyActionType.UnlockTokenMotion:
case ColonyActionType.UnlockTokenMultisig:
case ColonyActionType.VersionUpgrade:
case ColonyActionType.VersionUpgradeMotion:
case ColonyActionType.VersionUpgradeMultisig:
case ExtendedColonyActionType.UpdateColonyObjective:
case ExtendedColonyActionType.UpdateColonyObjectiveMotion:
case ExtendedColonyActionType.UpdateColonyObjectiveMultisig:
updatedActionsMap[colonyAction.transactionHash] = false;
break;

default:
updatedActionsMap[colonyAction.transactionHash] = true;
}
});

await Promise.all(promises);

setRedoEnabledActionsMap(updatedActionsMap);
};

buildRedoEnabledActionsMap();
}, [colonyActionsLoading, getHistoricRoles, stringifiedColonyActions]);

return redoEnabledActionsMap;
};
Loading

0 comments on commit 01bf277

Please sign in to comment.