Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Enable Recent Activity Table Item Redo Functionality #3587

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading