Refactor UI folder (#2016)

* Added Overview page

* Revised Getting Started page

* Minor revision

* Edited readme, minor modifications to docs

* Removed sweep.yaml, .devcontainer, .ergomake

* Moved security.md to .github, added contributing.md

* changes as per code review

* updated contributing.md

* fixed broken links & added missing links in doc, improved structure

* fixed link in wsl setup

* fixed server link, added https cloning in yarn-setup

* removed package-lock.json

* added doc card, admonitions

* removed underline from nav buttons

* refactoring modules/ui

* refactoring modules/ui

* Change folder case

* Fix theme location

* Fix case 2

* Fix storybook

---------

Co-authored-by: Nimra Ahmed <nimra1408@gmail.com>
Co-authored-by: Nimra Ahmed <50912134+nimraahmed@users.noreply.github.com>
This commit is contained in:
Charles Bochet
2023-10-14 00:04:29 +02:00
committed by GitHub
parent a35ea5e8f9
commit 258685467b
732 changed files with 1106 additions and 1010 deletions

View File

@ -0,0 +1,24 @@
import { useSetRecoilState } from 'recoil';
import { IconTrash } from '@/ui/display/icon';
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
import { useDeleteSelectedBoardCards } from './useDeleteSelectedBoardCards';
export const useBoardActionBarEntries = () => {
const setActionBarEntries = useSetRecoilState(actionBarEntriesState);
const deleteSelectedBoardCards = useDeleteSelectedBoardCards();
return {
setActionBarEntries: () =>
setActionBarEntries([
{
label: 'Delete',
Icon: IconTrash,
accent: 'danger',
onClick: deleteSelectedBoardCards,
},
]),
};
};

View File

@ -0,0 +1,27 @@
import { ViewFieldForVisibility } from '@/ui/data/view-bar/types/ViewFieldForVisibility';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState';
import { useBoardContext } from './useBoardContext';
export const useBoardCardFields = () => {
const { BoardRecoilScopeContext } = useBoardContext();
const [, setBoardCardFields] = useRecoilScopedState(
boardCardFieldsScopedState,
BoardRecoilScopeContext,
);
const handleFieldVisibilityChange = (field: ViewFieldForVisibility) => {
setBoardCardFields((previousFields) =>
previousFields.map((previousField) =>
previousField.key === field.key
? { ...previousField, isVisible: !field.isVisible }
: previousField,
),
);
};
return { handleFieldVisibilityChange };
};

View File

@ -0,0 +1,53 @@
import { useRecoilState } from 'recoil';
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
import { useUpdatePipelineStageMutation } from '~/generated/graphql';
import { boardColumnsState } from '../states/boardColumnsState';
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
export const useBoardColumns = () => {
const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
const { handleColumnMove } = useMoveViewColumns();
const [updatePipelineStageMutation] = useUpdatePipelineStageMutation();
const updatedPipelineStages = (stages: BoardColumnDefinition[]) => {
if (!stages.length) return;
return Promise.all(
stages.map((stage) =>
updatePipelineStageMutation({
variables: {
data: {
index: stage.index,
},
id: stage.id,
},
}),
),
);
};
const persistBoardColumns = async () => {
await updatedPipelineStages(boardColumns);
};
const handleMoveBoardColumn = (
direction: 'left' | 'right',
column: BoardColumnDefinition,
) => {
const currentColumnArrayIndex = boardColumns.findIndex(
(tableColumn) => tableColumn.id === column.id,
);
const columns = handleColumnMove(
direction,
currentColumnArrayIndex,
boardColumns,
);
setBoardColumns(columns);
};
return { handleMoveBoardColumn, persistBoardColumns };
};

View File

@ -0,0 +1,7 @@
import { useContext } from 'react';
import { BoardContext } from '@/companies/states/contexts/BoardContext';
export const useBoardContext = () => {
return useContext(BoardContext);
};

View File

@ -0,0 +1,24 @@
import { useSetRecoilState } from 'recoil';
import { IconTrash } from '@/ui/display/icon';
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
import { useDeleteSelectedBoardCards } from './useDeleteSelectedBoardCards';
export const useBoardContextMenuEntries = () => {
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
const deleteSelectedBoardCards = useDeleteSelectedBoardCards();
return {
setContextMenuEntries: () =>
setContextMenuEntries([
{
label: 'Delete',
Icon: IconTrash,
accent: 'danger',
onClick: () => deleteSelectedBoardCards(),
},
]),
};
};

View File

@ -0,0 +1,61 @@
import { useContext } from 'react';
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState';
import { BoardCardIdContext } from '../contexts/BoardCardIdContext';
import { activeCardIdsState } from '../states/activeCardIdsState';
import { isCardSelectedFamilyState } from '../states/isCardSelectedFamilyState';
export const useCurrentCardSelected = () => {
const currentCardId = useContext(BoardCardIdContext);
const isCardSelected = useRecoilValue(
isCardSelectedFamilyState(currentCardId ?? ''),
);
const setActiveCardIds = useSetRecoilState(activeCardIdsState);
const setCurrentCardSelected = useRecoilCallback(
({ set }) =>
(selected: boolean) => {
if (!currentCardId) return;
set(isCardSelectedFamilyState(currentCardId), selected);
set(actionBarOpenState, selected);
if (selected) {
setActiveCardIds((prevActiveCardIds) => [
...prevActiveCardIds,
currentCardId,
]);
} else {
setActiveCardIds((prevActiveCardIds) =>
prevActiveCardIds.filter((id) => id !== currentCardId),
);
}
},
[currentCardId, setActiveCardIds],
);
const unselectAllActiveCards = useRecoilCallback(
({ set, snapshot }) =>
() => {
const activeCardIds = snapshot.getLoadable(activeCardIdsState).contents;
activeCardIds.forEach((cardId: string) => {
set(isCardSelectedFamilyState(cardId), false);
});
set(activeCardIdsState, []);
set(actionBarOpenState, false);
},
[],
);
return {
currentCardSelected: isCardSelected,
setCurrentCardSelected,
unselectAllActiveCards,
};
};

View File

@ -0,0 +1,40 @@
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilValue } from 'recoil';
import { GET_PIPELINES } from '@/pipeline/graphql/queries/getPipelines';
import { useDeleteManyPipelineProgressMutation } from '~/generated/graphql';
import { selectedCardIdsSelector } from '../states/selectors/selectedCardIdsSelector';
import { useRemoveCardIds } from './useRemoveCardIds';
export const useDeleteSelectedBoardCards = () => {
const selectedCardIds = useRecoilValue(selectedCardIdsSelector);
const removeCardIds = useRemoveCardIds();
const [deletePipelineProgress] = useDeleteManyPipelineProgressMutation({
refetchQueries: [getOperationName(GET_PIPELINES) ?? ''],
});
const deleteSelectedBoardCards = async () => {
await deletePipelineProgress({
variables: {
ids: selectedCardIds,
},
optimisticResponse: {
__typename: 'Mutation',
deleteManyPipelineProgress: {
count: selectedCardIds.length,
},
},
update: (cache) => {
removeCardIds(selectedCardIds);
selectedCardIds.forEach((id) => {
cache.evict({ id: `PipelineProgress:${id}` });
});
},
});
};
return deleteSelectedBoardCards;
};

