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

select visible columns in settings side panel #614

Merged
merged 4 commits into from
Nov 14, 2024
Merged
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
2 changes: 1 addition & 1 deletion libs/ui/src/components/Explorer/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
refetch
});

const settingsButton = useOpenSettings();
const settingsButton = useOpenSettings(library);

return (
<>
Expand Down
89 changes: 89 additions & 0 deletions libs/ui/src/components/Explorer/edit-settings/ColumnItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {KitTypography} from 'aristid-ds';
import {FunctionComponent, ReactNode} from 'react';
import {FaChevronRight, FaEye, FaEyeSlash, FaGripLines} from 'react-icons/fa';
import styled from 'styled-components';

const StyledValue = styled(KitTypography.Text)`
color: var(--general-utilities-disabled);
`;

const StyledConfigurationItem = styled.li`
list-style: none;
color: var(--general-utilities-text-primary);
display: flex;
width: 100%;
height: 40px;
padding: 0 calc(var(--general-spacing-xs) * 1px);
align-items: center;
gap: calc(var(--general-spacing-xs) * 1px);
border-radius: calc(var(--general-spacing-xs) * 1px);
text-align: left;

&:first-child {
margin-top: calc(var(--general-spacing-xs) * 1px);
}

&:hover {
background: var(--general-utilities-main-light);

${StyledValue} {
color: var(--general-utilities-text-primary);
}
}

.title {
flex: 1 1 auto;
}

> svg {
flex: 0 0 calc(var(--general-spacing-s) * 1px);
}

> button {
border: none;
background: transparent;
padding: 0;
&:not([disabled]) {
cursor: pointer;
}
}
`;

const StyledFaEye = styled(FaEye)`
color: currentColor;
`;

const StyledEyeSlash = styled(FaEyeSlash)`
color: var(--general-utilities-disabled);
`;

const StyledEmptyIcon = styled.div`
width: calc(var(--general-spacing-s) * 1px);
`;

interface IColumnItemProps {
dragHandler?: ReactNode;
visible: boolean;
title: string;
onVisibilityClick?: () => void;
disabled?: boolean;
value?: string;
}

export const ColumnItem: FunctionComponent<IColumnItemProps> = ({
dragHandler,
title,
disabled,
visible,
onVisibilityClick
}) => (
<StyledConfigurationItem className={disabled ? 'disabled' : ''}>
{dragHandler || <StyledEmptyIcon />}
<KitTypography.Text size="fontSize5" ellipsis className="title">
{title}
</KitTypography.Text>
<button disabled={disabled} onClick={onVisibilityClick}>
{visible ? <StyledFaEye /> : <StyledEyeSlash />}
</button>
</StyledConfigurationItem>
);
58 changes: 52 additions & 6 deletions libs/ui/src/components/Explorer/edit-settings/DisplayMode.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,57 @@
// Copyright LEAV Solutions 2017 until 2023/11/05, Copyright Aristid from 2023/11/06
// This file is released under LGPL V3
// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {FunctionComponent} from 'react';
import {KitRadio, KitSpace, KitTag} from 'aristid-ds';
import {RadioChangeEvent} from 'aristid-ds/dist/Kit/DataEntry/Radio';
import {FunctionComponent, useState} from 'react';
import styled from 'styled-components';
import {DisplayModeTable} from './DisplayModeTable';

export const DisplayMode: FunctionComponent = () => {
const StyledWrapperDiv = styled.div`
display: flex;
flex-direction: column;
gap: calc(var(--general-spacing-l) * 1px);

.ant-radio-wrapper {
padding: calc(var(--general-spacing-xs) * 1px);
}
`;

interface IDisplayModeProps {
library: string;
}

export const DisplayMode: FunctionComponent<IDisplayModeProps> = ({library}) => {
const {t} = useSharedTranslation();
const [currentDisplayMode, setCurrentDisplayMode] = useState('table');

const _handleDisplayModeChange = (event: RadioChangeEvent) => {
setCurrentDisplayMode(event.target.value);
};

const comingSoonTag = <KitTag type="secondary" idCardProps={{description: String(t('explorer.coming-soon'))}} />;

return <div>TODO</div>;
return (
<StyledWrapperDiv>
<KitRadio.Group value={currentDisplayMode} onChange={_handleDisplayModeChange}>
<KitSpace direction="vertical" size={0}>
<KitRadio value="list" disabled>
<KitSpace>
{t('explorer.display-mode-list')} {comingSoonTag}
</KitSpace>
</KitRadio>
<KitRadio value="table">{t('explorer.display-mode-table')}</KitRadio>
<KitRadio value="mosaic" disabled>
<KitSpace>
{t('explorer.display-mode-mosaic')} {comingSoonTag}
</KitSpace>
</KitRadio>
<KitRadio value="planning" disabled>
<KitSpace>
{t('explorer.display-mode-planning')} {comingSoonTag}
</KitSpace>
</KitRadio>
</KitSpace>
</KitRadio.Group>
{currentDisplayMode === 'table' && <DisplayModeTable library={library} />}
</StyledWrapperDiv>
);
};
115 changes: 115 additions & 0 deletions libs/ui/src/components/Explorer/edit-settings/DisplayModeTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {useDebouncedValue} from '_ui/hooks/useDebouncedValue/useDebouncedValue';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {KitInput, KitTypography} from 'aristid-ds';
import {ChangeEvent, FunctionComponent, useMemo, useState} from 'react';
import styled from 'styled-components';
import {FaGripLines} from 'react-icons/fa';
import {ColumnItem} from './ColumnItem';
import {useGetLibraryColumns} from './useGetLibraryColumns';

const StyledList = styled.ul`
padding: 0;
margin: 0;
list-style: none;
color: var(--general-utilities-text-primary);
`;

const StyledDivider = styled.hr`
display: block;
height: 1px;
border: 0;
border-top: 1px solid var(--general-utilities-main-light);
margin: 0 calc(var(--general-spacing-s) * 1px);
padding: 0;
`;

interface IDisplayModeTableProps {
library: string;
}

export const DisplayModeTable: FunctionComponent<IDisplayModeTableProps> = ({library}) => {
const {t} = useSharedTranslation();
// TODO Where to stock visible columns list
// TODO when are changes saved (and thus, when is the table updated) ?
const [orderedVisibleColumns, setOrderedVisibleColumns] = useState<string[]>([]);
const [searchInput, setSearchInput] = useState('');
const debouncedSearchInput = useDebouncedValue(searchInput, 300);

const {attributeDetailsById} = useGetLibraryColumns(library);

const searchFilteredColumns = useMemo(() => {
const columnIds = Object.keys(attributeDetailsById);
if (columnIds.length === 0) {
return {};
}
if (searchInput === '') {
return attributeDetailsById;
}

return columnIds.reduce((acc, columnId) => {
if (attributeDetailsById[columnId].label.includes(searchInput) || columnId.includes(searchInput)) {
acc[columnId] = attributeDetailsById[columnId];
}
return acc;
}, {});
}, [debouncedSearchInput, attributeDetailsById]);
const searchFilteredColumnsIds = Object.keys(searchFilteredColumns);

const _onSearchChanged = (event: ChangeEvent<HTMLInputElement>) => {
const shouldIgnoreInputChange = event.target.value.length < 3 && searchInput.length < 3;
if (shouldIgnoreInputChange) {
return;
}
setSearchInput(() => {
if (event.target.value.length > 2) {
return event.target.value;
}
return '';
});
};

const _toggleColumnVisibility = (columnId: string) => () => {
setOrderedVisibleColumns(() => {
if (orderedVisibleColumns.includes(columnId)) {
return orderedVisibleColumns.filter(id => id !== columnId);
}
return [...orderedVisibleColumns, columnId];
});
};

return (
<div>
<KitTypography.Title level="h4">{t('items_list.columns')}</KitTypography.Title>
<KitInput placeholder={String(t('global.search'))} onChange={_onSearchChanged} allowClear></KitInput>
<div>
<StyledList>
<ColumnItem title={t('record_edition.whoAmI')} visible={false} disabled />
{orderedVisibleColumns
.filter(columnId => searchFilteredColumnsIds[columnId])
.map(columnId => (
<ColumnItem
key={columnId}
title={attributeDetailsById[columnId].label}
visible
onVisibilityClick={_toggleColumnVisibility(columnId)}
dragHandler={<FaGripLines />}
/>
))}
</StyledList>
<StyledDivider />
evoiron marked this conversation as resolved.
Show resolved Hide resolved
<StyledList>
{searchFilteredColumnsIds
.filter(columnId => !orderedVisibleColumns.includes(columnId))
.map(columnId => (
<ColumnItem
key={attributeDetailsById[columnId].id}
visible={false}
title={attributeDetailsById[columnId].label}
onVisibilityClick={_toggleColumnVisibility(columnId)}
/>
))}
</StyledList>
</div>
</div>
);
};
6 changes: 4 additions & 2 deletions libs/ui/src/components/Explorer/edit-settings/SettingItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ const StyledConfigurationItem = styled.li`
}
`;

export const SettingItem: FunctionComponent<{
interface ISettingItemProps {
icon: ReactNode;
title: string;
onClick: () => void;
value?: string;
}> = ({icon, title, value = '', onClick}) => (
}

export const SettingItem: FunctionComponent<ISettingItemProps> = ({icon, title, value = '', onClick}) => (
<StyledConfigurationItem>
<button onClick={onClick}>
{icon}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ const ConfigurationStyledMenu = styled.menu`
padding: 0;
`;

export const SettingsPanel: FunctionComponent = () => {
interface ISettingsPanelProps {
library: string;
}

export const SettingsPanel: FunctionComponent<ISettingsPanelProps> = ({library}) => {
const {t} = useSharedTranslation();

const {setActiveSettings, activeSettings} = useEditSettings();
Expand Down Expand Up @@ -91,7 +95,7 @@ export const SettingsPanel: FunctionComponent = () => {
</ConfigurationStyledMenu>
</nav>
)}
{currentPage === 'display-mode' && <DisplayMode />}
{currentPage === 'display-mode' && <DisplayMode library={library} />}
</ContentWrapperStyledDiv>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jest.mock('./DisplayMode', () => ({
}));

const MockOpenEditSettings: FunctionComponent = () => {
const OpenEditSettingsButton = useOpenSettings();
const OpenEditSettingsButton = useOpenSettings('');

return <>{OpenEditSettingsButton}</>;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright LEAV Solutions 2017 until 2023/11/05, Copyright Aristid from 2023/11/06
// This file is released under LGPL V3
// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt
import {AttributeDetailsFragment, GetAttributesByLibQuery, useGetAttributesByLibQuery} from '../../../_gqlTypes';
import {useLang} from '../../../hooks';
import {localizedTranslation} from '@leav/utils';

interface IColumnsById {
[attributeId: string]: AttributeDetailsFragment;
}

const _mapping = (data: GetAttributesByLibQuery | undefined, availableLangs: string[]): IColumnsById =>
data?.attributes?.list.reduce((acc, attribute) => {
acc[attribute.id] = {
...attribute,
label: localizedTranslation(attribute.label, availableLangs)
};
return acc;
}, {}) ?? {};

export const useGetLibraryColumns = (library: string) => {
const {lang: availableLangs} = useLang();
const {data, error, loading} = useGetAttributesByLibQuery({
variables: {
library
}
});

const attributeDetailsById = _mapping(data, availableLangs);

return {attributeDetailsById, error, loading};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {SettingsPanel} from './SettingsPanel';
import {useEditSettings} from './useEditSettings';

export const useOpenSettings = () => {
export const useOpenSettings = (library: string) => {
const {setActiveSettings} = useEditSettings();
const {t} = useSharedTranslation();

const _openSettingsPanel = () =>
setActiveSettings({
content: <SettingsPanel />,
content: <SettingsPanel library={library} />,
title: t('explorer.settings')
});

Expand Down
7 changes: 6 additions & 1 deletion libs/ui/src/locales/en/shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,12 @@
"back": "Back",
"view-configuration": "View Configuration",
"display-mode": "Display Mode",
"display-mode-list": "List",
"display-mode-table": "Table",
"display-mode-mosaic": "Mosaic",
"display-mode-planning": "Planning",
"filters": "Filters",
"sort": "Sort"
"sort": "Sort",
"coming-soon": "Coming soon"
}
}
Loading
Loading