mirror of
https://github.com/colanode/colanode.git
synced 2025-12-29 00:25:03 +01:00
Refactor table view cells
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { BooleanFieldNode, RecordNode } from '@/types/databases';
|
||||
import { useUpdateBooleanFieldValueMutation } from '@/mutations/use-update-boolean-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
|
||||
const getBooleanValue = (
|
||||
record: RecordNode,
|
||||
@@ -24,8 +25,12 @@ export const TableViewBooleanCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewBooleanCellProps) => {
|
||||
const { mutate, isPending } = useUpdateBooleanFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
const canEdit = true;
|
||||
|
||||
const [input, setInput] = React.useState<boolean>(
|
||||
@@ -47,11 +52,23 @@ export const TableViewBooleanCell = ({
|
||||
|
||||
if (typeof e === 'boolean') {
|
||||
setInput(e.valueOf());
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
value: e.valueOf(),
|
||||
});
|
||||
const checked = e.valueOf();
|
||||
if (checked) {
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
numberValue: 1,
|
||||
textValue: null,
|
||||
foreignNodeId: null,
|
||||
});
|
||||
} else {
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import isHotkey from 'is-hotkey';
|
||||
import { RecordNode, EmailFieldNode } from '@/types/databases';
|
||||
import { useUpdateEmailFieldValueMutation } from '@/mutations/use-update-email-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
import { SmartTextInput } from '@/components/ui/smart-text-input';
|
||||
|
||||
const getEmailValue = (record: RecordNode, field: EmailFieldNode): string => {
|
||||
const attribute = record.attributes.find((attr) => attr.type === field.id);
|
||||
@@ -17,38 +18,37 @@ export const TableViewEmailCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewEmailCellProps) => {
|
||||
const { mutate, isPending } = useUpdateEmailFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const canEdit = true;
|
||||
|
||||
const [text, setText] = React.useState<string>(
|
||||
getEmailValue(record, field) ?? '',
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
setText(getEmailValue(record, field) ?? '');
|
||||
}, [record.versionId]);
|
||||
|
||||
const saveIfChanged = (current: string, previous: string | null) => {
|
||||
if (current.length && current !== previous) {
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
value: current,
|
||||
});
|
||||
}
|
||||
};
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
|
||||
return (
|
||||
<input
|
||||
value={text}
|
||||
<SmartTextInput
|
||||
value={getEmailValue(record, field)}
|
||||
readOnly={!canEdit || isPending}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={() => saveIfChanged(text, getEmailValue(record, field))}
|
||||
onKeyDown={(e) => {
|
||||
if (isHotkey('enter', e)) {
|
||||
saveIfChanged(text, getEmailValue(record, field));
|
||||
e.preventDefault();
|
||||
onChange={(newValue) => {
|
||||
if (isPending) return;
|
||||
if (!canEdit) return;
|
||||
|
||||
if (newValue === null || newValue === '') {
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
} else {
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
textValue: newValue,
|
||||
numberValue: null,
|
||||
foreignNodeId: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text"
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
PopoverContent,
|
||||
} from '@/components/ui/popover';
|
||||
import { SelectFieldOptions } from '@/components/databases/fields/select-field-options';
|
||||
import { useUpdateMultiSelectFieldValueMutation } from '@/mutations/use-update-multi-select-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
|
||||
const getMultiSelectValues = (
|
||||
record: RecordNode,
|
||||
@@ -26,7 +27,13 @@ export const TableViewMultiSelectCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewMultiSelectCellProps) => {
|
||||
const { mutate, isPending } = useUpdateMultiSelectFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [selectedValues, setSelectedValues] = React.useState(
|
||||
getMultiSelectValues(record, field),
|
||||
@@ -63,19 +70,20 @@ export const TableViewMultiSelectCell = ({
|
||||
|
||||
if (selectedValues.includes(id)) {
|
||||
setSelectedValues(selectedValues.filter((v) => v !== id));
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
selectOptionId: id,
|
||||
add: false,
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: id,
|
||||
});
|
||||
} else {
|
||||
setSelectedValues([...selectedValues, id]);
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
selectOptionId: id,
|
||||
add: true,
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: id,
|
||||
foreignNodeId: id,
|
||||
numberValue: null,
|
||||
textValue: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React from 'react';
|
||||
import isHotkey from 'is-hotkey';
|
||||
import { RecordNode } from '@/types/databases';
|
||||
import { NumberFieldNode } from '@/types/databases';
|
||||
import { useUpdateNumberFieldValueMutation } from '@/mutations/use-update-number-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
import { SmartNumberInput } from '@/components/ui/smart-number-input';
|
||||
|
||||
const getNumberValue = (
|
||||
record: RecordNode,
|
||||
@@ -21,55 +22,44 @@ export const TableViewNumberCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewNumberCellProps) => {
|
||||
const { mutate, isPending } = useUpdateNumberFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const canEdit = true;
|
||||
|
||||
const [input, setInput] = React.useState<string>(
|
||||
getNumberValue(record, field)?.toString() ?? '',
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
setInput(getNumberValue(record, field)?.toString() ?? '');
|
||||
}, [record.versionId]);
|
||||
|
||||
const saveIfChanged = (current: number | null, previous: number | null) => {
|
||||
if (current !== previous) {
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
value: current,
|
||||
});
|
||||
}
|
||||
};
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
|
||||
return (
|
||||
<input
|
||||
className="flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text"
|
||||
<SmartNumberInput
|
||||
value={getNumberValue(record, field)}
|
||||
readOnly={!canEdit || isPending}
|
||||
value={input ?? ''}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onBlur={() => {
|
||||
const number = Number(input);
|
||||
if (Number.isNaN(number)) {
|
||||
setInput('');
|
||||
saveIfChanged(null, getNumberValue(record, field));
|
||||
onChange={(newValue) => {
|
||||
if (isPending) return;
|
||||
if (!canEdit) return;
|
||||
|
||||
if (newValue === getNumberValue(record, field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue === null) {
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
} else {
|
||||
saveIfChanged(number, getNumberValue(record, field));
|
||||
}
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (isHotkey('enter', e)) {
|
||||
const number = Number(input);
|
||||
if (Number.isNaN(number)) {
|
||||
setInput('');
|
||||
saveIfChanged(null, getNumberValue(record, field));
|
||||
} else {
|
||||
saveIfChanged(number, getNumberValue(record, field));
|
||||
}
|
||||
e.preventDefault();
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
numberValue: newValue,
|
||||
textValue: null,
|
||||
foreignNodeId: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import isHotkey from 'is-hotkey';
|
||||
import { RecordNode, PhoneFieldNode } from '@/types/databases';
|
||||
import { useUpdatePhoneFieldValueMutation } from '@/mutations/use-update-phone-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
import { SmartTextInput } from '@/components/ui/smart-text-input';
|
||||
|
||||
const getPhoneValue = (record: RecordNode, field: PhoneFieldNode): string => {
|
||||
const attribute = record.attributes.find((attr) => attr.type === field.id);
|
||||
@@ -17,38 +18,41 @@ export const TableViewPhoneCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewPhoneCellProps) => {
|
||||
const { mutate, isPending } = useUpdatePhoneFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const canEdit = true;
|
||||
|
||||
const [text, setText] = React.useState<string>(
|
||||
getPhoneValue(record, field) ?? '',
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
setText(getPhoneValue(record, field) ?? '');
|
||||
}, [record.versionId]);
|
||||
|
||||
const saveIfChanged = (current: string, previous: string | null) => {
|
||||
if (current.length && current !== previous) {
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
value: current,
|
||||
});
|
||||
}
|
||||
};
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
|
||||
return (
|
||||
<input
|
||||
value={text}
|
||||
<SmartTextInput
|
||||
value={getPhoneValue(record, field)}
|
||||
readOnly={!canEdit || isPending}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={() => saveIfChanged(text, getPhoneValue(record, field))}
|
||||
onKeyDown={(e) => {
|
||||
if (isHotkey('enter', e)) {
|
||||
saveIfChanged(text, getPhoneValue(record, field));
|
||||
e.preventDefault();
|
||||
onChange={(newValue) => {
|
||||
if (isPending) return;
|
||||
if (!canEdit) return;
|
||||
|
||||
if (newValue === getPhoneValue(record, field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue === null || newValue === '') {
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
} else {
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
numberValue: 1,
|
||||
textValue: newValue,
|
||||
foreignNodeId: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text"
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
PopoverContent,
|
||||
} from '@/components/ui/popover';
|
||||
import { SelectFieldOptions } from '@/components/databases/fields/select-field-options';
|
||||
import { useUpdateSelectFieldValueMutation } from '@/mutations/use-update-select-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
|
||||
const getSelectValue = (
|
||||
record: RecordNode,
|
||||
@@ -26,7 +27,13 @@ export const TableViewSelectCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewSelectCellProps) => {
|
||||
const { mutate, isPending } = useUpdateSelectFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [selectedValue, setSelectedValue] = React.useState(
|
||||
getSelectValue(record, field) ?? '',
|
||||
@@ -65,20 +72,20 @@ export const TableViewSelectCell = ({
|
||||
|
||||
if (selectedValue === id) {
|
||||
setSelectedValue('');
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
selectOptionId: id,
|
||||
add: false,
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
} else {
|
||||
setSelectedValue(id);
|
||||
mutate(
|
||||
upsertNodeAttribute(
|
||||
{
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
selectOptionId: id,
|
||||
add: true,
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
foreignNodeId: id,
|
||||
textValue: null,
|
||||
numberValue: null,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
@@ -87,6 +94,7 @@ export const TableViewSelectCell = ({
|
||||
},
|
||||
);
|
||||
}
|
||||
setSelectedValue(id);
|
||||
}}
|
||||
/>
|
||||
</PopoverContent>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import isHotkey from 'is-hotkey';
|
||||
import { RecordNode, TextFieldNode } from '@/types/databases';
|
||||
import { useUpdateTextFieldValueMutation } from '@/mutations/use-update-text-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
import { SmartTextInput } from '@/components/ui/smart-text-input';
|
||||
|
||||
const getTextValue = (record: RecordNode, field: TextFieldNode): string => {
|
||||
const attribute = record.attributes.find((attr) => attr.type === field.id);
|
||||
@@ -17,38 +18,41 @@ export const TableViewTextCell = ({
|
||||
record,
|
||||
field,
|
||||
}: TableViewTextCellProps) => {
|
||||
const { mutate, isPending } = useUpdateTextFieldValueMutation();
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const canEdit = true;
|
||||
|
||||
const [text, setText] = React.useState<string>(
|
||||
getTextValue(record, field) ?? '',
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
setText(getTextValue(record, field) ?? '');
|
||||
}, [record.versionId]);
|
||||
|
||||
const saveIfChanged = (current: string, previous: string | null) => {
|
||||
if (current.length && current !== previous) {
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
value: current,
|
||||
});
|
||||
}
|
||||
};
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
|
||||
return (
|
||||
<input
|
||||
<SmartTextInput
|
||||
value={getTextValue(record, field)}
|
||||
readOnly={!canEdit || isPending}
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={() => saveIfChanged(text, getTextValue(record, field))}
|
||||
onKeyDown={(e) => {
|
||||
if (isHotkey('enter', e)) {
|
||||
saveIfChanged(text, getTextValue(record, field));
|
||||
e.preventDefault();
|
||||
onChange={(newValue) => {
|
||||
if (isPending) return;
|
||||
if (!canEdit) return;
|
||||
|
||||
if (newValue === getTextValue(record, field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue === null || newValue === '') {
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
} else {
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
numberValue: 1,
|
||||
textValue: newValue,
|
||||
foreignNodeId: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import isHotkey from 'is-hotkey';
|
||||
import { RecordNode, UrlFieldNode } from '@/types/databases';
|
||||
import { cn, isValidUrl } from '@/lib/utils';
|
||||
import {
|
||||
@@ -8,7 +7,9 @@ import {
|
||||
HoverCardTrigger,
|
||||
} from '@/components/ui/hover-card';
|
||||
import { Icon } from '@/components/ui/icon';
|
||||
import { useUpdateUrlFieldValueMutation } from '@/mutations/use-update-url-field-value-mutation';
|
||||
import { useNodeAttributeUpsertMutation } from '@/mutations/use-node-attribute-upsert-mutation';
|
||||
import { useNodeAttributeDeleteMutation } from '@/mutations/use-node-attribute-delete-mutation';
|
||||
import { SmartTextInput } from '@/components/ui/smart-text-input';
|
||||
|
||||
const getUrlValue = (record: RecordNode, field: UrlFieldNode): string => {
|
||||
const attribute = record.attributes.find((attr) => attr.type === field.id);
|
||||
@@ -18,56 +19,51 @@ const getUrlValue = (record: RecordNode, field: UrlFieldNode): string => {
|
||||
interface TableViewUrlCellProps {
|
||||
record: RecordNode;
|
||||
field: UrlFieldNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const TableViewUrlCell = ({
|
||||
record,
|
||||
field,
|
||||
className,
|
||||
}: TableViewUrlCellProps) => {
|
||||
const { mutate, isPending } = useUpdateUrlFieldValueMutation();
|
||||
export const TableViewUrlCell = ({ record, field }: TableViewUrlCellProps) => {
|
||||
const { mutate: upsertNodeAttribute, isPending: isUpsertingNodeAttribute } =
|
||||
useNodeAttributeUpsertMutation();
|
||||
const { mutate: deleteNodeAttribute, isPending: isDeletingNodeAttribute } =
|
||||
useNodeAttributeDeleteMutation();
|
||||
|
||||
const canEdit = true;
|
||||
|
||||
const [text, setText] = React.useState<string>(
|
||||
getUrlValue(record, field) ?? '',
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
setText(getUrlValue(record, field) ?? '');
|
||||
}, [record.versionId]);
|
||||
|
||||
const saveIfChanged = (current: string, previous: string | null) => {
|
||||
if (current.length && current !== previous) {
|
||||
mutate({
|
||||
recordId: record.id,
|
||||
fieldId: field.id,
|
||||
value: current,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isPending = isUpsertingNodeAttribute || isDeletingNodeAttribute;
|
||||
const text = getUrlValue(record, field);
|
||||
const isUrl = text.length > 0 && isValidUrl(text);
|
||||
|
||||
return (
|
||||
<HoverCard openDelay={300}>
|
||||
<HoverCardTrigger>
|
||||
<input
|
||||
<SmartTextInput
|
||||
value={text}
|
||||
readOnly={!canEdit || isPending}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={() => saveIfChanged(text, getUrlValue(record, field))}
|
||||
onKeyDown={(e) => {
|
||||
if (isHotkey('enter', e)) {
|
||||
saveIfChanged(text, getUrlValue(record, field));
|
||||
e.preventDefault();
|
||||
onChange={(newValue) => {
|
||||
if (isPending) return;
|
||||
if (!canEdit) return;
|
||||
|
||||
if (newValue === text) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue === null || newValue === '') {
|
||||
deleteNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
});
|
||||
} else {
|
||||
upsertNodeAttribute({
|
||||
nodeId: record.id,
|
||||
type: field.id,
|
||||
key: '1',
|
||||
numberValue: 1,
|
||||
textValue: newValue,
|
||||
foreignNodeId: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
className={cn(
|
||||
'flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text',
|
||||
className,
|
||||
)}
|
||||
className="flex h-full w-full cursor-pointer flex-row items-center gap-1 p-1 text-sm focus-visible:cursor-text"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent
|
||||
|
||||
@@ -9,94 +9,101 @@ interface SmartNumberInputProps {
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
const SmartNumberInput = React.forwardRef<
|
||||
HTMLInputElement,
|
||||
SmartNumberInputProps
|
||||
>(({ value, onChange, className, min, max, step = 1, ...props }, ref) => {
|
||||
const [localValue, setLocalValue] = React.useState(value?.toString() ?? '');
|
||||
const initialValue = React.useRef(value?.toString() ?? '');
|
||||
>(
|
||||
(
|
||||
{ value, onChange, className, min, max, step = 1, readOnly, ...props },
|
||||
ref,
|
||||
) => {
|
||||
const [localValue, setLocalValue] = React.useState(value?.toString() ?? '');
|
||||
const initialValue = React.useRef(value?.toString() ?? '');
|
||||
|
||||
// Create a debounced version of onChange
|
||||
const debouncedOnChange = React.useMemo(
|
||||
() => debounce((value: number) => onChange(value), 500),
|
||||
[onChange],
|
||||
);
|
||||
// Create a debounced version of onChange
|
||||
const debouncedOnChange = React.useMemo(
|
||||
() => debounce((value: number) => onChange(value), 500),
|
||||
[onChange],
|
||||
);
|
||||
|
||||
// Update localValue when value prop changes
|
||||
React.useEffect(() => {
|
||||
setLocalValue(value?.toString() ?? '');
|
||||
initialValue.current = value?.toString() ?? '';
|
||||
}, [value]);
|
||||
// Update localValue when value prop changes
|
||||
React.useEffect(() => {
|
||||
setLocalValue(value?.toString() ?? '');
|
||||
initialValue.current = value?.toString() ?? '';
|
||||
}, [value]);
|
||||
|
||||
// Cleanup debounce on unmount
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
debouncedOnChange.cancel();
|
||||
};
|
||||
}, [debouncedOnChange]);
|
||||
// Cleanup debounce on unmount
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
debouncedOnChange.cancel();
|
||||
};
|
||||
}, [debouncedOnChange]);
|
||||
|
||||
const handleBlur = () => {
|
||||
const newValue = parseFloat(localValue);
|
||||
if (!isNaN(newValue) && localValue !== initialValue.current) {
|
||||
debouncedOnChange.cancel(); // Cancel any pending debounced calls
|
||||
onChange(applyConstraints(newValue));
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Escape') {
|
||||
setLocalValue(initialValue.current); // Revert to initial value
|
||||
debouncedOnChange.cancel(); // Cancel any pending debounced calls
|
||||
} else if (event.key === 'Enter') {
|
||||
const handleBlur = () => {
|
||||
const newValue = parseFloat(localValue);
|
||||
if (!isNaN(newValue) && localValue !== initialValue.current) {
|
||||
onChange(applyConstraints(newValue)); // Fire onChange immediately when Enter is pressed
|
||||
debouncedOnChange.cancel(); // Cancel any pending debounced calls
|
||||
onChange(applyConstraints(newValue));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
setLocalValue(newValue);
|
||||
const parsedValue = parseFloat(newValue);
|
||||
if (!isNaN(parsedValue)) {
|
||||
debouncedOnChange(applyConstraints(parsedValue)); // Trigger debounced onChange
|
||||
}
|
||||
};
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Escape') {
|
||||
setLocalValue(initialValue.current); // Revert to initial value
|
||||
debouncedOnChange.cancel(); // Cancel any pending debounced calls
|
||||
} else if (event.key === 'Enter') {
|
||||
const newValue = parseFloat(localValue);
|
||||
if (!isNaN(newValue) && localValue !== initialValue.current) {
|
||||
onChange(applyConstraints(newValue)); // Fire onChange immediately when Enter is pressed
|
||||
debouncedOnChange.cancel(); // Cancel any pending debounced calls
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const applyConstraints = (value: number): number => {
|
||||
let constrainedValue = value;
|
||||
if (min !== undefined) {
|
||||
constrainedValue = Math.max(min, constrainedValue);
|
||||
}
|
||||
if (max !== undefined) {
|
||||
constrainedValue = Math.min(max, constrainedValue);
|
||||
}
|
||||
return Math.round(constrainedValue / step) * step;
|
||||
};
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
setLocalValue(newValue);
|
||||
const parsedValue = parseFloat(newValue);
|
||||
if (!isNaN(parsedValue)) {
|
||||
debouncedOnChange(applyConstraints(parsedValue)); // Trigger debounced onChange
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<input
|
||||
type="number"
|
||||
className={cn(
|
||||
'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
value={localValue}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const applyConstraints = (value: number): number => {
|
||||
let constrainedValue = value;
|
||||
if (min !== undefined) {
|
||||
constrainedValue = Math.max(min, constrainedValue);
|
||||
}
|
||||
if (max !== undefined) {
|
||||
constrainedValue = Math.min(max, constrainedValue);
|
||||
}
|
||||
return Math.round(constrainedValue / step) * step;
|
||||
};
|
||||
|
||||
return (
|
||||
<input
|
||||
type="number"
|
||||
className={cn(
|
||||
'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
value={localValue}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
readOnly={readOnly}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SmartNumberInput.displayName = 'SmartNumberInput';
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@ interface SmartTextInputProps {
|
||||
value: string | null;
|
||||
onChange: (newValue: string) => void;
|
||||
className?: string;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
const SmartTextInput = React.forwardRef<HTMLInputElement, SmartTextInputProps>(
|
||||
({ value, onChange, className, ...props }, ref) => {
|
||||
({ value, onChange, className, readOnly, ...props }, ref) => {
|
||||
const [localValue, setLocalValue] = React.useState(value ?? '');
|
||||
const initialValue = React.useRef(value ?? '');
|
||||
|
||||
@@ -69,6 +70,7 @@ const SmartTextInput = React.forwardRef<HTMLInputElement, SmartTextInputProps>(
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
readOnly={readOnly}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateBooleanFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export const useUpdateBooleanFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
return useMutation<void, Error, UpdateBooleanFieldValueMutationProps>({
|
||||
mutationFn: async ({ recordId, fieldId, value }) => {
|
||||
if (!value) {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: fieldId,
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
number_value: 1,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) => ob.doNothing())
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateEmailFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const useUpdateEmailFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
return useMutation<void, Error, UpdateEmailFieldValueMutationProps>({
|
||||
mutationFn: async ({ recordId, fieldId, value }) => {
|
||||
if (value.length === 0) {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
text_value: value,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) =>
|
||||
ob.doUpdateSet({
|
||||
text_value: value,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateMultiSelectFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
selectOptionId: string;
|
||||
add: boolean;
|
||||
}
|
||||
|
||||
export const useUpdateMultiSelectFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
recordId,
|
||||
fieldId,
|
||||
selectOptionId,
|
||||
add,
|
||||
}: UpdateMultiSelectFieldValueMutationProps) => {
|
||||
if (add) {
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: selectOptionId,
|
||||
foreign_node_id: selectOptionId,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) => ob.doNothing())
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
} else {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and([
|
||||
eb('node_id', '=', recordId),
|
||||
eb('type', '=', fieldId),
|
||||
eb('key', '=', selectOptionId),
|
||||
]),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateNumberFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
value: number | null;
|
||||
}
|
||||
|
||||
export const useUpdateNumberFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
return useMutation<void, Error, UpdateNumberFieldValueMutationProps>({
|
||||
mutationFn: async ({ recordId, fieldId, value }) => {
|
||||
if (value === null) {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
number_value: value,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) =>
|
||||
ob.doUpdateSet({
|
||||
number_value: value,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdatePhoneFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const useUpdatePhoneFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
return useMutation<void, Error, UpdatePhoneFieldValueMutationProps>({
|
||||
mutationFn: async ({ recordId, fieldId, value }) => {
|
||||
if (value.length === 0) {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
text_value: value,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) =>
|
||||
ob.doUpdateSet({
|
||||
text_value: value,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateSelectFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
selectOptionId: string;
|
||||
add: boolean;
|
||||
}
|
||||
|
||||
export const useUpdateSelectFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
recordId,
|
||||
fieldId,
|
||||
selectOptionId,
|
||||
add,
|
||||
}: UpdateSelectFieldValueMutationProps) => {
|
||||
if (add) {
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
foreign_node_id: selectOptionId,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) =>
|
||||
ob.doUpdateSet({
|
||||
foreign_node_id: selectOptionId,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
} else {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and([
|
||||
eb('node_id', '=', recordId),
|
||||
eb('type', '=', fieldId),
|
||||
eb('key', '=', '1'),
|
||||
]),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateTextFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const useUpdateTextFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
return useMutation<void, Error, UpdateTextFieldValueMutationProps>({
|
||||
mutationFn: async ({ recordId, fieldId, value }) => {
|
||||
if (value.length === 0) {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: fieldId,
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
text_value: value,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) =>
|
||||
ob.doUpdateSet({
|
||||
text_value: value,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface UpdateUrlFieldValueMutationProps {
|
||||
recordId: string;
|
||||
fieldId: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const useUpdateUrlFieldValueMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
return useMutation<void, Error, UpdateUrlFieldValueMutationProps>({
|
||||
mutationFn: async ({ recordId, fieldId, value }) => {
|
||||
if (value.length === 0) {
|
||||
const query = workspace.schema
|
||||
.deleteFrom('node_attributes')
|
||||
.where((eb) =>
|
||||
eb.and({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: fieldId,
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: recordId,
|
||||
type: fieldId,
|
||||
key: '1',
|
||||
text_value: value,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((ob) =>
|
||||
ob.doUpdateSet({
|
||||
text_value: value,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
import { useWorkspace } from '@/contexts/workspace';
|
||||
import { AttributeTypes } from '@/lib/constants';
|
||||
import { NeuronId } from '@/lib/id';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
interface ViewFilterOperatorUpdateMutationInput {
|
||||
filterId: string;
|
||||
operator: string;
|
||||
}
|
||||
|
||||
export const useViewFilterOperatorUpdateMutation = () => {
|
||||
const workspace = useWorkspace();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
filterId,
|
||||
operator,
|
||||
}: ViewFilterOperatorUpdateMutationInput) => {
|
||||
const query = workspace.schema
|
||||
.insertInto('node_attributes')
|
||||
.values({
|
||||
node_id: filterId,
|
||||
type: AttributeTypes.Operator,
|
||||
key: '1',
|
||||
text_value: operator,
|
||||
created_at: new Date().toISOString(),
|
||||
created_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
})
|
||||
.onConflict((b) =>
|
||||
b.doUpdateSet({
|
||||
text_value: operator,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: workspace.userId,
|
||||
version_id: NeuronId.generate(NeuronId.Type.Version),
|
||||
}),
|
||||
)
|
||||
.compile();
|
||||
|
||||
await workspace.mutate(query);
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user