View File

@ -0,0 +1,26 @@
// Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
import { useRecoilCallback } from 'recoil';
import { boardCardIdsByColumnIdFamilyState } from '../states/boardCardIdsByColumnIdFamilyState';
import { boardColumnsState } from '../states/boardColumnsState';
export const useRemoveCardIds = () =>
useRecoilCallback(
({ snapshot, set }) =>
(cardIdToRemove: string[]) => {
const boardColumns = snapshot
.getLoadable(boardColumnsState)
.valueOrThrow();
boardColumns.forEach((boardColumn) => {
const columnCardIds = snapshot
.getLoadable(boardCardIdsByColumnIdFamilyState(boardColumn.id))
.valueOrThrow();
set(
boardCardIdsByColumnIdFamilyState(boardColumn.id),
columnCardIds.filter((cardId) => !cardIdToRemove.includes(cardId)),
);
});
},
[],
);

View File

@ -0,0 +1,29 @@
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState';
import { activeCardIdsState } from '../states/activeCardIdsState';
import { isCardSelectedFamilyState } from '../states/isCardSelectedFamilyState';
export const useSetCardSelected = () => {
const setActionBarOpenState = useSetRecoilState(actionBarOpenState);
return useRecoilCallback(
({ set, snapshot }) =>
(cardId: string, selected: boolean) => {
const activeCardIds = snapshot.getLoadable(activeCardIdsState).contents;
set(isCardSelectedFamilyState(cardId), selected);
setActionBarOpenState(selected || activeCardIds.length > 0);
if (selected) {
set(activeCardIdsState, [...activeCardIds, cardId]);
} else {
set(
activeCardIdsState,
activeCardIds.filter((id: string) => id !== cardId),
);
}
},
);
};

View File

@ -0,0 +1,85 @@
import { DropResult } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
import { useRecoilCallback } from 'recoil';
import { boardCardIdsByColumnIdFamilyState } from '../states/boardCardIdsByColumnIdFamilyState';
import { boardColumnsState } from '../states/boardColumnsState';
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
export const useUpdateBoardCardIds = () =>
useRecoilCallback(
({ snapshot, set }) =>
(result: DropResult) => {
const currentBoardColumns = snapshot
.getLoadable(boardColumnsState)
.valueOrThrow();
const newBoardColumns = [...currentBoardColumns];
const { destination, source } = result;
if (!destination) return;
const sourceColumnIndex = newBoardColumns.findIndex(
(boardColumn: BoardColumnDefinition) =>
boardColumn.id === source.droppableId,
);
const sourceColumn = newBoardColumns[sourceColumnIndex];
const destinationColumnIndex = newBoardColumns.findIndex(
(boardColumn: BoardColumnDefinition) =>
boardColumn.id === destination.droppableId,
);
const destinationColumn = newBoardColumns[destinationColumnIndex];
if (!destinationColumn || !sourceColumn) return;
const sourceCardIds = [
...snapshot
.getLoadable(boardCardIdsByColumnIdFamilyState(sourceColumn.id))
.valueOrThrow(),
];
const destinationCardIds = [
...snapshot
.getLoadable(
boardCardIdsByColumnIdFamilyState(destinationColumn.id),
)
.valueOrThrow(),
];
const destinationIndex =
destination.index >= destinationCardIds.length
? destinationCardIds.length - 1
: destination.index;
if (sourceColumn.id === destinationColumn.id) {
const [deletedCardId] = sourceCardIds.splice(source.index, 1);
sourceCardIds.splice(destinationIndex, 0, deletedCardId);
set(
boardCardIdsByColumnIdFamilyState(sourceColumn.id),
sourceCardIds,
);
} else {
const [removedCardId] = sourceCardIds.splice(source.index, 1);
destinationCardIds.splice(destinationIndex, 0, removedCardId);
set(
boardCardIdsByColumnIdFamilyState(sourceColumn.id),
sourceCardIds,
);
set(
boardCardIdsByColumnIdFamilyState(destinationColumn.id),
destinationCardIds,
);
}
return newBoardColumns;
},
[],
);