mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: tauri kanban fixes (#2273)
* chore: group cards count * chore: delete board card * chore: date time format read and update * fix: move field * fix: dnd fields * chore: number format popup * chore: refactor date options * chore: replace button in DateFormatPopup with PopupItem --------- Co-authored-by: qinluhe <qinluhe.twodog@gmail.com>
This commit is contained in:
parent
2838cd5e0c
commit
55cb7acc7f
6
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
6
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -640,6 +640,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -657,6 +658,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -678,6 +680,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -689,6 +692,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -705,6 +709,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -722,6 +727,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
|
@ -0,0 +1,96 @@
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
import { PopupWindow } from '$app/components/_shared/PopupWindow';
|
||||
import { CheckmarkSvg } from '$app/components/_shared/svg/CheckmarkSvg';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DateFormatPB } from '@/services/backend';
|
||||
import { useDateTimeFormat } from '$app/components/_shared/EditRow/DateTimeFormat.hooks';
|
||||
import { useAppSelector } from '$app/stores/store';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { IDateType } from '$app/stores/reducers/database/slice';
|
||||
|
||||
export const DateFormatPopup = ({
|
||||
left,
|
||||
top,
|
||||
cellIdentifier,
|
||||
fieldController,
|
||||
onOutsideClick,
|
||||
}: {
|
||||
left: number;
|
||||
top: number;
|
||||
cellIdentifier: CellIdentifier;
|
||||
fieldController: FieldController;
|
||||
onOutsideClick: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation('');
|
||||
const { changeDateFormat } = useDateTimeFormat(cellIdentifier, fieldController);
|
||||
const databaseStore = useAppSelector((state) => state.database);
|
||||
const [dateType, setDateType] = useState<IDateType | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
setDateType(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as IDateType);
|
||||
}, [databaseStore]);
|
||||
|
||||
const changeFormat = async (format: DateFormatPB) => {
|
||||
await changeDateFormat(format);
|
||||
onOutsideClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<PopupWindow className={'p-2 text-xs'} onOutsideClick={onOutsideClick} left={left} top={top}>
|
||||
<PopupItem
|
||||
changeFormat={changeFormat}
|
||||
format={DateFormatPB.Friendly}
|
||||
checked={dateType?.dateFormat === DateFormatPB.Friendly}
|
||||
text={t('grid.field.dateFormatFriendly')}
|
||||
/>
|
||||
<PopupItem
|
||||
changeFormat={changeFormat}
|
||||
format={DateFormatPB.ISO}
|
||||
checked={dateType?.dateFormat === DateFormatPB.ISO}
|
||||
text={t('grid.field.dateFormatISO')}
|
||||
/>
|
||||
<PopupItem
|
||||
changeFormat={changeFormat}
|
||||
format={DateFormatPB.Local}
|
||||
checked={dateType?.dateFormat === DateFormatPB.Local}
|
||||
text={t('grid.field.dateFormatLocal')}
|
||||
/>
|
||||
<PopupItem
|
||||
changeFormat={changeFormat}
|
||||
format={DateFormatPB.US}
|
||||
checked={dateType?.dateFormat === DateFormatPB.US}
|
||||
text={t('grid.field.dateFormatUS')}
|
||||
/>
|
||||
</PopupWindow>
|
||||
);
|
||||
};
|
||||
|
||||
function PopupItem({
|
||||
format,
|
||||
text,
|
||||
changeFormat,
|
||||
checked,
|
||||
}: {
|
||||
format: DateFormatPB;
|
||||
text: string;
|
||||
changeFormat: (_: DateFormatPB) => Promise<void>;
|
||||
checked: boolean;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
onClick={() => changeFormat(format)}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg px-2 py-1.5 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
{text}
|
||||
|
||||
{checked && (
|
||||
<div className={'ml-8 h-5 w-5 p-1'}>
|
||||
<CheckmarkSvg></CheckmarkSvg>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
@ -1,17 +1,14 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { CellCache } from '$app/stores/effects/database/cell/cell_cache';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
import Calendar from 'react-calendar';
|
||||
import dayjs from 'dayjs';
|
||||
import { ClockSvg } from '$app/components/_shared/svg/ClockSvg';
|
||||
import { MoreSvg } from '$app/components/_shared/svg/MoreSvg';
|
||||
import { EditorUncheckSvg } from '$app/components/_shared/svg/EditorUncheckSvg';
|
||||
import { useCell } from '$app/components/_shared/database-hooks/useCell';
|
||||
import { CalendarData } from '$app/stores/effects/database/cell/controller_builder';
|
||||
import { DateCellDataPB } from '@/services/backend';
|
||||
import { PopupWindow } from '$app/components/_shared/PopupWindow';
|
||||
import { DateTypeOptions } from '$app/components/_shared/EditRow/DateTypeOptions';
|
||||
|
||||
export const DatePickerPopup = ({
|
||||
left,
|
||||
@ -29,15 +26,13 @@ export const DatePickerPopup = ({
|
||||
onOutsideClick: () => void;
|
||||
}) => {
|
||||
const { data, cellController } = useCell(cellIdentifier, cellCache, fieldController);
|
||||
const { t } = useTranslation('');
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
|
||||
|
||||
useEffect(() => {
|
||||
const date_pb = data as DateCellDataPB | undefined;
|
||||
if (!date_pb || !date_pb?.date.length) return;
|
||||
|
||||
// should be changed after we can modify date format
|
||||
setSelectedDate(dayjs(date_pb.date, 'MMM DD, YYYY').toDate());
|
||||
setSelectedDate(dayjs(date_pb.date).toDate());
|
||||
}, [data]);
|
||||
|
||||
const onChange = async (v: Date | null | (Date | null)[]) => {
|
||||
@ -50,30 +45,10 @@ export const DatePickerPopup = ({
|
||||
|
||||
return (
|
||||
<PopupWindow className={'p-2 text-xs'} onOutsideClick={onOutsideClick} left={left} top={top}>
|
||||
<div className={'px-2'}>
|
||||
<div className={'px-2 pb-2'}>
|
||||
<Calendar onChange={(d) => onChange(d)} value={selectedDate} />
|
||||
</div>
|
||||
<hr className={'-mx-2 my-4 border-shade-6'} />
|
||||
<div className={'flex items-center justify-between px-4'}>
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<i className={'h-4 w-4'}>
|
||||
<ClockSvg></ClockSvg>
|
||||
</i>
|
||||
<span>{t('grid.field.includeTime')}</span>
|
||||
</div>
|
||||
<i className={'h-5 w-5'}>
|
||||
<EditorUncheckSvg></EditorUncheckSvg>
|
||||
</i>
|
||||
</div>
|
||||
<hr className={'-mx-2 my-4 border-shade-6'} />
|
||||
<div className={'flex items-center justify-between px-4 pb-2'}>
|
||||
<span>
|
||||
{t('grid.field.dateFormat')} & {t('grid.field.timeFormat')}
|
||||
</span>
|
||||
<i className={'h-5 w-5'}>
|
||||
<MoreSvg></MoreSvg>
|
||||
</i>
|
||||
</div>
|
||||
<DateTypeOptions cellIdentifier={cellIdentifier} fieldController={fieldController}></DateTypeOptions>
|
||||
</PopupWindow>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,35 @@
|
||||
import { TypeOptionController } from '$app/stores/effects/database/field/type_option/type_option_controller';
|
||||
import { Some } from 'ts-results';
|
||||
import { DateFormatPB, DateTypeOptionPB, FieldType, TimeFormatPB } from '@/services/backend';
|
||||
import { makeDateTypeOptionContext } from '$app/stores/effects/database/field/type_option/type_option_context';
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
|
||||
export const useDateTimeFormat = (cellIdentifier: CellIdentifier, fieldController: FieldController) => {
|
||||
const changeFormat = async (change: (option: DateTypeOptionPB) => void) => {
|
||||
const fieldInfo = fieldController.getField(cellIdentifier.fieldId);
|
||||
if (!fieldInfo) return;
|
||||
const typeOptionController = new TypeOptionController(cellIdentifier.viewId, Some(fieldInfo), FieldType.DateTime);
|
||||
await typeOptionController.initialize();
|
||||
const dateTypeOptionContext = makeDateTypeOptionContext(typeOptionController);
|
||||
const typeOption = await dateTypeOptionContext.getTypeOption().then((a) => a.unwrap());
|
||||
change(typeOption);
|
||||
await dateTypeOptionContext.setTypeOption(typeOption);
|
||||
};
|
||||
|
||||
const changeDateFormat = async (format: DateFormatPB) => {
|
||||
await changeFormat((option) => (option.date_format = format));
|
||||
};
|
||||
const changeTimeFormat = async (format: TimeFormatPB) => {
|
||||
await changeFormat((option) => (option.time_format = format));
|
||||
};
|
||||
const includeTime = async (include: boolean) => {
|
||||
await changeFormat((option) => (option.include_time = include));
|
||||
};
|
||||
|
||||
return {
|
||||
changeDateFormat,
|
||||
changeTimeFormat,
|
||||
includeTime,
|
||||
};
|
||||
};
|
@ -0,0 +1,149 @@
|
||||
import { DateFormatPopup } from '$app/components/_shared/EditRow/DateFormatPopup';
|
||||
import { TimeFormatPopup } from '$app/components/_shared/EditRow/TimeFormatPopup';
|
||||
import { MoreSvg } from '$app/components/_shared/svg/MoreSvg';
|
||||
import { EditorCheckSvg } from '$app/components/_shared/svg/EditorCheckSvg';
|
||||
import { EditorUncheckSvg } from '$app/components/_shared/svg/EditorUncheckSvg';
|
||||
import { MouseEventHandler, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IDateType } from '$app/stores/reducers/database/slice';
|
||||
import { useAppSelector } from '$app/stores/store';
|
||||
import { useDateTimeFormat } from '$app/components/_shared/EditRow/DateTimeFormat.hooks';
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
|
||||
export const DateTypeOptions = ({
|
||||
cellIdentifier,
|
||||
fieldController,
|
||||
}: {
|
||||
cellIdentifier: CellIdentifier;
|
||||
fieldController: FieldController;
|
||||
}) => {
|
||||
const { t } = useTranslation('');
|
||||
|
||||
const [showDateFormatPopup, setShowDateFormatPopup] = useState(false);
|
||||
const [dateFormatTop, setDateFormatTop] = useState(0);
|
||||
const [dateFormatLeft, setDateFormatLeft] = useState(0);
|
||||
|
||||
const [showTimeFormatPopup, setShowTimeFormatPopup] = useState(false);
|
||||
const [timeFormatTop, setTimeFormatTop] = useState(0);
|
||||
const [timeFormatLeft, setTimeFormatLeft] = useState(0);
|
||||
|
||||
const [dateType, setDateType] = useState<IDateType | undefined>();
|
||||
|
||||
const databaseStore = useAppSelector((state) => state.database);
|
||||
const { includeTime } = useDateTimeFormat(cellIdentifier, fieldController);
|
||||
|
||||
useEffect(() => {
|
||||
setDateType(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as IDateType);
|
||||
}, [databaseStore]);
|
||||
|
||||
const onDateFormatClick = (_left: number, _top: number) => {
|
||||
setShowDateFormatPopup(true);
|
||||
setDateFormatLeft(_left + 10);
|
||||
setDateFormatTop(_top);
|
||||
};
|
||||
|
||||
const onTimeFormatClick = (_left: number, _top: number) => {
|
||||
setShowTimeFormatPopup(true);
|
||||
setTimeFormatLeft(_left + 10);
|
||||
setTimeFormatTop(_top);
|
||||
};
|
||||
|
||||
const _onDateFormatClick: MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
while (!(target instanceof HTMLButtonElement)) {
|
||||
if (target.parentElement === null) return;
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
const { right: _left, top: _top } = target.getBoundingClientRect();
|
||||
onDateFormatClick(_left, _top);
|
||||
};
|
||||
|
||||
const _onTimeFormatClick: MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
while (!(target instanceof HTMLButtonElement)) {
|
||||
if (target.parentElement === null) return;
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
const { right: _left, top: _top } = target.getBoundingClientRect();
|
||||
onTimeFormatClick(_left, _top);
|
||||
};
|
||||
|
||||
const toggleIncludeTime = async () => {
|
||||
if (dateType?.includeTime) {
|
||||
await includeTime(false);
|
||||
} else {
|
||||
await includeTime(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col'}>
|
||||
<hr className={'-mx-2 my-2 border-shade-6'} />
|
||||
<button
|
||||
onClick={_onDateFormatClick}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg px-2 py-2 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
<span>{t('grid.field.dateFormat')}</span>
|
||||
<i className={'h-5 w-5'}>
|
||||
<MoreSvg></MoreSvg>
|
||||
</i>
|
||||
</button>
|
||||
<hr className={'-mx-2 my-2 border-shade-6'} />
|
||||
<button
|
||||
onClick={() => toggleIncludeTime()}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg px-2 py-2 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
<div className={'flex items-center gap-2'}>
|
||||
{/*<i className={'h-4 w-4'}>
|
||||
<ClockSvg></ClockSvg>
|
||||
</i>*/}
|
||||
<span>{t('grid.field.includeTime')}</span>
|
||||
</div>
|
||||
<i className={'h-5 w-5'}>
|
||||
{dateType?.includeTime ? <EditorCheckSvg></EditorCheckSvg> : <EditorUncheckSvg></EditorUncheckSvg>}
|
||||
</i>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={_onTimeFormatClick}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg px-2 py-2 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
<span>{t('grid.field.timeFormat')}</span>
|
||||
<i className={'h-5 w-5'}>
|
||||
<MoreSvg></MoreSvg>
|
||||
</i>
|
||||
</button>
|
||||
{showDateFormatPopup && (
|
||||
<DateFormatPopup
|
||||
top={dateFormatTop}
|
||||
left={dateFormatLeft}
|
||||
cellIdentifier={cellIdentifier}
|
||||
fieldController={fieldController}
|
||||
onOutsideClick={() => setShowDateFormatPopup(false)}
|
||||
></DateFormatPopup>
|
||||
)}
|
||||
{showTimeFormatPopup && (
|
||||
<TimeFormatPopup
|
||||
top={timeFormatTop}
|
||||
left={timeFormatLeft}
|
||||
cellIdentifier={cellIdentifier}
|
||||
fieldController={fieldController}
|
||||
onOutsideClick={() => setShowTimeFormatPopup(false)}
|
||||
></TimeFormatPopup>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
import { CellController } from '$app/stores/effects/database/cell/cell_controller';
|
||||
import { useEffect, useState, KeyboardEvent, useMemo } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const EditCellText = ({
|
||||
data,
|
||||
@ -16,6 +16,7 @@ export const EditCellText = ({
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!value?.length) return;
|
||||
setContentRows(Math.max(1, (value || '').split('\n').length));
|
||||
}, [value]);
|
||||
|
||||
|
@ -42,7 +42,7 @@ export const EditCellWrapper = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Draggable draggableId={cellIdentifier.fieldId} index={index}>
|
||||
<Draggable draggableId={cellIdentifier.fieldId} index={index} key={cellIdentifier.fieldId}>
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
@ -61,7 +61,7 @@ export const EditCellWrapper = ({
|
||||
<FieldTypeIcon fieldType={cellIdentifier.fieldType}></FieldTypeIcon>
|
||||
</div>
|
||||
<span className={'overflow-hidden text-ellipsis whitespace-nowrap'}>
|
||||
{databaseStore.fields[cellIdentifier.fieldId].title}
|
||||
{databaseStore.fields[cellIdentifier.fieldId]?.title || ''}
|
||||
</span>
|
||||
</div>
|
||||
<div className={'flex-1 cursor-pointer rounded-lg hover:bg-shade-6'}>
|
||||
|
@ -1,15 +1,17 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { MouseEventHandler, useEffect, useRef, useState } from 'react';
|
||||
import { TrashSvg } from '$app/components/_shared/svg/TrashSvg';
|
||||
import { FieldTypeIcon } from '$app/components/_shared/EditRow/FieldTypeIcon';
|
||||
import { FieldTypeName } from '$app/components/_shared/EditRow/FieldTypeName';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TypeOptionController } from '$app/stores/effects/database/field/type_option/type_option_controller';
|
||||
import { Some } from 'ts-results';
|
||||
import { FieldInfo } from '$app/stores/effects/database/field/field_controller';
|
||||
import { FieldController, FieldInfo } from '$app/stores/effects/database/field/field_controller';
|
||||
import { MoreSvg } from '$app/components/_shared/svg/MoreSvg';
|
||||
import { useAppSelector } from '$app/stores/store';
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { PopupWindow } from '$app/components/_shared/PopupWindow';
|
||||
import { FieldType } from '@/services/backend';
|
||||
import { DateTypeOptions } from '$app/components/_shared/EditRow/DateTypeOptions';
|
||||
|
||||
export const EditFieldPopup = ({
|
||||
top,
|
||||
@ -18,7 +20,9 @@ export const EditFieldPopup = ({
|
||||
viewId,
|
||||
onOutsideClick,
|
||||
fieldInfo,
|
||||
fieldController,
|
||||
changeFieldTypeClick,
|
||||
onNumberFormat,
|
||||
}: {
|
||||
top: number;
|
||||
left: number;
|
||||
@ -26,7 +30,9 @@ export const EditFieldPopup = ({
|
||||
viewId: string;
|
||||
onOutsideClick: () => void;
|
||||
fieldInfo: FieldInfo | undefined;
|
||||
fieldController?: FieldController;
|
||||
changeFieldTypeClick: (buttonTop: number, buttonRight: number) => void;
|
||||
onNumberFormat?: (buttonLeft: number, buttonTop: number) => void;
|
||||
}) => {
|
||||
const databaseStore = useAppSelector((state) => state.database);
|
||||
const { t } = useTranslation('');
|
||||
@ -59,6 +65,19 @@ export const EditFieldPopup = ({
|
||||
onOutsideClick();
|
||||
};
|
||||
|
||||
const onNumberFormatClick: MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
while (!(target instanceof HTMLButtonElement)) {
|
||||
if (target.parentElement === null) return;
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
const { right: _left, top: _top } = target.getBoundingClientRect();
|
||||
onNumberFormat?.(_left, _top);
|
||||
};
|
||||
|
||||
return (
|
||||
<PopupWindow
|
||||
className={'px-2 py-2 text-xs'}
|
||||
@ -69,7 +88,7 @@ export const EditFieldPopup = ({
|
||||
left={left}
|
||||
top={top}
|
||||
>
|
||||
<div className={'flex flex-col gap-2 p-2'}>
|
||||
<div className={'flex flex-col gap-2'}>
|
||||
<input
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
@ -79,24 +98,24 @@ export const EditFieldPopup = ({
|
||||
|
||||
<button
|
||||
onClick={() => onDeleteFieldClick()}
|
||||
className={
|
||||
'flex cursor-pointer items-center gap-2 rounded-lg px-2 py-2 text-main-alert hover:bg-main-secondary'
|
||||
}
|
||||
className={'flex cursor-pointer items-center gap-2 rounded-lg py-2 text-main-alert hover:bg-main-secondary'}
|
||||
>
|
||||
<i className={'h-5 w-5'}>
|
||||
<TrashSvg></TrashSvg>
|
||||
</i>
|
||||
<span>{t('grid.field.delete')}</span>
|
||||
<span className={'flex items-center gap-2 pl-2'}>
|
||||
<i className={'block h-5 w-5'}>
|
||||
<TrashSvg></TrashSvg>
|
||||
</i>
|
||||
<span>{t('grid.field.delete')}</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div
|
||||
ref={changeTypeButtonRef}
|
||||
onClick={() => onChangeFieldTypeClick()}
|
||||
className={
|
||||
'relative flex cursor-pointer items-center justify-between rounded-lg text-black hover:bg-main-secondary'
|
||||
'relative flex cursor-pointer items-center justify-between rounded-lg py-2 text-black hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
<button className={'flex cursor-pointer items-center gap-2 rounded-lg px-2 py-2'}>
|
||||
<button className={'flex cursor-pointer items-center gap-2 rounded-lg pl-2'}>
|
||||
<i className={'h-5 w-5'}>
|
||||
<FieldTypeIcon fieldType={cellIdentifier.fieldType}></FieldTypeIcon>
|
||||
</i>
|
||||
@ -104,10 +123,35 @@ export const EditFieldPopup = ({
|
||||
<FieldTypeName fieldType={cellIdentifier.fieldType}></FieldTypeName>
|
||||
</span>
|
||||
</button>
|
||||
<i className={'h-5 w-5'}>
|
||||
<MoreSvg></MoreSvg>
|
||||
</i>
|
||||
<span className={'pr-2'}>
|
||||
<i className={' block h-5 w-5'}>
|
||||
<MoreSvg></MoreSvg>
|
||||
</i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{cellIdentifier.fieldType === FieldType.Number && (
|
||||
<>
|
||||
<hr className={'-mx-2 border-shade-6'} />
|
||||
<button
|
||||
onClick={onNumberFormatClick}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg py-2 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
<span className={'pl-2'}>{t('grid.field.numberFormat')}</span>
|
||||
<span className={'pr-2'}>
|
||||
<i className={'block h-5 w-5'}>
|
||||
<MoreSvg></MoreSvg>
|
||||
</i>
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{cellIdentifier.fieldType === FieldType.DateTime && fieldController && (
|
||||
<DateTypeOptions cellIdentifier={cellIdentifier} fieldController={fieldController}></DateTypeOptions>
|
||||
)}
|
||||
</div>
|
||||
</PopupWindow>
|
||||
);
|
||||
|
@ -16,6 +16,7 @@ import { CellOptionsPopup } from '$app/components/_shared/EditRow/CellOptionsPop
|
||||
import { DatePickerPopup } from '$app/components/_shared/EditRow/DatePickerPopup';
|
||||
import { DragDropContext, Droppable, OnDragEndResponder } from 'react-beautiful-dnd';
|
||||
import { EditCellOptionPopup } from '$app/components/_shared/EditRow/EditCellOptionPopup';
|
||||
import { NumberFormatPopup } from '$app/components/_shared/EditRow/NumberFormatPopup';
|
||||
|
||||
export const EditRow = ({
|
||||
onClose,
|
||||
@ -55,6 +56,10 @@ export const EditRow = ({
|
||||
|
||||
const [editingSelectOption, setEditingSelectOption] = useState<SelectOptionPB | undefined>();
|
||||
|
||||
const [showNumberFormatPopup, setShowNumberFormatPopup] = useState(false);
|
||||
const [numberFormatTop, setNumberFormatTop] = useState(0);
|
||||
const [numberFormatLeft, setNumberFormatLeft] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
setUnveil(true);
|
||||
}, []);
|
||||
@ -120,10 +125,16 @@ export const EditRow = ({
|
||||
setEditCellOptionTop(_top);
|
||||
};
|
||||
|
||||
const onNumberFormat = (_left: number, _top: number) => {
|
||||
setShowNumberFormatPopup(true);
|
||||
setNumberFormatLeft(_left + 10);
|
||||
setNumberFormatTop(_top);
|
||||
};
|
||||
|
||||
const onDragEnd: OnDragEndResponder = (result) => {
|
||||
if (!result.destination?.index) return;
|
||||
void controller.moveField({
|
||||
fieldId: result.source.droppableId,
|
||||
fieldId: result.draggableId,
|
||||
fromIndex: result.source.index,
|
||||
toIndex: result.destination.index,
|
||||
});
|
||||
@ -195,7 +206,9 @@ export const EditRow = ({
|
||||
viewId={viewId}
|
||||
onOutsideClick={onOutsideEditFieldClick}
|
||||
fieldInfo={controller.fieldController.getField(editingCell.fieldId)}
|
||||
fieldController={controller.fieldController}
|
||||
changeFieldTypeClick={onChangeFieldTypeClick}
|
||||
onNumberFormat={onNumberFormat}
|
||||
></EditFieldPopup>
|
||||
)}
|
||||
{showChangeFieldTypePopup && (
|
||||
@ -238,6 +251,17 @@ export const EditRow = ({
|
||||
}}
|
||||
></EditCellOptionPopup>
|
||||
)}
|
||||
{showNumberFormatPopup && editingCell && (
|
||||
<NumberFormatPopup
|
||||
top={numberFormatTop}
|
||||
left={numberFormatLeft}
|
||||
cellIdentifier={editingCell}
|
||||
fieldController={controller.fieldController}
|
||||
onOutsideClick={() => {
|
||||
setShowNumberFormatPopup(false);
|
||||
}}
|
||||
></NumberFormatPopup>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -0,0 +1,26 @@
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
import { FieldType, NumberFormatPB } from '@/services/backend';
|
||||
import { TypeOptionController } from '$app/stores/effects/database/field/type_option/type_option_controller';
|
||||
import { Some } from 'ts-results';
|
||||
import {
|
||||
makeDateTypeOptionContext,
|
||||
makeNumberTypeOptionContext,
|
||||
} from '$app/stores/effects/database/field/type_option/type_option_context';
|
||||
|
||||
export const useNumberFormat = (cellIdentifier: CellIdentifier, fieldController: FieldController) => {
|
||||
const changeNumberFormat = async (format: NumberFormatPB) => {
|
||||
const fieldInfo = fieldController.getField(cellIdentifier.fieldId);
|
||||
if (!fieldInfo) return;
|
||||
const typeOptionController = new TypeOptionController(cellIdentifier.viewId, Some(fieldInfo), FieldType.Number);
|
||||
await typeOptionController.initialize();
|
||||
const numberTypeOptionContext = makeNumberTypeOptionContext(typeOptionController);
|
||||
const typeOption = await numberTypeOptionContext.getTypeOption().then((a) => a.unwrap());
|
||||
typeOption.format = format;
|
||||
await numberTypeOptionContext.setTypeOption(typeOption);
|
||||
};
|
||||
|
||||
return {
|
||||
changeNumberFormat,
|
||||
};
|
||||
};
|
@ -0,0 +1,108 @@
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
import { PopupWindow } from '$app/components/_shared/PopupWindow';
|
||||
import { useNumberFormat } from '$app/components/_shared/EditRow/NumberFormat.hooks';
|
||||
import { NumberFormatPB } from '@/services/backend';
|
||||
import { CheckmarkSvg } from '$app/components/_shared/svg/CheckmarkSvg';
|
||||
import { useAppSelector } from '$app/stores/store';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { INumberType } from '$app/stores/reducers/database/slice';
|
||||
|
||||
const list = [
|
||||
{ format: NumberFormatPB.Num, title: 'Num' },
|
||||
{ format: NumberFormatPB.USD, title: 'USD' },
|
||||
{ format: NumberFormatPB.CanadianDollar, title: 'CanadianDollar' },
|
||||
{ format: NumberFormatPB.EUR, title: 'EUR' },
|
||||
{ format: NumberFormatPB.Pound, title: 'Pound' },
|
||||
{ format: NumberFormatPB.Yen, title: 'Yen' },
|
||||
{ format: NumberFormatPB.Ruble, title: 'Ruble' },
|
||||
{ format: NumberFormatPB.Rupee, title: 'Rupee' },
|
||||
{ format: NumberFormatPB.Won, title: 'Won' },
|
||||
{ format: NumberFormatPB.Yuan, title: 'Yuan' },
|
||||
{ format: NumberFormatPB.Real, title: 'Real' },
|
||||
{ format: NumberFormatPB.Lira, title: 'Lira' },
|
||||
{ format: NumberFormatPB.Rupiah, title: 'Rupiah' },
|
||||
{ format: NumberFormatPB.Franc, title: 'Franc' },
|
||||
{ format: NumberFormatPB.HongKongDollar, title: 'HongKongDollar' },
|
||||
{ format: NumberFormatPB.NewZealandDollar, title: 'NewZealandDollar' },
|
||||
{ format: NumberFormatPB.Krona, title: 'Krona' },
|
||||
{ format: NumberFormatPB.NorwegianKrone, title: 'NorwegianKrone' },
|
||||
{ format: NumberFormatPB.MexicanPeso, title: 'MexicanPeso' },
|
||||
{ format: NumberFormatPB.Rand, title: 'Rand' },
|
||||
{ format: NumberFormatPB.NewTaiwanDollar, title: 'NewTaiwanDollar' },
|
||||
{ format: NumberFormatPB.DanishKrone, title: 'DanishKrone' },
|
||||
{ format: NumberFormatPB.Baht, title: 'Baht' },
|
||||
{ format: NumberFormatPB.Forint, title: 'Forint' },
|
||||
{ format: NumberFormatPB.Koruna, title: 'Koruna' },
|
||||
{ format: NumberFormatPB.Shekel, title: 'Shekel' },
|
||||
{ format: NumberFormatPB.ChileanPeso, title: 'ChileanPeso' },
|
||||
{ format: NumberFormatPB.PhilippinePeso, title: 'PhilippinePeso' },
|
||||
{ format: NumberFormatPB.Dirham, title: 'Dirham' },
|
||||
{ format: NumberFormatPB.ColombianPeso, title: 'ColombianPeso' },
|
||||
{ format: NumberFormatPB.Riyal, title: 'Riyal' },
|
||||
{ format: NumberFormatPB.Ringgit, title: 'Ringgit' },
|
||||
{ format: NumberFormatPB.Leu, title: 'Leu' },
|
||||
{ format: NumberFormatPB.ArgentinePeso, title: 'ArgentinePeso' },
|
||||
{ format: NumberFormatPB.UruguayanPeso, title: 'UruguayanPeso' },
|
||||
{ format: NumberFormatPB.Percent, title: 'Percent' },
|
||||
];
|
||||
|
||||
export const NumberFormatPopup = ({
|
||||
left,
|
||||
top,
|
||||
cellIdentifier,
|
||||
fieldController,
|
||||
onOutsideClick,
|
||||
}: {
|
||||
left: number;
|
||||
top: number;
|
||||
cellIdentifier: CellIdentifier;
|
||||
fieldController: FieldController;
|
||||
onOutsideClick: () => void;
|
||||
}) => {
|
||||
const { changeNumberFormat } = useNumberFormat(cellIdentifier, fieldController);
|
||||
const databaseStore = useAppSelector((state) => state.database);
|
||||
const [numberType, setNumberType] = useState<INumberType | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
setNumberType(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as INumberType);
|
||||
}, [databaseStore]);
|
||||
|
||||
const changeNumberFormatClick = async (format: NumberFormatPB) => {
|
||||
await changeNumberFormat(format);
|
||||
onOutsideClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<PopupWindow className={'p-2 text-xs'} onOutsideClick={onOutsideClick} left={left} top={top}>
|
||||
<div className={'h-[400px] overflow-auto'}>
|
||||
{list.map((item, index) => (
|
||||
<FormatButton
|
||||
key={index}
|
||||
title={item.title}
|
||||
checked={numberType?.numberFormat === item.format}
|
||||
onClick={() => changeNumberFormatClick(item.format)}
|
||||
></FormatButton>
|
||||
))}
|
||||
</div>
|
||||
</PopupWindow>
|
||||
);
|
||||
};
|
||||
|
||||
const FormatButton = ({ title, checked, onClick }: { title: string; checked: boolean; onClick: () => void }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => onClick()}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg py-1.5 px-2 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
<span className={'block pr-8'}>{title}</span>
|
||||
{checked && (
|
||||
<div className={'h-5 w-5 p-1'}>
|
||||
<CheckmarkSvg></CheckmarkSvg>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
@ -0,0 +1,72 @@
|
||||
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
|
||||
import { FieldController } from '$app/stores/effects/database/field/field_controller';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PopupWindow } from '$app/components/_shared/PopupWindow';
|
||||
import { TimeFormatPB } from '@/services/backend';
|
||||
import { CheckmarkSvg } from '$app/components/_shared/svg/CheckmarkSvg';
|
||||
import { useDateTimeFormat } from '$app/components/_shared/EditRow/DateTimeFormat.hooks';
|
||||
import { useAppSelector } from '$app/stores/store';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { IDateType } from '$app/stores/reducers/database/slice';
|
||||
|
||||
export const TimeFormatPopup = ({
|
||||
left,
|
||||
top,
|
||||
cellIdentifier,
|
||||
fieldController,
|
||||
onOutsideClick,
|
||||
}: {
|
||||
left: number;
|
||||
top: number;
|
||||
cellIdentifier: CellIdentifier;
|
||||
fieldController: FieldController;
|
||||
onOutsideClick: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation('');
|
||||
const databaseStore = useAppSelector((state) => state.database);
|
||||
const [dateType, setDateType] = useState<IDateType | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
setDateType(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as IDateType);
|
||||
}, [databaseStore]);
|
||||
|
||||
const { changeTimeFormat } = useDateTimeFormat(cellIdentifier, fieldController);
|
||||
|
||||
const changeFormat = async (format: TimeFormatPB) => {
|
||||
await changeTimeFormat(format);
|
||||
onOutsideClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<PopupWindow className={'p-2 text-xs'} onOutsideClick={onOutsideClick} left={left} top={top}>
|
||||
<button
|
||||
onClick={() => changeFormat(TimeFormatPB.TwelveHour)}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg px-2 py-1.5 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
{t('grid.field.timeFormatTwelveHour')}
|
||||
|
||||
{dateType?.timeFormat === TimeFormatPB.TwelveHour && (
|
||||
<div className={'ml-8 h-5 w-5 p-1'}>
|
||||
<CheckmarkSvg></CheckmarkSvg>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => changeFormat(TimeFormatPB.TwentyFourHour)}
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between rounded-lg px-2 py-1.5 hover:bg-main-secondary'
|
||||
}
|
||||
>
|
||||
{t('grid.field.timeFormatTwentyFourHour')}
|
||||
|
||||
{dateType?.timeFormat === TimeFormatPB.TwentyFourHour && (
|
||||
<div className={'ml-8 h-5 w-5 p-1'}>
|
||||
<CheckmarkSvg></CheckmarkSvg>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</PopupWindow>
|
||||
);
|
||||
};
|
@ -70,7 +70,7 @@ export default async function (viewId: string, fieldInfo: FieldInfo, dispatch?:
|
||||
title: field.name,
|
||||
fieldType: field.field_type,
|
||||
fieldOptions: {
|
||||
NumberFormatPB: typeOption.format,
|
||||
numberFormat: typeOption.format,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -82,8 +82,8 @@ export default async function (viewId: string, fieldInfo: FieldInfo, dispatch?:
|
||||
title: field.name,
|
||||
fieldType: field.field_type,
|
||||
fieldOptions: {
|
||||
DateFormatPB: typeOption.date_format,
|
||||
TimeFormatPB: typeOption.time_format,
|
||||
dateFormat: typeOption.date_format,
|
||||
timeFormat: typeOption.time_format,
|
||||
includeTime: typeOption.include_time,
|
||||
},
|
||||
};
|
||||
|
@ -25,9 +25,13 @@ export const useCell = (cellIdentifier: CellIdentifier, cellCache: CellCache, fi
|
||||
});
|
||||
|
||||
void (async () => {
|
||||
const cellData = await c.getCellData();
|
||||
if (cellData.some) {
|
||||
setData(cellData.unwrap());
|
||||
try {
|
||||
const cellData = await c.getCellData();
|
||||
if (cellData.some) {
|
||||
setData(cellData.unwrap());
|
||||
}
|
||||
} catch (e) {
|
||||
// mute for now
|
||||
}
|
||||
})();
|
||||
|
||||
|
@ -4,7 +4,10 @@ import { useRow } from '../_shared/database-hooks/useRow';
|
||||
import { DatabaseController } from '$app/stores/effects/database/database_controller';
|
||||
import { BoardCell } from './BoardCell';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { MouseEventHandler } from 'react';
|
||||
import { MouseEventHandler, useState } from 'react';
|
||||
import { PopupWindow } from '$app/components/_shared/PopupWindow';
|
||||
import { TrashSvg } from '$app/components/_shared/svg/TrashSvg';
|
||||
import { RowBackendService } from '$app/stores/effects/database/row/row_bd_svc';
|
||||
|
||||
export const BoardCard = ({
|
||||
index,
|
||||
@ -23,38 +26,79 @@ export const BoardCard = ({
|
||||
}) => {
|
||||
const { cells } = useRow(viewId, controller, rowInfo);
|
||||
|
||||
const [showCardPopup, setShowCardPopup] = useState(false);
|
||||
const [cardPopupLeft, setCardPopupLeft] = useState(0);
|
||||
const [cardPopupTop, setCardPopupTop] = useState(0);
|
||||
|
||||
const onDetailClick: MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
// onOpenRow(rowInfo);
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
while (!(target instanceof HTMLButtonElement)) {
|
||||
if (target.parentElement === null) return;
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
const { right: left, top } = target.getBoundingClientRect();
|
||||
setCardPopupLeft(left);
|
||||
setCardPopupTop(top);
|
||||
setShowCardPopup(true);
|
||||
};
|
||||
|
||||
const onDeleteRowClick = async () => {
|
||||
setShowCardPopup(false);
|
||||
const svc = new RowBackendService(viewId);
|
||||
await svc.deleteRow(rowInfo.row.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<Draggable draggableId={rowInfo.row.id} index={index}>
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
onClick={() => onOpenRow(rowInfo)}
|
||||
className={`relative cursor-pointer select-none rounded-lg border border-shade-6 bg-white px-3 py-2 transition-transform duration-100 hover:bg-main-selector `}
|
||||
>
|
||||
<button onClick={onDetailClick} className={'absolute right-4 top-2.5 h-5 w-5 rounded hover:bg-surface-2'}>
|
||||
<Details2Svg></Details2Svg>
|
||||
</button>
|
||||
<div className={'flex flex-col gap-3'}>
|
||||
{cells
|
||||
.filter((cell) => cell.fieldId !== groupByFieldId)
|
||||
.map((cell, cellIndex) => (
|
||||
<BoardCell
|
||||
key={cellIndex}
|
||||
cellIdentifier={cell.cellIdentifier}
|
||||
cellCache={controller.databaseViewCache.getRowCache().getCellCache()}
|
||||
fieldController={controller.fieldController}
|
||||
></BoardCell>
|
||||
))}
|
||||
<>
|
||||
<Draggable draggableId={rowInfo.row.id} key={rowInfo.row.id} index={index}>
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
onClick={() => onOpenRow(rowInfo)}
|
||||
className={`relative cursor-pointer select-none rounded-lg border border-shade-6 bg-white px-3 py-2 transition-transform duration-100 hover:bg-main-selector `}
|
||||
>
|
||||
<button onClick={onDetailClick} className={'absolute right-4 top-2.5 h-5 w-5 rounded hover:bg-surface-2'}>
|
||||
<Details2Svg></Details2Svg>
|
||||
</button>
|
||||
<div className={'flex flex-col gap-3'}>
|
||||
{cells
|
||||
.filter((cell) => cell.fieldId !== groupByFieldId)
|
||||
.map((cell, cellIndex) => (
|
||||
<BoardCell
|
||||
key={cellIndex}
|
||||
cellIdentifier={cell.cellIdentifier}
|
||||
cellCache={controller.databaseViewCache.getRowCache().getCellCache()}
|
||||
fieldController={controller.fieldController}
|
||||
></BoardCell>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
{showCardPopup && (
|
||||
<PopupWindow
|
||||
className={'p-2 text-xs'}
|
||||
onOutsideClick={() => setShowCardPopup(false)}
|
||||
left={cardPopupLeft}
|
||||
top={cardPopupTop}
|
||||
>
|
||||
<button
|
||||
key={index}
|
||||
className={'flex w-full cursor-pointer items-center gap-2 rounded-lg px-2 py-2 hover:bg-main-secondary'}
|
||||
onClick={() => onDeleteRowClick()}
|
||||
>
|
||||
<i className={'h-5 w-5'}>
|
||||
<TrashSvg></TrashSvg>
|
||||
</i>
|
||||
<span className={'flex-shrink-0'}>Delete</span>
|
||||
</button>
|
||||
</PopupWindow>
|
||||
)}
|
||||
</Draggable>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ export const BoardGroup = ({
|
||||
<div className={'flex items-center justify-between p-4'}>
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<span>{group.name}</span>
|
||||
<span className={'text-shade-4'}>()</span>
|
||||
<span className={'text-shade-4'}>({group.rows.length})</span>
|
||||
</div>
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<button className={'h-5 w-5 rounded hover:bg-surface-2'}>
|
||||
|
@ -13,13 +13,13 @@ export interface ISelectOptionType {
|
||||
}
|
||||
|
||||
export interface IDateType {
|
||||
DateFormatPB: DateFormatPB;
|
||||
TimeFormatPB: TimeFormatPB;
|
||||
dateFormat: DateFormatPB;
|
||||
timeFormat: TimeFormatPB;
|
||||
includeTime: boolean;
|
||||
}
|
||||
|
||||
export interface INumberType {
|
||||
NumberFormatPB: NumberFormatPB;
|
||||
numberFormat: NumberFormatPB;
|
||||
}
|
||||
|
||||
export interface IDatabaseField {
|
||||
|
6
frontend/rust-lib/Cargo.lock
generated
6
frontend/rust-lib/Cargo.lock
generated
@ -544,6 +544,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -561,6 +562,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -582,6 +584,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -593,6 +596,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -609,6 +613,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -626,6 +631,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=935868#93586873d1982d3b4ab96993a39810e4bb4d1993"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
|
Loading…
Reference in New Issue
Block a user