Skip to content

Commit 01bf277

Browse files
authored
Merge pull request #3587 from JoinColony/fix/3551-bring-back-action-table-redo-logic
Fix: Enable Recent Activity Table Item Redo Functionality
2 parents b8ea57e + 870d8ad commit 01bf277

File tree

14 files changed

+439
-151
lines changed

14 files changed

+439
-151
lines changed

src/components/common/ColonyActionsTable/ColonyActionsTable.tsx

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import React, { type FC, useEffect } from 'react';
1+
import React, { type FC } from 'react';
22

3-
import { useActionSidebarContext } from '~context/ActionSidebarContext/ActionSidebarContext.ts';
43
import { type ColonyAction } from '~types/graphql.ts';
54
import { formatText } from '~utils/intl.ts';
65
import Table from '~v5/common/Table/index.ts';
76
import TableHeader from '~v5/common/TableHeader/TableHeader.tsx';
87

98
import { useActionsTableProps } from './hooks/useActionsTableProps.tsx';
9+
import { useHandleRedoAction } from './hooks/useHandleRedoAction.ts';
1010
import ActionsTableFilters from './partials/ActionsTableFilters/index.ts';
1111
import { type ColonyActionsTableProps } from './types.ts';
1212

@@ -21,24 +21,8 @@ const ColonyActionsTable: FC<ColonyActionsTableProps> = ({
2121
rest,
2222
actionProps.setSelectedAction,
2323
);
24-
const {
25-
actionSidebarToggle: [, { toggleOn: toggleActionSidebarOn }],
26-
} = useActionSidebarContext();
27-
28-
useEffect(() => {
29-
if (actionProps.defaultValues && actionProps.selectedAction) {
30-
toggleActionSidebarOn({ ...actionProps.defaultValues });
31-
32-
setTimeout(() => {
33-
actionProps.setSelectedAction(undefined);
34-
}, 50);
35-
}
36-
}, [
37-
actionProps.defaultValues,
38-
toggleActionSidebarOn,
39-
actionProps.selectedAction,
40-
actionProps,
41-
]);
24+
25+
useHandleRedoAction({ actionProps });
4226

4327
return (
4428
<>

src/components/common/ColonyActionsTable/RecentActivityTable.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { type ColonyAction } from '~types/graphql.ts';
66
import Table from '~v5/common/Table/index.ts';
77

88
import { useActionsTableProps } from './hooks/useActionsTableProps.tsx';
9+
import { useHandleRedoAction } from './hooks/useHandleRedoAction.ts';
910
import { type ColonyActionsTableProps } from './types.ts';
1011

1112
const displayName = 'common.RecentActivityTable';
@@ -34,6 +35,8 @@ const RecentActivityTable: FC<ColonyActionsTableProps> = ({
3435
actionProps.setSelectedAction,
3536
);
3637

38+
useHandleRedoAction({ actionProps });
39+
3740
return (
3841
<Table<ColonyAction>
3942
{...tableProps}

src/components/common/ColonyActionsTable/hooks/useActionsTableProps.tsx

Lines changed: 27 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,27 @@
1-
import {
2-
ArrowSquareOut,
3-
FilePlus,
4-
ShareNetwork,
5-
Binoculars,
6-
Repeat,
7-
} from '@phosphor-icons/react';
1+
import { Binoculars } from '@phosphor-icons/react';
82
import clsx from 'clsx';
93
import React from 'react';
10-
import { generatePath, useNavigate } from 'react-router-dom';
114

12-
import { APP_URL, DEFAULT_NETWORK_INFO } from '~constants';
135
import { useActionSidebarContext } from '~context/ActionSidebarContext/ActionSidebarContext.ts';
14-
import { useColonyContext } from '~context/ColonyContext/ColonyContext.ts';
156
import { useMobile } from '~hooks/index.ts';
16-
import { type ActivityFeedColonyAction } from '~hooks/useActivityFeed/types.ts';
17-
import {
18-
COLONY_ACTIVITY_ROUTE,
19-
COLONY_HOME_ROUTE,
20-
TX_SEARCH_PARAM,
21-
} from '~routes';
22-
import TransactionLink from '~shared/TransactionLink/index.ts';
237
import { type ColonyAction } from '~types/graphql.ts';
24-
import { formatText } from '~utils/intl.ts';
258
import { merge } from '~utils/lodash.ts';
269
import EmptyContent from '~v5/common/EmptyContent/index.ts';
2710
import { MEATBALL_MENU_COLUMN_ID } from '~v5/common/Table/consts.ts';
2811
import { type TableProps } from '~v5/common/Table/types.ts';
2912

3013
import { useFiltersContext } from '../FiltersContext/FiltersContext.ts';
31-
import MeatballMenuCopyItem from '../partials/MeatballMenuCopyItem/MeatballMenuCopyItem.tsx';
3214
import { type ColonyActionsTableProps } from '../types.ts';
3315

3416
import useActionsTableData from './useActionsTableData.ts';
3517
import useColonyActionsTableColumns from './useColonyActionsTableColumns.tsx';
18+
import { useGetMenuProps } from './useGetMenuProps.tsx';
3619
import useRenderRowLink from './useRenderRowLink.tsx';
3720
import useRenderSubComponent from './useRenderSubComponent.tsx';
3821

3922
export const useActionsTableProps = (
4023
props: Omit<ColonyActionsTableProps, 'withHeader' | 'actionProps'>,
41-
setAction: (actionHash: string) => void,
24+
setAction: ColonyActionsTableProps['actionProps']['setSelectedAction'],
4225
) => {
4326
const {
4427
className,
@@ -53,8 +36,8 @@ export const useActionsTableProps = (
5336
const { searchFilter, selectedFiltersCount } = useFiltersContext();
5437

5538
const {
56-
data,
57-
loading,
39+
data: colonyActions,
40+
loading: colonyActionsLoading,
5841
loadingMotionStates,
5942
goToNextPage,
6043
goToPreviousPage,
@@ -67,86 +50,35 @@ export const useActionsTableProps = (
6750
} = useActionsTableData(pageSize);
6851

6952
const columns = useColonyActionsTableColumns({
70-
loading,
53+
loading: colonyActionsLoading,
7154
loadingMotionStates,
7255
refetchMotionStates,
7356
showUserAvatar,
7457
});
7558
const {
7659
actionSidebarToggle: [, { toggleOn: toggleActionSidebarOn }],
7760
} = useActionSidebarContext();
78-
const navigate = useNavigate();
79-
const {
80-
colony: { name: colonyName },
81-
} = useColonyContext();
82-
const getMenuProps: TableProps<ActivityFeedColonyAction>['getMenuProps'] = ({
83-
original: { transactionHash },
84-
}) => ({
85-
disabled: loading,
86-
dropdownPlacementProps: {
87-
withAutoTopPlacement: true,
88-
top: 10,
89-
},
90-
items: [
91-
{
92-
key: '1',
93-
label: formatText({ id: 'activityFeedTable.menu.view' }),
94-
icon: FilePlus,
95-
onClick: () => {
96-
navigate(
97-
`${window.location.pathname}?${TX_SEARCH_PARAM}=${transactionHash}`,
98-
{
99-
replace: true,
100-
},
101-
);
102-
},
103-
},
104-
{
105-
key: '2',
106-
label: (
107-
<TransactionLink hash={transactionHash}>
108-
{formatText(
109-
{ id: 'activityFeedTable.menu.viewOnNetwork' },
110-
{
111-
blockExplorerName: DEFAULT_NETWORK_INFO.blockExplorerName,
112-
},
113-
)}
114-
</TransactionLink>
115-
),
116-
icon: ArrowSquareOut,
117-
},
118-
{
119-
key: '3',
120-
label: formatText({ id: 'activityFeedTable.menu.share' }),
121-
renderItemWrapper: (itemWrapperProps, children) => (
122-
<MeatballMenuCopyItem
123-
textToCopy={`${APP_URL.origin}/${generatePath(COLONY_HOME_ROUTE, {
124-
colonyName,
125-
})}${COLONY_ACTIVITY_ROUTE}?${TX_SEARCH_PARAM}=${transactionHash}`}
126-
{...itemWrapperProps}
127-
>
128-
{children}
129-
</MeatballMenuCopyItem>
130-
),
131-
icon: ShareNetwork,
132-
onClick: () => false,
133-
},
134-
{
135-
key: '4',
136-
label: formatText({ id: 'completedAction.redoAction' }),
137-
icon: Repeat,
138-
onClick: () => setAction(transactionHash),
139-
},
140-
],
61+
62+
const getMenuProps = useGetMenuProps({
63+
setAction,
64+
colonyActions,
65+
colonyActionsLoading,
14166
});
142-
const isMobile = useMobile();
143-
const renderRowLink = useRenderRowLink(loading, isRecentActivityVariant);
67+
68+
const renderRowLink = useRenderRowLink(
69+
colonyActionsLoading,
70+
isRecentActivityVariant,
71+
);
72+
14473
const renderSubComponent = useRenderSubComponent({
14574
loadingMotionStates,
146-
loading,
75+
loading: colonyActionsLoading,
14776
refetchMotionStates,
14877
getMenuProps,
14978
});
79+
80+
const isMobile = useMobile();
81+
15082
const tableProps = merge(
15183
{
15284
className: clsx(
@@ -155,7 +87,8 @@ export const useActionsTableProps = (
15587
{
15688
'sm:[&_td]:h-[66px]': isRecentActivityVariant,
15789
'sm:[&_td]:h-[70px]': !isRecentActivityVariant,
158-
'sm:[&_tr:hover]:bg-gray-25': data.length > 0 && !loading,
90+
'sm:[&_tr:hover]:bg-gray-25':
91+
colonyActions.length > 0 && !colonyActionsLoading,
15992
},
16093
),
16194
enableSortingRemoval: false,
@@ -178,22 +111,22 @@ export const useActionsTableProps = (
178111
pageSize,
179112
},
180113
},
181-
additionalPaginationButtonsContent: loading
114+
additionalPaginationButtonsContent: colonyActionsLoading
182115
? undefined
183116
: additionalPaginationButtonsContent,
184117
onSortingChange: setSorting,
185118
getRowId: (row) => row.transactionHash,
186119
meatBallMenuStaticSize: isRecentActivityVariant ? '2rem' : '3rem',
187120
getMenuProps,
188121
columns,
189-
data,
122+
data: colonyActions,
190123
manualPagination: true,
191-
canNextPage: hasNextPage || loading,
124+
canNextPage: hasNextPage || colonyActionsLoading,
192125
canPreviousPage: hasPrevPage,
193126
showTotalPagesNumber,
194127
nextPage: goToNextPage,
195128
previousPage: goToPreviousPage,
196-
paginationDisabled: loading,
129+
paginationDisabled: colonyActionsLoading,
197130
getRowCanExpand: () => isMobile,
198131
emptyContent: (
199132
<EmptyContent
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { useEffect, useState } from 'react';
2+
3+
import { ColonyActionType, useGetColonyHistoricRoleRolesLazyQuery } from '~gql';
4+
import { type ActivityFeedColonyAction } from '~hooks/useActivityFeed/types.ts';
5+
import { ExtendedColonyActionType } from '~types/actions.ts';
6+
import { getHistoricRolesDatabaseId } from '~utils/databaseId.ts';
7+
import { transformActionRolesToColonyRoles } from '~v5/common/CompletedAction/partials/SetUserRoles/utils.ts';
8+
9+
export const useBuildRedoEnabledActionsMap = ({
10+
colonyActions = [],
11+
colonyActionsLoading,
12+
}: {
13+
colonyActions?: ActivityFeedColonyAction[];
14+
colonyActionsLoading: boolean;
15+
}) => {
16+
const [redoEnabledActionsMap, setRedoEnabledActionsMap] = useState<
17+
Record<ActivityFeedColonyAction['transactionHash'], boolean>
18+
>({});
19+
20+
const [getHistoricRoles] = useGetColonyHistoricRoleRolesLazyQuery({
21+
fetchPolicy: 'cache-and-network',
22+
});
23+
24+
// I'm using simple stringification to help the useEffect hook with shallow comparison and avoid unnecessary rerenders
25+
const stringifiedColonyActions = JSON.stringify(colonyActions);
26+
27+
useEffect(() => {
28+
const buildRedoEnabledActionsMap = async () => {
29+
const originalColonyActions = JSON.parse(
30+
stringifiedColonyActions,
31+
) as typeof colonyActions;
32+
33+
if (colonyActionsLoading || originalColonyActions.length === 0) {
34+
return;
35+
}
36+
37+
const updatedActionsMap: typeof redoEnabledActionsMap = {};
38+
const promises: Promise<void>[] = [];
39+
40+
originalColonyActions.forEach((colonyAction) => {
41+
switch (
42+
colonyAction.type as ColonyActionType | ExtendedColonyActionType
43+
) {
44+
case ColonyActionType.SetUserRoles:
45+
case ColonyActionType.SetUserRolesMotion:
46+
case ColonyActionType.SetUserRolesMultisig: {
47+
const {
48+
blockNumber,
49+
colonyAddress,
50+
fromDomain,
51+
recipientAddress,
52+
rolesAreMultiSig,
53+
roles,
54+
motionData,
55+
multiSigData,
56+
} = colonyAction;
57+
58+
const promise = async () => {
59+
const result = await getHistoricRoles({
60+
variables: {
61+
id: getHistoricRolesDatabaseId({
62+
blockNumber,
63+
colonyAddress,
64+
nativeId: fromDomain?.nativeId,
65+
recipientAddress,
66+
isMultiSig: rolesAreMultiSig,
67+
}),
68+
},
69+
});
70+
71+
const dbPermissionsNew = transformActionRolesToColonyRoles(
72+
result?.data?.getColonyHistoricRole || roles,
73+
);
74+
75+
const isMotion = !!motionData;
76+
const isMultiSig = !!multiSigData;
77+
78+
const shouldShowRedoItem =
79+
!!dbPermissionsNew.length ||
80+
(isMotion && !motionData?.isFinalized) ||
81+
(isMultiSig && !multiSigData?.isExecuted);
82+
83+
updatedActionsMap[colonyAction.transactionHash] =
84+
shouldShowRedoItem;
85+
};
86+
87+
promises.push(promise());
88+
break;
89+
}
90+
91+
case ColonyActionType.AddVerifiedMembers:
92+
case ColonyActionType.AddVerifiedMembersMotion:
93+
case ColonyActionType.AddVerifiedMembersMultisig:
94+
case ColonyActionType.CreateDecisionMotion:
95+
case ColonyActionType.ColonyEdit:
96+
case ColonyActionType.ColonyEditMotion:
97+
case ColonyActionType.ColonyEditMultisig:
98+
case ColonyActionType.CreateDomain:
99+
case ColonyActionType.CreateDomainMotion:
100+
case ColonyActionType.CreateDomainMultisig:
101+
case ColonyActionType.EditDomain:
102+
case ColonyActionType.EditDomainMotion:
103+
case ColonyActionType.EditDomainMultisig:
104+
case ColonyActionType.RemoveVerifiedMembers:
105+
case ColonyActionType.RemoveVerifiedMembersMotion:
106+
case ColonyActionType.RemoveVerifiedMembersMultisig:
107+
case ColonyActionType.UnlockToken:
108+
case ColonyActionType.UnlockTokenMotion:
109+
case ColonyActionType.UnlockTokenMultisig:
110+
case ColonyActionType.VersionUpgrade:
111+
case ColonyActionType.VersionUpgradeMotion:
112+
case ColonyActionType.VersionUpgradeMultisig:
113+
case ExtendedColonyActionType.UpdateColonyObjective:
114+
case ExtendedColonyActionType.UpdateColonyObjectiveMotion:
115+
case ExtendedColonyActionType.UpdateColonyObjectiveMultisig:
116+
updatedActionsMap[colonyAction.transactionHash] = false;
117+
break;
118+
119+
default:
120+
updatedActionsMap[colonyAction.transactionHash] = true;
121+
}
122+
});
123+
124+
await Promise.all(promises);
125+
126+
setRedoEnabledActionsMap(updatedActionsMap);
127+
};
128+
129+
buildRedoEnabledActionsMap();
130+
}, [colonyActionsLoading, getHistoricRoles, stringifiedColonyActions]);
131+
132+
return redoEnabledActionsMap;
133+
};

0 commit comments

Comments
 (0)