mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-24 05:01:46 +03:00
feat: support group by status in kanban mode, resolved #40
This commit is contained in:
parent
418e260ade
commit
f18f51ba7c
@ -41,6 +41,7 @@ const getKanbanColor = (
|
||||
return DEFAULT_COLOR;
|
||||
}
|
||||
if (
|
||||
group.type === PropertyType.Status ||
|
||||
group.type === PropertyType.Select ||
|
||||
group.type === PropertyType.MultiSelect ||
|
||||
group.type === DEFAULT_GROUP_ID
|
||||
|
@ -4,7 +4,7 @@ import { ModifyPanelContentProps } from './types';
|
||||
import { StyledDivider, StyledPopoverSubTitle } from '../StyledComponent';
|
||||
import { BasicSelect } from './Select';
|
||||
import { InformationProperty, InformationValue } from '../../recast-block';
|
||||
import { genInitialOptions, getPendantIconsConfigByName } from '../utils';
|
||||
import { generateInitialOptions, getPendantIconsConfigByName } from '../utils';
|
||||
|
||||
export default (props: ModifyPanelContentProps) => {
|
||||
const { onPropertyChange, onValueChange, initialValue, property } = props;
|
||||
@ -38,7 +38,7 @@ export default (props: ModifyPanelContentProps) => {
|
||||
}}
|
||||
initialOptions={
|
||||
propProperty?.emailOptions ||
|
||||
genInitialOptions(
|
||||
generateInitialOptions(
|
||||
property?.type,
|
||||
getPendantIconsConfigByName('Email')
|
||||
)
|
||||
@ -66,7 +66,7 @@ export default (props: ModifyPanelContentProps) => {
|
||||
}}
|
||||
initialOptions={
|
||||
propProperty?.phoneOptions ||
|
||||
genInitialOptions(
|
||||
generateInitialOptions(
|
||||
property?.type,
|
||||
getPendantIconsConfigByName('Phone')
|
||||
)
|
||||
@ -94,7 +94,7 @@ export default (props: ModifyPanelContentProps) => {
|
||||
}}
|
||||
initialOptions={
|
||||
propProperty?.locationOptions ||
|
||||
genInitialOptions(
|
||||
generateInitialOptions(
|
||||
property?.type,
|
||||
getPendantIconsConfigByName('Location')
|
||||
)
|
||||
|
@ -21,7 +21,7 @@ import {
|
||||
} from '@toeverything/components/ui';
|
||||
import { HighLightIconInput } from './IconInput';
|
||||
import { PendantConfig, IconNames, OptionIdType, OptionType } from '../types';
|
||||
import { genBasicOption } from '../utils';
|
||||
import { generateBasicOption } from '../utils';
|
||||
|
||||
type OptionItemType = {
|
||||
option: OptionType;
|
||||
@ -66,7 +66,7 @@ export const BasicSelect = ({
|
||||
const [selectIds, setSelectIds] = useState<OptionIdType[]>(initialValue);
|
||||
|
||||
const insertOption = (insertId: OptionIdType) => {
|
||||
const newOption = genBasicOption({
|
||||
const newOption = generateBasicOption({
|
||||
index: options.length + 1,
|
||||
iconConfig,
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Input, Option, Select, Tooltip } from '@toeverything/components/ui';
|
||||
import { HelpCenterIcon } from '@toeverything/components/icons';
|
||||
import { AsyncBlock } from '../../editor';
|
||||
@ -15,13 +14,13 @@ import {
|
||||
StyledPopoverSubTitle,
|
||||
StyledPopoverWrapper,
|
||||
} from '../StyledComponent';
|
||||
import { genInitialOptions, getPendantConfigByType } from '../utils';
|
||||
import {
|
||||
generateRandomFieldName,
|
||||
generateInitialOptions,
|
||||
getPendantConfigByType,
|
||||
} from '../utils';
|
||||
import { useOnCreateSure } from './hooks';
|
||||
|
||||
const upperFirst = (str: string) => {
|
||||
return `${str[0].toUpperCase()}${str.slice(1)}`;
|
||||
};
|
||||
|
||||
export const CreatePendantPanel = ({
|
||||
block,
|
||||
onSure,
|
||||
@ -35,7 +34,7 @@ export const CreatePendantPanel = ({
|
||||
|
||||
useEffect(() => {
|
||||
selectedOption &&
|
||||
setFieldName(upperFirst(`${selectedOption.type}#${nanoid(4)}`));
|
||||
setFieldName(generateRandomFieldName(selectedOption.type));
|
||||
}, [selectedOption]);
|
||||
|
||||
return (
|
||||
@ -93,7 +92,7 @@ export const CreatePendantPanel = ({
|
||||
<PendantModifyPanel
|
||||
type={selectedOption.type}
|
||||
// Select, MultiSelect, Status use this props as initial property
|
||||
initialOptions={genInitialOptions(
|
||||
initialOptions={generateInitialOptions(
|
||||
selectedOption.type,
|
||||
getPendantConfigByType(selectedOption.type)
|
||||
)}
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
import { OptionIdType, OptionType } from './types';
|
||||
import { pendantConfig } from './config';
|
||||
import { PendantConfig, PendantTypes } from './types';
|
||||
import { nanoid } from 'nanoid';
|
||||
type Props = {
|
||||
recastBlockId: string;
|
||||
blockId: string;
|
||||
@ -60,7 +61,7 @@ export const getPendantHistory = ({
|
||||
return data[recastBlockId] ?? {};
|
||||
};
|
||||
|
||||
export const removePropertyValueRecord = ({
|
||||
export const removePendantHistory = ({
|
||||
recastBlockId,
|
||||
propertyId,
|
||||
}: {
|
||||
@ -107,7 +108,7 @@ export const getOfficialSelected = ({
|
||||
.map(id => {
|
||||
return tempOptions.findIndex((o: OptionType) => o.id === id);
|
||||
})
|
||||
.filter(index => index != -1);
|
||||
.filter(index => index !== -1);
|
||||
selectedId = selectedIndex.map((index: number) => {
|
||||
return options[index].id;
|
||||
});
|
||||
@ -130,7 +131,7 @@ export const getPendantIconsConfigByName = (
|
||||
return pendantConfig[pendantName];
|
||||
};
|
||||
|
||||
export const genBasicOption = ({
|
||||
export const generateBasicOption = ({
|
||||
index,
|
||||
iconConfig,
|
||||
name = '',
|
||||
@ -159,22 +160,22 @@ export const genBasicOption = ({
|
||||
/**
|
||||
* Status Pendant is a Select Pendant built-in some options
|
||||
* **/
|
||||
export const genInitialOptions = (
|
||||
export const generateInitialOptions = (
|
||||
type: PendantTypes,
|
||||
iconConfig: PendantConfig
|
||||
) => {
|
||||
if (type === PendantTypes.Status) {
|
||||
return [
|
||||
genBasicOption({ index: 0, iconConfig, name: 'No Started' }),
|
||||
genBasicOption({
|
||||
generateBasicOption({ index: 0, iconConfig, name: 'No Started' }),
|
||||
generateBasicOption({
|
||||
index: 1,
|
||||
iconConfig,
|
||||
name: 'In Progress',
|
||||
}),
|
||||
genBasicOption({ index: 2, iconConfig, name: 'Complete' }),
|
||||
generateBasicOption({ index: 2, iconConfig, name: 'Complete' }),
|
||||
];
|
||||
}
|
||||
return [genBasicOption({ index: 0, iconConfig })];
|
||||
return [generateBasicOption({ index: 0, iconConfig })];
|
||||
};
|
||||
|
||||
export const checkPendantForm = (
|
||||
@ -222,3 +223,10 @@ export const checkPendantForm = (
|
||||
|
||||
return { passed: true, message: 'Check passed !' };
|
||||
};
|
||||
|
||||
const upperFirst = (str: string) => {
|
||||
return `${str[0].toUpperCase()}${str.slice(1)}`;
|
||||
};
|
||||
|
||||
export const generateRandomFieldName = (type: PendantTypes) =>
|
||||
upperFirst(`${type}#${nanoid(4)}`);
|
||||
|
@ -10,6 +10,12 @@ import {
|
||||
} from '../recast-block/types';
|
||||
import type { DefaultGroup, KanbanGroup } from './types';
|
||||
import { DEFAULT_GROUP_ID } from './types';
|
||||
import {
|
||||
generateInitialOptions,
|
||||
generateRandomFieldName,
|
||||
getPendantIconsConfigByName,
|
||||
} from '../block-pendant/utils';
|
||||
import { SelectOption } from '../recast-block';
|
||||
|
||||
/**
|
||||
* - If the `groupBy` is `SelectProperty` or `MultiSelectProperty`, return `(Multi)SelectProperty.options`.
|
||||
@ -23,6 +29,7 @@ export const getGroupOptions = async (
|
||||
return [];
|
||||
}
|
||||
switch (groupBy.type) {
|
||||
case PropertyType.Status:
|
||||
case PropertyType.Select:
|
||||
case PropertyType.MultiSelect: {
|
||||
return groupBy.options.map(option => ({
|
||||
@ -57,6 +64,9 @@ const isValueBelongOption = (
|
||||
case PropertyType.MultiSelect: {
|
||||
return propertyValue.value.some(i => i === option.id);
|
||||
}
|
||||
case PropertyType.Status: {
|
||||
return propertyValue.value === option.id;
|
||||
}
|
||||
// case PropertyType.Text: {
|
||||
// TOTODO:DO support this type
|
||||
// }
|
||||
@ -107,6 +117,7 @@ export const moveCardToGroup = async (
|
||||
success = await removeValue(groupById);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (group.type) {
|
||||
case PropertyType.Select: {
|
||||
success = await setValue({
|
||||
@ -116,6 +127,14 @@ export const moveCardToGroup = async (
|
||||
});
|
||||
break;
|
||||
}
|
||||
case PropertyType.Status: {
|
||||
success = await setValue({
|
||||
id: groupById,
|
||||
type: group.type,
|
||||
value: group.id,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case PropertyType.MultiSelect: {
|
||||
success = await setValue({
|
||||
id: groupById,
|
||||
@ -194,14 +213,18 @@ export const genDefaultGroup = (groupBy: RecastMetaProperty): DefaultGroup => ({
|
||||
items: [],
|
||||
});
|
||||
|
||||
export const DEFAULT_GROUP_BY_PROPERTY = {
|
||||
name: 'Status',
|
||||
options: [
|
||||
{ name: 'No Started', color: '#E53535', background: '#FFCECE' },
|
||||
{ name: 'In Progress', color: '#A77F1A', background: '#FFF5AB' },
|
||||
{ name: 'Complete', color: '#3C8867', background: '#C5FBE0' },
|
||||
],
|
||||
};
|
||||
export const generateDefaultGroupByProperty = (): {
|
||||
name: string;
|
||||
options: Omit<SelectOption, 'id'>[];
|
||||
type: PropertyType.Status;
|
||||
} => ({
|
||||
name: generateRandomFieldName(PropertyType.Status),
|
||||
type: PropertyType.Status,
|
||||
options: generateInitialOptions(
|
||||
PropertyType.Status,
|
||||
getPendantIconsConfigByName(PropertyType.Status)
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* Unwrap blocks from the grid recursively.
|
||||
|
@ -7,6 +7,7 @@ export const useKanbanGroup = (groupBy: RecastMetaProperty) => {
|
||||
const { updateSelect } = useSelectProperty();
|
||||
|
||||
switch (groupBy.type) {
|
||||
case PropertyType.Status:
|
||||
case PropertyType.MultiSelect:
|
||||
case PropertyType.Select: {
|
||||
const {
|
||||
|
@ -18,8 +18,8 @@ import {
|
||||
import { supportChildren } from '../utils';
|
||||
import {
|
||||
calcCardGroup,
|
||||
DEFAULT_GROUP_BY_PROPERTY,
|
||||
genDefaultGroup,
|
||||
generateDefaultGroupByProperty,
|
||||
getCardGroup,
|
||||
getGroupOptions,
|
||||
moveCardToAfter,
|
||||
@ -48,6 +48,7 @@ export const useRecastKanbanGroupBy = () => {
|
||||
// Add other type groupBy support
|
||||
const supportedGroupBy = getProperties().filter(
|
||||
prop =>
|
||||
prop.type === PropertyType.Status ||
|
||||
prop.type === PropertyType.Select ||
|
||||
prop.type === PropertyType.MultiSelect
|
||||
);
|
||||
@ -88,7 +89,8 @@ export const useRecastKanbanGroupBy = () => {
|
||||
// TODO: support other property type
|
||||
if (
|
||||
groupByProperty.type !== PropertyType.Select &&
|
||||
groupByProperty.type !== PropertyType.MultiSelect
|
||||
groupByProperty.type !== PropertyType.MultiSelect &&
|
||||
groupByProperty.type !== PropertyType.Status
|
||||
) {
|
||||
console.warn('Not support groupBy type', groupByProperty);
|
||||
|
||||
@ -134,7 +136,7 @@ export const useInitKanbanEffect = ():
|
||||
}
|
||||
// 3. no group by, no properties
|
||||
// create a new property and set it as group by
|
||||
const prop = await createSelect(DEFAULT_GROUP_BY_PROPERTY);
|
||||
const prop = await createSelect(generateDefaultGroupByProperty());
|
||||
await setGroupBy(prop.id);
|
||||
};
|
||||
|
||||
|
@ -46,7 +46,10 @@ export type DefaultGroup = KanbanGroupBase & {
|
||||
|
||||
type SelectGroup = KanbanGroupBase &
|
||||
SelectOption & {
|
||||
type: PropertyType.Select | PropertyType.MultiSelect;
|
||||
type:
|
||||
| PropertyType.Select
|
||||
| PropertyType.MultiSelect
|
||||
| PropertyType.Status;
|
||||
};
|
||||
|
||||
type TextGroup = KanbanGroupBase & {
|
||||
|
@ -257,14 +257,12 @@ export const getRecastItemValue = (block: RecastItem | AsyncBlock) => {
|
||||
const isSelectLikeProperty = (
|
||||
metaProperty?: RecastMetaProperty
|
||||
): metaProperty is SelectProperty | MultiSelectProperty => {
|
||||
if (
|
||||
return !(
|
||||
!metaProperty ||
|
||||
(metaProperty.type !== PropertyType.Select &&
|
||||
(metaProperty.type !== PropertyType.Status &&
|
||||
metaProperty.type !== PropertyType.Select &&
|
||||
metaProperty.type !== PropertyType.MultiSelect)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -312,7 +310,7 @@ export const useSelectProperty = () => {
|
||||
};
|
||||
|
||||
const updateSelect = (
|
||||
selectProperty: SelectProperty | MultiSelectProperty
|
||||
selectProperty: StatusProperty | SelectProperty | MultiSelectProperty
|
||||
) => {
|
||||
// if (typeof selectProperty === 'string') {
|
||||
// const maybeSelectProperty = getProperty(selectProperty);
|
||||
|
Loading…
Reference in New Issue
Block a user