@proteos/ui 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +97 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +98 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/attribute-type-icon/attribute-type-icon.test.tsx +12 -0
- package/src/components/attribute-type-icon/attribute-type-icon.tsx +6 -0
- package/src/components/record-filter/operators.test.ts +20 -2
- package/src/components/record-filter/operators.ts +93 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proteos/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"license": "FSL-1.1-Apache-2.0",
|
|
5
5
|
"description": "Proteos React component library (React Aria Components + Tailwind v4).",
|
|
6
6
|
"repository": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"tailwind-variants": "^3.2.2",
|
|
57
57
|
"tailwindcss": "^4.2.4",
|
|
58
58
|
"thinking-orbs": "^0.3.1",
|
|
59
|
-
"@proteos/sdk": "0.
|
|
59
|
+
"@proteos/sdk": "0.53.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@biomejs/biome": "^2.4.13",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { ATTRIBUTE_TYPE_ICONS, ATTRIBUTE_TYPES } from './attribute-type-icon'
|
|
4
|
+
|
|
5
|
+
describe('ATTRIBUTE_TYPE_ICONS', () => {
|
|
6
|
+
it('maps every attribute type to an icon (a missing entry crashes the type picker at runtime)', () => {
|
|
7
|
+
for (const type of ATTRIBUTE_TYPES) {
|
|
8
|
+
expect(ATTRIBUTE_TYPE_ICONS[type], `no icon for ${type}`).toBeTypeOf('object')
|
|
9
|
+
}
|
|
10
|
+
expect(ATTRIBUTE_TYPES).toContain('contact-address')
|
|
11
|
+
})
|
|
12
|
+
})
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
Brackets,
|
|
6
6
|
Calendar,
|
|
7
7
|
CircleDot,
|
|
8
|
+
Contact,
|
|
8
9
|
Hash,
|
|
9
10
|
Link2,
|
|
10
11
|
type LucideIcon,
|
|
@@ -55,6 +56,9 @@ import { cn } from '../../lib/cn'
|
|
|
55
56
|
currency → Banknote (money — amount + currency_code)
|
|
56
57
|
knowledge-text → BookText (long text stored as a knowledge node)
|
|
57
58
|
file → Paperclip (attachment — stored-file reference)
|
|
59
|
+
contact-address → Contact (one canonical reachable address — email /
|
|
60
|
+
phone / LinkedIn — binding the record to a
|
|
61
|
+
conversation contact)
|
|
58
62
|
========================================================================= */
|
|
59
63
|
|
|
60
64
|
/**
|
|
@@ -81,6 +85,7 @@ export const AttributeType = {
|
|
|
81
85
|
Currency: 'currency',
|
|
82
86
|
KnowledgeText: 'knowledge-text',
|
|
83
87
|
File: 'file',
|
|
88
|
+
ContactAddress: 'contact-address',
|
|
84
89
|
} as const
|
|
85
90
|
export type AttributeType = (typeof AttributeType)[keyof typeof AttributeType]
|
|
86
91
|
|
|
@@ -102,6 +107,7 @@ export const ATTRIBUTE_TYPE_ICONS: Record<AttributeType, LucideIcon> = {
|
|
|
102
107
|
[AttributeType.Currency]: Banknote,
|
|
103
108
|
[AttributeType.KnowledgeText]: BookText,
|
|
104
109
|
[AttributeType.File]: Paperclip,
|
|
110
|
+
[AttributeType.ContactAddress]: Contact,
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
export function useAttributeTypeIcon(type: AttributeType): LucideIcon {
|
|
@@ -11,13 +11,31 @@ describe('operatorsForType', () => {
|
|
|
11
11
|
}
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
it('only allows starts_with / ends_with on
|
|
14
|
+
it('only allows starts_with / ends_with on string-like types', () => {
|
|
15
15
|
for (const op of ['starts_with', 'ends_with'] as const) {
|
|
16
16
|
const types = OPERATORS.find((o) => o.id === op)?.types ?? []
|
|
17
|
-
expect(types).toEqual(['string'])
|
|
17
|
+
expect(types).toEqual(['string', 'contact-address'])
|
|
18
18
|
}
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
+
it('treats contact-address like a string (one canonical value)', () => {
|
|
22
|
+
const ops = operatorsForType('contact-address').map((o) => o.id)
|
|
23
|
+
for (const expected of [
|
|
24
|
+
'eq',
|
|
25
|
+
'ne',
|
|
26
|
+
'in',
|
|
27
|
+
'not_in',
|
|
28
|
+
'contains',
|
|
29
|
+
'starts_with',
|
|
30
|
+
'ends_with',
|
|
31
|
+
'empty',
|
|
32
|
+
'not_empty',
|
|
33
|
+
]) {
|
|
34
|
+
expect(ops).toContain(expected)
|
|
35
|
+
}
|
|
36
|
+
expect(ops).not.toContain('gt')
|
|
37
|
+
})
|
|
38
|
+
|
|
21
39
|
it('allows in / not_in on strings, numbers, and enums (not datetime/boolean/array)', () => {
|
|
22
40
|
for (const op of ['in', 'not_in'] as const) {
|
|
23
41
|
const types = new Set(OPERATORS.find((o) => o.id === op)?.types ?? [])
|
|
@@ -18,44 +18,126 @@ export const OPERATORS: ReadonlyArray<OperatorDescriptor> = [
|
|
|
18
18
|
id: 'eq',
|
|
19
19
|
label: 'is',
|
|
20
20
|
arity: 1,
|
|
21
|
-
types: [
|
|
21
|
+
types: [
|
|
22
|
+
'string',
|
|
23
|
+
'number',
|
|
24
|
+
'integer',
|
|
25
|
+
'currency',
|
|
26
|
+
'datetime',
|
|
27
|
+
'enum',
|
|
28
|
+
'boolean',
|
|
29
|
+
'relation',
|
|
30
|
+
'user',
|
|
31
|
+
'principal',
|
|
32
|
+
'contact-address',
|
|
33
|
+
],
|
|
22
34
|
},
|
|
23
35
|
{
|
|
24
36
|
id: 'ne',
|
|
25
37
|
label: 'is not',
|
|
26
38
|
arity: 1,
|
|
27
|
-
types: [
|
|
39
|
+
types: [
|
|
40
|
+
'string',
|
|
41
|
+
'number',
|
|
42
|
+
'integer',
|
|
43
|
+
'currency',
|
|
44
|
+
'datetime',
|
|
45
|
+
'enum',
|
|
46
|
+
'boolean',
|
|
47
|
+
'relation',
|
|
48
|
+
'user',
|
|
49
|
+
'principal',
|
|
50
|
+
'contact-address',
|
|
51
|
+
],
|
|
28
52
|
},
|
|
29
53
|
{
|
|
30
54
|
id: 'in',
|
|
31
55
|
label: 'is any of',
|
|
32
56
|
arity: 'n',
|
|
33
|
-
types: [
|
|
57
|
+
types: [
|
|
58
|
+
'string',
|
|
59
|
+
'number',
|
|
60
|
+
'integer',
|
|
61
|
+
'currency',
|
|
62
|
+
'enum',
|
|
63
|
+
'relation',
|
|
64
|
+
'user',
|
|
65
|
+
'principal',
|
|
66
|
+
'contact-address',
|
|
67
|
+
],
|
|
34
68
|
},
|
|
35
69
|
{
|
|
36
70
|
id: 'not_in',
|
|
37
71
|
label: 'is none of',
|
|
38
72
|
arity: 'n',
|
|
39
|
-
types: [
|
|
73
|
+
types: [
|
|
74
|
+
'string',
|
|
75
|
+
'number',
|
|
76
|
+
'integer',
|
|
77
|
+
'currency',
|
|
78
|
+
'enum',
|
|
79
|
+
'relation',
|
|
80
|
+
'user',
|
|
81
|
+
'principal',
|
|
82
|
+
'contact-address',
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
{ id: 'contains', label: 'contains', arity: 1, types: ['string', 'array', 'contact-address'] },
|
|
86
|
+
{ id: 'starts_with', label: 'starts with', arity: 1, types: ['string', 'contact-address'] },
|
|
87
|
+
{ id: 'ends_with', label: 'ends with', arity: 1, types: ['string', 'contact-address'] },
|
|
88
|
+
{
|
|
89
|
+
id: 'gt',
|
|
90
|
+
label: 'is greater than',
|
|
91
|
+
arity: 1,
|
|
92
|
+
types: ['number', 'integer', 'currency', 'datetime'],
|
|
40
93
|
},
|
|
41
|
-
{ id: 'contains', label: 'contains', arity: 1, types: ['string', 'array'] },
|
|
42
|
-
{ id: 'starts_with', label: 'starts with', arity: 1, types: ['string'] },
|
|
43
|
-
{ id: 'ends_with', label: 'ends with', arity: 1, types: ['string'] },
|
|
44
|
-
{ id: 'gt', label: 'is greater than', arity: 1, types: ['number', 'integer', 'currency', 'datetime'] },
|
|
45
94
|
{ id: 'gte', label: 'is on or after', arity: 1, types: ['datetime'] },
|
|
46
|
-
{
|
|
95
|
+
{
|
|
96
|
+
id: 'lt',
|
|
97
|
+
label: 'is less than',
|
|
98
|
+
arity: 1,
|
|
99
|
+
types: ['number', 'integer', 'currency', 'datetime'],
|
|
100
|
+
},
|
|
47
101
|
{ id: 'lte', label: 'is on or before', arity: 1, types: ['datetime'] },
|
|
48
102
|
{
|
|
49
103
|
id: 'empty',
|
|
50
104
|
label: 'is empty',
|
|
51
105
|
arity: 0,
|
|
52
|
-
types: [
|
|
106
|
+
types: [
|
|
107
|
+
'string',
|
|
108
|
+
'number',
|
|
109
|
+
'integer',
|
|
110
|
+
'currency',
|
|
111
|
+
'datetime',
|
|
112
|
+
'enum',
|
|
113
|
+
'boolean',
|
|
114
|
+
'array',
|
|
115
|
+
'relation',
|
|
116
|
+
'user',
|
|
117
|
+
'principal',
|
|
118
|
+
'file',
|
|
119
|
+
'contact-address',
|
|
120
|
+
],
|
|
53
121
|
},
|
|
54
122
|
{
|
|
55
123
|
id: 'not_empty',
|
|
56
124
|
label: 'is not empty',
|
|
57
125
|
arity: 0,
|
|
58
|
-
types: [
|
|
126
|
+
types: [
|
|
127
|
+
'string',
|
|
128
|
+
'number',
|
|
129
|
+
'integer',
|
|
130
|
+
'currency',
|
|
131
|
+
'datetime',
|
|
132
|
+
'enum',
|
|
133
|
+
'boolean',
|
|
134
|
+
'array',
|
|
135
|
+
'relation',
|
|
136
|
+
'user',
|
|
137
|
+
'principal',
|
|
138
|
+
'file',
|
|
139
|
+
'contact-address',
|
|
140
|
+
],
|
|
59
141
|
},
|
|
60
142
|
]
|
|
61
143
|
|