From eb0538b856141ef7ee8173d982a142cd2b78773a Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Fri, 17 Apr 2026 13:41:24 +0100
Subject: [PATCH] fix
---
.../components/cells/cell-multi-select.tsx | 66 ++++++++++++++++++-
.../base/components/cells/cell-select.tsx | 65 +++++++++++++++++-
.../components/property/property-options.tsx | 6 +-
.../src/features/base/styles/cells.module.css | 23 +++++++
4 files changed, 154 insertions(+), 6 deletions(-)
diff --git a/apps/client/src/features/base/components/cells/cell-multi-select.tsx b/apps/client/src/features/base/components/cells/cell-multi-select.tsx
index f76366f0..95e9d951 100644
--- a/apps/client/src/features/base/components/cells/cell-multi-select.tsx
+++ b/apps/client/src/features/base/components/cells/cell-multi-select.tsx
@@ -1,4 +1,4 @@
-import { useState, useRef, useEffect, useCallback } from "react";
+import { useState, useRef, useEffect, useCallback, useMemo } from "react";
import { Popover, TextInput } from "@mantine/core";
import {
IBaseProperty,
@@ -6,8 +6,15 @@ import {
Choice,
} from "@/features/base/types/base.types";
import { choiceColor } from "@/features/base/components/cells/choice-color";
+import { useUpdatePropertyMutation } from "@/features/base/queries/base-property-query";
+import { v7 as uuid7 } from "uuid";
import cellClasses from "@/features/base/styles/cells.module.css";
+const CHOICE_COLORS = [
+ "gray", "red", "pink", "grape", "violet", "indigo",
+ "blue", "cyan", "teal", "green", "lime", "yellow", "orange",
+];
+
type CellMultiSelectProps = {
value: unknown;
property: IBaseProperty;
@@ -55,14 +62,55 @@ export function CellMultiSelect({
[selectedIds, selectedSet, onCommit],
);
+ const updatePropertyMutation = useUpdatePropertyMutation();
+
+ const trimmedSearch = search.trim();
+ const hasExactMatch = useMemo(
+ () =>
+ trimmedSearch.length > 0 &&
+ choices.some((c) => c.name.toLowerCase() === trimmedSearch.toLowerCase()),
+ [choices, trimmedSearch],
+ );
+ const showAddOption = trimmedSearch.length > 0 && !hasExactMatch;
+
+ const addOptionColor = useMemo(
+ () => CHOICE_COLORS[choices.length % CHOICE_COLORS.length],
+ [choices.length],
+ );
+
+ const handleAddOption = useCallback(() => {
+ if (!trimmedSearch) return;
+ const newChoice: Choice = {
+ id: uuid7(),
+ name: trimmedSearch,
+ color: addOptionColor,
+ };
+ const newChoices = [...choices, newChoice];
+ updatePropertyMutation.mutate({
+ propertyId: property.id,
+ baseId: property.baseId,
+ typeOptions: {
+ ...typeOptions,
+ choices: newChoices,
+ choiceOrder: newChoices.map((c) => c.id),
+ },
+ });
+ onCommit([...selectedIds, newChoice.id]);
+ setSearch("");
+ }, [trimmedSearch, addOptionColor, choices, typeOptions, property, updatePropertyMutation, selectedIds, onCommit]);
+
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === "Escape") {
e.preventDefault();
onCancel();
}
+ if (e.key === "Enter" && showAddOption) {
+ e.preventDefault();
+ handleAddOption();
+ }
},
- [onCancel],
+ [onCancel, showAddOption, handleAddOption],
);
const MAX_VISIBLE = 3;
@@ -110,6 +158,20 @@ export function CellMultiSelect({
))}
+ {showAddOption && (
+
+ Add option:
+
+ {trimmedSearch}
+
+
+ )}
diff --git a/apps/client/src/features/base/components/cells/cell-select.tsx b/apps/client/src/features/base/components/cells/cell-select.tsx
index 38c6361c..77096c89 100644
--- a/apps/client/src/features/base/components/cells/cell-select.tsx
+++ b/apps/client/src/features/base/components/cells/cell-select.tsx
@@ -1,4 +1,4 @@
-import { useState, useRef, useEffect, useCallback } from "react";
+import { useState, useRef, useEffect, useCallback, useMemo } from "react";
import { Popover, TextInput } from "@mantine/core";
import {
IBaseProperty,
@@ -6,8 +6,15 @@ import {
Choice,
} from "@/features/base/types/base.types";
import { choiceColor } from "@/features/base/components/cells/choice-color";
+import { useUpdatePropertyMutation } from "@/features/base/queries/base-property-query";
+import { v7 as uuid7 } from "uuid";
import cellClasses from "@/features/base/styles/cells.module.css";
+const CHOICE_COLORS = [
+ "gray", "red", "pink", "grape", "violet", "indigo",
+ "blue", "cyan", "teal", "green", "lime", "yellow", "orange",
+];
+
type CellSelectProps = {
value: unknown;
property: IBaseProperty;
@@ -52,14 +59,54 @@ export function CellSelect({
[selectedId, onCommit],
);
+ const updatePropertyMutation = useUpdatePropertyMutation();
+
+ const trimmedSearch = search.trim();
+ const hasExactMatch = useMemo(
+ () =>
+ trimmedSearch.length > 0 &&
+ choices.some((c) => c.name.toLowerCase() === trimmedSearch.toLowerCase()),
+ [choices, trimmedSearch],
+ );
+ const showAddOption = trimmedSearch.length > 0 && !hasExactMatch;
+
+ const addOptionColor = useMemo(
+ () => CHOICE_COLORS[choices.length % CHOICE_COLORS.length],
+ [choices.length],
+ );
+
+ const handleAddOption = useCallback(() => {
+ if (!trimmedSearch) return;
+ const newChoice: Choice = {
+ id: uuid7(),
+ name: trimmedSearch,
+ color: addOptionColor,
+ };
+ const newChoices = [...choices, newChoice];
+ updatePropertyMutation.mutate({
+ propertyId: property.id,
+ baseId: property.baseId,
+ typeOptions: {
+ ...typeOptions,
+ choices: newChoices,
+ choiceOrder: newChoices.map((c) => c.id),
+ },
+ });
+ onCommit(newChoice.id);
+ }, [trimmedSearch, addOptionColor, choices, typeOptions, property, updatePropertyMutation, onCommit]);
+
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === "Escape") {
e.preventDefault();
onCancel();
}
+ if (e.key === "Enter" && showAddOption) {
+ e.preventDefault();
+ handleAddOption();
+ }
},
- [onCancel],
+ [onCancel, showAddOption, handleAddOption],
);
if (isEditing) {
@@ -112,6 +159,20 @@ export function CellSelect({
))}
+ {showAddOption && (
+
+ Add option:
+
+ {trimmedSearch}
+
+
+ )}
diff --git a/apps/client/src/features/base/components/property/property-options.tsx b/apps/client/src/features/base/components/property/property-options.tsx
index 6754c059..37b6f962 100644
--- a/apps/client/src/features/base/components/property/property-options.tsx
+++ b/apps/client/src/features/base/components/property/property-options.tsx
@@ -167,6 +167,7 @@ function NumberOptions({