@nixxie-cms/core 1.0.3 → 2.0.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/CHANGELOG.md +36 -0
- package/CHANGES-1.1.md +134 -0
- package/context/dist/nixxie-cms-core-context.cjs.js +4 -3
- package/context/dist/nixxie-cms-core-context.esm.js +3 -2
- package/dist/declarations/src/access.d.ts +2 -2
- package/dist/declarations/src/access.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts +2 -2
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/context.d.ts +6 -6
- package/dist/declarations/src/admin-ui/context.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/Fields.d.ts +3 -3
- package/dist/declarations/src/admin-ui/utils/Fields.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/filters.d.ts +5 -5
- package/dist/declarations/src/admin-ui/utils/filters.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts +3 -3
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/utils.d.ts +2 -2
- package/dist/declarations/src/admin-ui/utils/utils.d.ts.map +1 -1
- package/dist/declarations/src/context.d.ts +1 -1
- package/dist/declarations/src/context.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bigInt/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/bigInt/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bytes/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/bytes/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/calendarDay/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/calendarDay/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/checkbox/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/checkbox/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/decimal/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/decimal/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/file/index.d.ts +4 -4
- package/dist/declarations/src/fields/types/file/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/float/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/float/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/image/index.d.ts +4 -4
- package/dist/declarations/src/fields/types/image/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/integer/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/integer/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/json/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/json/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/multiselect/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/multiselect/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/multiselect/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/password/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/password/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/index.d.ts +8 -8
- package/dist/declarations/src/fields/types/relationship/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/types.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/types.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/select/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/select/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/text/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/text/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/timestamp/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/timestamp/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/virtual/index.d.ts +7 -7
- package/dist/declarations/src/fields/types/virtual/index.d.ts.map +1 -1
- package/dist/declarations/src/helpers.d.ts +249 -13
- package/dist/declarations/src/helpers.d.ts.map +1 -1
- package/dist/declarations/src/index.d.ts +9 -4
- package/dist/declarations/src/index.d.ts.map +1 -1
- package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -1
- package/dist/declarations/src/lib/admin-meta.d.ts +11 -11
- package/dist/declarations/src/lib/admin-meta.d.ts.map +1 -1
- package/dist/declarations/src/lib/core/access-control.d.ts +18 -18
- package/dist/declarations/src/lib/core/access-control.d.ts.map +1 -1
- package/dist/declarations/src/lib/core/cascade.d.ts +47 -0
- package/dist/declarations/src/lib/core/cascade.d.ts.map +1 -0
- package/dist/declarations/src/lib/core/initialise-lists.d.ts +27 -24
- package/dist/declarations/src/lib/core/initialise-lists.d.ts.map +1 -1
- package/dist/declarations/src/lib/env.d.ts +9 -0
- package/dist/declarations/src/lib/env.d.ts.map +1 -0
- package/dist/declarations/src/lib/system.d.ts +1 -1
- package/dist/declarations/src/lib/system.d.ts.map +1 -1
- package/dist/declarations/src/list-features.d.ts +162 -0
- package/dist/declarations/src/list-features.d.ts.map +1 -0
- package/dist/declarations/src/schema.d.ts +24 -23
- package/dist/declarations/src/schema.d.ts.map +1 -1
- package/dist/declarations/src/session.d.ts +75 -0
- package/dist/declarations/src/session.d.ts.map +1 -1
- package/dist/declarations/src/types/admin-meta.d.ts +11 -11
- package/dist/declarations/src/types/admin-meta.d.ts.map +1 -1
- package/dist/declarations/src/types/config/access-control.d.ts +42 -42
- package/dist/declarations/src/types/config/access-control.d.ts.map +1 -1
- package/dist/declarations/src/types/config/fields.d.ts +19 -19
- package/dist/declarations/src/types/config/fields.d.ts.map +1 -1
- package/dist/declarations/src/types/config/hooks.d.ts +131 -131
- package/dist/declarations/src/types/config/hooks.d.ts.map +1 -1
- package/dist/declarations/src/types/config/index.d.ts +190 -8
- package/dist/declarations/src/types/config/index.d.ts.map +1 -1
- package/dist/declarations/src/types/config/lists.d.ts +146 -108
- package/dist/declarations/src/types/config/lists.d.ts.map +1 -1
- package/dist/declarations/src/types/context.d.ts +507 -47
- package/dist/declarations/src/types/context.d.ts.map +1 -1
- package/dist/declarations/src/types/next-fields.d.ts +28 -28
- package/dist/declarations/src/types/next-fields.d.ts.map +1 -1
- package/dist/declarations/src/types/type-info.d.ts +3 -3
- package/dist/declarations/src/types/type-info.d.ts.map +1 -1
- package/dist/{express-455ae20c.cjs.js → express-84d534c2.cjs.js} +6 -6
- package/dist/{express-7559ca2d.esm.js → express-d0a4ce99.esm.js} +6 -6
- package/dist/{index-15c8f81e.esm.js → index-5d8b0b4e.esm.js} +363 -183
- package/dist/index-6055753b.cjs.js +393 -0
- package/dist/{index-42045902.cjs.js → index-ac29f382.cjs.js} +363 -185
- package/dist/index-f1703b7b.esm.js +386 -0
- package/dist/nixxie-cms-core.cjs.js +1388 -30
- package/dist/nixxie-cms-core.esm.js +1362 -24
- package/dist/{non-null-graphql-add6bb3d.cjs.js → non-null-graphql-4a44c122.cjs.js} +1 -1
- package/dist/{non-null-graphql-a84ed64d.esm.js → non-null-graphql-8c5feaae.esm.js} +1 -1
- package/dist/{resolve-hooks-165a9ce2.cjs.js → resolve-hooks-10a5f84c.cjs.js} +240 -6
- package/dist/{resolve-hooks-6813a045.esm.js → resolve-hooks-9e676794.esm.js} +238 -7
- package/dist/{system-a321642d.cjs.js → system-6b37a5f8.cjs.js} +33 -7
- package/dist/{system-03e49e4f.esm.js → system-e591d821.esm.js} +33 -7
- package/fields/dist/nixxie-cms-core-fields.cjs.js +29 -576
- package/fields/dist/nixxie-cms-core-fields.esm.js +18 -565
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +4 -2
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +4 -2
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.js +1 -6
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.esm.js +1 -6
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +4 -2
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +4 -2
- package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +4 -3
- package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +4 -3
- package/package.json +4 -4
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +4 -3
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +4 -3
- package/scripts/dist/nixxie-cms-core-scripts.cjs.js +4 -3
- package/scripts/dist/nixxie-cms-core-scripts.esm.js +4 -3
- package/session/dist/nixxie-cms-core-session.cjs.js +286 -0
- package/session/dist/nixxie-cms-core-session.esm.js +279 -1
- package/src/access.ts +25 -25
- package/src/admin-ui/admin-meta-graphql.ts +5 -5
- package/src/admin-ui/components/CreateButtonLink.tsx +46 -46
- package/src/admin-ui/components/Navigation.tsx +3 -3
- package/src/admin-ui/context.tsx +6 -6
- package/src/admin-ui/utils/Fields.tsx +241 -241
- package/src/admin-ui/utils/actionData.ts +36 -36
- package/src/admin-ui/utils/filters.ts +148 -148
- package/src/admin-ui/utils/useCreateItem.ts +171 -171
- package/src/admin-ui/utils/utils.tsx +127 -127
- package/src/context.ts +1 -1
- package/src/fields/non-null-graphql.ts +115 -115
- package/src/fields/types/bigInt/index.ts +6 -6
- package/src/fields/types/bytes/index.ts +6 -6
- package/src/fields/types/calendarDay/index.ts +18 -19
- package/src/fields/types/checkbox/index.ts +6 -6
- package/src/fields/types/decimal/index.ts +6 -6
- package/src/fields/types/file/index.ts +8 -8
- package/src/fields/types/float/index.ts +6 -6
- package/src/fields/types/image/index.ts +8 -8
- package/src/fields/types/integer/index.ts +6 -6
- package/src/fields/types/json/index.ts +5 -5
- package/src/fields/types/multiselect/index.ts +7 -7
- package/src/fields/types/multiselect/views/index.tsx +149 -151
- package/src/fields/types/password/index.ts +6 -6
- package/src/fields/types/relationship/index.ts +13 -13
- package/src/fields/types/relationship/views/ComboboxMany.tsx +110 -110
- package/src/fields/types/relationship/views/ComboboxSingle.tsx +115 -115
- package/src/fields/types/relationship/views/ContextualActions.tsx +139 -139
- package/src/fields/types/relationship/views/index.tsx +492 -492
- package/src/fields/types/relationship/views/types.ts +46 -46
- package/src/fields/types/relationship/views/useApolloQuery.ts +185 -185
- package/src/fields/types/relationship/views/useFilter.tsx +109 -109
- package/src/fields/types/select/index.ts +6 -6
- package/src/fields/types/text/index.ts +6 -6
- package/src/fields/types/timestamp/index.ts +23 -21
- package/src/fields/types/virtual/index.ts +11 -11
- package/src/helpers.ts +773 -42
- package/src/index.ts +66 -24
- package/src/internal-unstable/admin-ui/pages/ItemPage/common.tsx +4 -4
- package/src/internal-unstable/admin-ui/pages/ItemPage/index.tsx +5 -5
- package/src/internal-unstable/admin-ui/pages/ListPage/index.tsx +8 -8
- package/src/lib/admin-meta.ts +369 -369
- package/src/lib/context/createContext.ts +6 -0
- package/src/lib/core/access-control.ts +434 -434
- package/src/lib/core/cascade.ts +236 -0
- package/src/lib/core/initialise-lists.ts +49 -33
- package/src/lib/core/mutations/index.ts +7 -0
- package/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts +145 -145
- package/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts +71 -71
- package/src/lib/core/queries/output-field.ts +178 -178
- package/src/lib/env.ts +50 -0
- package/src/lib/id-field.ts +2 -2
- package/src/lib/system.ts +221 -207
- package/src/lib/typescript-schema-printer.ts +227 -227
- package/src/list-features.ts +476 -0
- package/src/schema.ts +92 -22
- package/src/session.ts +225 -0
- package/src/types/admin-meta.ts +218 -218
- package/src/types/config/access-control.ts +186 -186
- package/src/types/config/fields.ts +96 -96
- package/src/types/config/hooks.ts +529 -529
- package/src/types/config/index.ts +206 -7
- package/src/types/config/lists.ts +606 -565
- package/src/types/context.ts +592 -55
- package/src/types/next-fields.ts +31 -31
- package/src/types/type-info.ts +38 -38
- package/src/types/type-tests.ts +21 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SimpleFieldTypeInfo } from '../../../types'
|
|
2
2
|
import {
|
|
3
|
-
type
|
|
3
|
+
type BaseCollectionTypeInfo,
|
|
4
4
|
type CommonFieldConfig,
|
|
5
5
|
type FieldTypeFunc,
|
|
6
6
|
fieldType,
|
|
@@ -12,8 +12,8 @@ import { filters } from '../../filters'
|
|
|
12
12
|
import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
|
|
13
13
|
import type { controller } from './views'
|
|
14
14
|
|
|
15
|
-
export type DecimalFieldConfig<
|
|
16
|
-
|
|
15
|
+
export type DecimalFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
16
|
+
CollectionTypeInfo,
|
|
17
17
|
SimpleFieldTypeInfo<'Decimal'>
|
|
18
18
|
> & {
|
|
19
19
|
isIndexed?: boolean | 'unique'
|
|
@@ -40,9 +40,9 @@ function safeParseDecimal(value: string | null | undefined) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// TODO: https://github.com/Nixxie/keystatic/blob/main/design-system/pkg/src/number-field/NumberField.tsx
|
|
43
|
-
export function decimal<
|
|
44
|
-
config: DecimalFieldConfig<
|
|
45
|
-
): FieldTypeFunc<
|
|
43
|
+
export function decimal<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
44
|
+
config: DecimalFieldConfig<CollectionTypeInfo> = {}
|
|
45
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
46
46
|
const {
|
|
47
47
|
defaultValue: defaultValue_,
|
|
48
48
|
isIndexed,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BaseNixxieTypeInfo,
|
|
3
|
-
|
|
3
|
+
BaseCollectionTypeInfo,
|
|
4
4
|
CommonFieldConfig,
|
|
5
5
|
FieldHooks,
|
|
6
6
|
FieldTypeFunc,
|
|
@@ -29,11 +29,11 @@ export type FieldTypeInfo = {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export type FileFieldConfig<
|
|
33
|
-
|
|
32
|
+
export type FileFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
33
|
+
CollectionTypeInfo,
|
|
34
34
|
FieldTypeInfo
|
|
35
35
|
> & {
|
|
36
|
-
storage: StorageStrategy<
|
|
36
|
+
storage: StorageStrategy<CollectionTypeInfo['all']>
|
|
37
37
|
transformName?: (originalFilename: string) => MaybePromise<string>
|
|
38
38
|
db?: {
|
|
39
39
|
extendPrismaSchema?: (field: string) => string
|
|
@@ -81,9 +81,9 @@ async function inputResolver(
|
|
|
81
81
|
return { filename, filesize }
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
export function file<
|
|
85
|
-
config: FileFieldConfig<
|
|
86
|
-
): FieldTypeFunc<
|
|
84
|
+
export function file<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
85
|
+
config: FileFieldConfig<CollectionTypeInfo>
|
|
86
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
87
87
|
const { transformName = defaultTransformName } = config
|
|
88
88
|
return meta => {
|
|
89
89
|
const { fieldKey } = meta
|
|
@@ -93,7 +93,7 @@ export function file<ListTypeInfo extends BaseListTypeInfo>(
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
const afterOperationResolver: Extract<
|
|
96
|
-
FieldHooks<
|
|
96
|
+
FieldHooks<BaseCollectionTypeInfo, FieldTypeInfo>['afterOperation'],
|
|
97
97
|
(args: any) => any
|
|
98
98
|
> = async function afterOperationResolver(args) {
|
|
99
99
|
if (args.operation === 'update' || args.operation === 'delete') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SimpleFieldTypeInfo } from '../../../types'
|
|
2
2
|
import {
|
|
3
|
-
type
|
|
3
|
+
type BaseCollectionTypeInfo,
|
|
4
4
|
type FieldTypeFunc,
|
|
5
5
|
type CommonFieldConfig,
|
|
6
6
|
fieldType,
|
|
@@ -11,8 +11,8 @@ import { filters } from '../../filters'
|
|
|
11
11
|
import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
|
|
12
12
|
import type { controller } from './views'
|
|
13
13
|
|
|
14
|
-
export type FloatFieldConfig<
|
|
15
|
-
|
|
14
|
+
export type FloatFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
15
|
+
CollectionTypeInfo,
|
|
16
16
|
SimpleFieldTypeInfo<'Float'>
|
|
17
17
|
> & {
|
|
18
18
|
isIndexed?: boolean | 'unique'
|
|
@@ -29,9 +29,9 @@ export type FloatFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFiel
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function float<
|
|
33
|
-
config: FloatFieldConfig<
|
|
34
|
-
): FieldTypeFunc<
|
|
32
|
+
export function float<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
33
|
+
config: FloatFieldConfig<CollectionTypeInfo> = {}
|
|
34
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
35
35
|
const { defaultValue: defaultValue_, isIndexed, validation = {} } = config
|
|
36
36
|
|
|
37
37
|
const { isRequired = false, min, max } = validation
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
2
|
+
BaseCollectionTypeInfo,
|
|
3
3
|
FieldTypeFunc,
|
|
4
4
|
CommonFieldConfig,
|
|
5
5
|
NixxieContext,
|
|
@@ -32,11 +32,11 @@ export type FieldTypeInfo = {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export type ImageFieldConfig<
|
|
36
|
-
|
|
35
|
+
export type ImageFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
36
|
+
CollectionTypeInfo,
|
|
37
37
|
FieldTypeInfo
|
|
38
38
|
> & {
|
|
39
|
-
storage: StorageStrategy<
|
|
39
|
+
storage: StorageStrategy<CollectionTypeInfo['all']>
|
|
40
40
|
transformName?: (originalFilename: string, extension: string) => MaybePromise<string>
|
|
41
41
|
db?: {
|
|
42
42
|
extendPrismaSchema?: (field: string) => string
|
|
@@ -149,9 +149,9 @@ function isValidImageExtension(extension: string): extension is ImageExtension {
|
|
|
149
149
|
return extensionsSet.has(extension)
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
export function image<
|
|
153
|
-
config: ImageFieldConfig<
|
|
154
|
-
): FieldTypeFunc<
|
|
152
|
+
export function image<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
153
|
+
config: ImageFieldConfig<CollectionTypeInfo>
|
|
154
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
155
155
|
const { transformName = defaultTransformName } = config
|
|
156
156
|
return meta => {
|
|
157
157
|
const { fieldKey } = meta
|
|
@@ -161,7 +161,7 @@ export function image<ListTypeInfo extends BaseListTypeInfo>(
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
const afterOperationResolver: Extract<
|
|
164
|
-
FieldHooks<
|
|
164
|
+
FieldHooks<BaseCollectionTypeInfo, FieldTypeInfo>['afterOperation'],
|
|
165
165
|
(args: any) => any
|
|
166
166
|
> = async function afterOperationResolver(args) {
|
|
167
167
|
if (args.operation === 'update' || args.operation === 'delete') {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { g } from '../../..'
|
|
2
2
|
import type { SimpleFieldTypeInfo } from '../../../types'
|
|
3
3
|
import {
|
|
4
|
-
type
|
|
4
|
+
type BaseCollectionTypeInfo,
|
|
5
5
|
type CommonFieldConfig,
|
|
6
6
|
type FieldTypeFunc,
|
|
7
7
|
fieldType,
|
|
@@ -11,8 +11,8 @@ import { filters } from '../../filters'
|
|
|
11
11
|
import { defaultIsRequired, makeValidateHook } from '../../non-null-graphql'
|
|
12
12
|
import type { controller } from './views'
|
|
13
13
|
|
|
14
|
-
export type IntegerFieldConfig<
|
|
15
|
-
|
|
14
|
+
export type IntegerFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
15
|
+
CollectionTypeInfo,
|
|
16
16
|
SimpleFieldTypeInfo<'Int'>
|
|
17
17
|
> & {
|
|
18
18
|
isIndexed?: boolean | 'unique'
|
|
@@ -33,9 +33,9 @@ export type IntegerFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFi
|
|
|
33
33
|
const MAX_INT = 0x7fffffff
|
|
34
34
|
const MIN_INT = -0x80000000
|
|
35
35
|
|
|
36
|
-
export function integer<
|
|
37
|
-
config: IntegerFieldConfig<
|
|
38
|
-
): FieldTypeFunc<
|
|
36
|
+
export function integer<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
37
|
+
config: IntegerFieldConfig<CollectionTypeInfo> = {}
|
|
38
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
39
39
|
const { defaultValue: defaultValue_, isIndexed, validation = {} } = config
|
|
40
40
|
|
|
41
41
|
const { isRequired = false, min, max } = validation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { g } from '../../..'
|
|
2
2
|
import {
|
|
3
|
-
type
|
|
3
|
+
type BaseCollectionTypeInfo,
|
|
4
4
|
type CommonFieldConfig,
|
|
5
5
|
fieldType,
|
|
6
6
|
type FieldTypeFunc,
|
|
@@ -22,18 +22,18 @@ type FieldTypeInfo = {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export type JsonFieldConfig<
|
|
26
|
-
|
|
25
|
+
export type JsonFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
26
|
+
CollectionTypeInfo,
|
|
27
27
|
FieldTypeInfo
|
|
28
28
|
> & {
|
|
29
29
|
defaultValue?: JSONValue
|
|
30
30
|
db?: { map?: string; extendPrismaSchema?: (field: string) => string }
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export function json<
|
|
33
|
+
export function json<CollectionTypeInfo extends BaseCollectionTypeInfo>({
|
|
34
34
|
defaultValue = null,
|
|
35
35
|
...config
|
|
36
|
-
}: JsonFieldConfig<
|
|
36
|
+
}: JsonFieldConfig<CollectionTypeInfo> = {}): FieldTypeFunc<CollectionTypeInfo> {
|
|
37
37
|
return meta => {
|
|
38
38
|
if ((config as any).isIndexed === 'unique') {
|
|
39
39
|
throw Error("isIndexed: 'unique' is not a supported option for field type json")
|
|
@@ -2,7 +2,7 @@ import { g } from '../../..'
|
|
|
2
2
|
import { humanize } from '../../../lib/utils'
|
|
3
3
|
import type { JSONValue } from '../../../types'
|
|
4
4
|
import {
|
|
5
|
-
type
|
|
5
|
+
type BaseCollectionTypeInfo,
|
|
6
6
|
type CommonFieldConfig,
|
|
7
7
|
type FieldData,
|
|
8
8
|
fieldType,
|
|
@@ -26,8 +26,8 @@ type FieldTypeInfo = {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export type MultiselectFieldConfig<
|
|
30
|
-
|
|
29
|
+
export type MultiselectFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
30
|
+
CollectionTypeInfo,
|
|
31
31
|
FieldTypeInfo
|
|
32
32
|
> &
|
|
33
33
|
(
|
|
@@ -63,9 +63,9 @@ export type MultiselectFieldConfig<ListTypeInfo extends BaseListTypeInfo> = Comm
|
|
|
63
63
|
const MAX_INT = 2147483647
|
|
64
64
|
const MIN_INT = -2147483648
|
|
65
65
|
|
|
66
|
-
export function multiselect<
|
|
67
|
-
config: MultiselectFieldConfig<
|
|
68
|
-
): FieldTypeFunc<
|
|
66
|
+
export function multiselect<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
67
|
+
config: MultiselectFieldConfig<CollectionTypeInfo>
|
|
68
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
69
69
|
const { defaultValue: defaultValue_, ui: { displayMode = 'select', ...ui } = {} } = config
|
|
70
70
|
|
|
71
71
|
config.db ??= {}
|
|
@@ -165,7 +165,7 @@ export function multiselect<ListTypeInfo extends BaseListTypeInfo>(
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
function configToOptionsAndGraphQLType(
|
|
168
|
-
config: MultiselectFieldConfig<
|
|
168
|
+
config: MultiselectFieldConfig<BaseCollectionTypeInfo>,
|
|
169
169
|
meta: FieldData
|
|
170
170
|
) {
|
|
171
171
|
if (config.type === 'integer') {
|
|
@@ -1,151 +1,149 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { useFilter, useListFormatter } from '@react-aria/i18n'
|
|
3
|
-
|
|
4
|
-
import { Checkbox, CheckboxGroup } from '@keystar/ui/checkbox'
|
|
5
|
-
import { Combobox, Item } from '@keystar/ui/combobox'
|
|
6
|
-
import { VStack } from '@keystar/ui/layout'
|
|
7
|
-
import { TagGroup } from '@keystar/ui/tag'
|
|
8
|
-
import { Text } from '@keystar/ui/typography'
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
CellComponent,
|
|
12
|
-
FieldController,
|
|
13
|
-
FieldControllerConfig,
|
|
14
|
-
FieldProps,
|
|
15
|
-
} from '../../../../types'
|
|
16
|
-
|
|
17
|
-
export function Field(props: FieldProps<typeof controller>) {
|
|
18
|
-
if (props.field.displayMode === 'checkboxes') return <CheckboxesModeField {...props} />
|
|
19
|
-
return <SelectModeField {...props} />
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function SelectModeField(props: FieldProps<typeof controller>) {
|
|
23
|
-
const { field, onChange, value } = props
|
|
24
|
-
const [filterText, setFilterText] = useState('')
|
|
25
|
-
const { contains } = useFilter({ sensitivity: 'base' })
|
|
26
|
-
const items = field.options.filter(option => !value.some(x => x.value === option.value))
|
|
27
|
-
const filteredItems = filterText ? items.filter(item => contains(item.label, filterText)) : items
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<VStack gap="regular">
|
|
31
|
-
<Combobox
|
|
32
|
-
label={field.label}
|
|
33
|
-
description={field.description}
|
|
34
|
-
isReadOnly={onChange === undefined}
|
|
35
|
-
items={filteredItems}
|
|
36
|
-
loadingState="idle"
|
|
37
|
-
onInputChange={setFilterText}
|
|
38
|
-
inputValue={filterText}
|
|
39
|
-
// selectedKey={null}
|
|
40
|
-
onSelectionChange={key => {
|
|
41
|
-
if (key == null) return
|
|
42
|
-
onChange?.([...value, field.valuesToOptionsWithStringValues[key]])
|
|
43
|
-
}}
|
|
44
|
-
width="auto"
|
|
45
|
-
>
|
|
46
|
-
{item => <Item key={item.value}>{item.label}</Item>}
|
|
47
|
-
</Combobox>
|
|
48
|
-
|
|
49
|
-
<TagGroup
|
|
50
|
-
aria-label={`${field.label} selected items`}
|
|
51
|
-
items={value}
|
|
52
|
-
maxRows={2}
|
|
53
|
-
onRemove={keys => {
|
|
54
|
-
const key = keys.values().next().value
|
|
55
|
-
onChange?.(value.filter(x => x.value !== key))
|
|
56
|
-
}}
|
|
57
|
-
renderEmptyState={() => (
|
|
58
|
-
<Text color="neutralSecondary" size="small">
|
|
59
|
-
No items…
|
|
60
|
-
</Text>
|
|
61
|
-
)}
|
|
62
|
-
>
|
|
63
|
-
{item => <Item key={item.value}>{item.label}</Item>}
|
|
64
|
-
</TagGroup>
|
|
65
|
-
</VStack>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function CheckboxesModeField(props: FieldProps<typeof controller>) {
|
|
70
|
-
const { field, onChange, value } = props
|
|
71
|
-
return (
|
|
72
|
-
<CheckboxGroup
|
|
73
|
-
label={field.label}
|
|
74
|
-
description={field.description}
|
|
75
|
-
isReadOnly={onChange === undefined}
|
|
76
|
-
value={value.map(x => x.value)}
|
|
77
|
-
onChange={keys => {
|
|
78
|
-
onChange?.(keys.map(key => field.valuesToOptionsWithStringValues[key]))
|
|
79
|
-
}}
|
|
80
|
-
>
|
|
81
|
-
{field.options.map(option => (
|
|
82
|
-
<Checkbox key={option.value} value={option.value}>
|
|
83
|
-
{option.label}
|
|
84
|
-
</Checkbox>
|
|
85
|
-
))}
|
|
86
|
-
</CheckboxGroup>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export const Cell: CellComponent<typeof controller> = ({ value = [], field }) => {
|
|
91
|
-
const listFormatter = useListFormatter({ style: 'short', type: 'conjunction' })
|
|
92
|
-
const labels = (value as string[]).map(x => field.valuesToOptionsWithStringValues[x].label)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
type
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
}
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { useFilter, useListFormatter } from '@react-aria/i18n'
|
|
3
|
+
|
|
4
|
+
import { Checkbox, CheckboxGroup } from '@keystar/ui/checkbox'
|
|
5
|
+
import { Combobox, Item } from '@keystar/ui/combobox'
|
|
6
|
+
import { VStack } from '@keystar/ui/layout'
|
|
7
|
+
import { TagGroup } from '@keystar/ui/tag'
|
|
8
|
+
import { Text } from '@keystar/ui/typography'
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
CellComponent,
|
|
12
|
+
FieldController,
|
|
13
|
+
FieldControllerConfig,
|
|
14
|
+
FieldProps,
|
|
15
|
+
} from '../../../../types'
|
|
16
|
+
|
|
17
|
+
export function Field(props: FieldProps<typeof controller>) {
|
|
18
|
+
if (props.field.displayMode === 'checkboxes') return <CheckboxesModeField {...props} />
|
|
19
|
+
return <SelectModeField {...props} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function SelectModeField(props: FieldProps<typeof controller>) {
|
|
23
|
+
const { field, onChange, value } = props
|
|
24
|
+
const [filterText, setFilterText] = useState('')
|
|
25
|
+
const { contains } = useFilter({ sensitivity: 'base' })
|
|
26
|
+
const items = field.options.filter(option => !value.some(x => x.value === option.value))
|
|
27
|
+
const filteredItems = filterText ? items.filter(item => contains(item.label, filterText)) : items
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<VStack gap="regular">
|
|
31
|
+
<Combobox
|
|
32
|
+
label={field.label}
|
|
33
|
+
description={field.description}
|
|
34
|
+
isReadOnly={onChange === undefined}
|
|
35
|
+
items={filteredItems}
|
|
36
|
+
loadingState="idle"
|
|
37
|
+
onInputChange={setFilterText}
|
|
38
|
+
inputValue={filterText}
|
|
39
|
+
// selectedKey={null}
|
|
40
|
+
onSelectionChange={key => {
|
|
41
|
+
if (key == null) return
|
|
42
|
+
onChange?.([...value, field.valuesToOptionsWithStringValues[key]])
|
|
43
|
+
}}
|
|
44
|
+
width="auto"
|
|
45
|
+
>
|
|
46
|
+
{item => <Item key={item.value}>{item.label}</Item>}
|
|
47
|
+
</Combobox>
|
|
48
|
+
|
|
49
|
+
<TagGroup
|
|
50
|
+
aria-label={`${field.label} selected items`}
|
|
51
|
+
items={value}
|
|
52
|
+
maxRows={2}
|
|
53
|
+
onRemove={keys => {
|
|
54
|
+
const key = keys.values().next().value
|
|
55
|
+
onChange?.(value.filter(x => x.value !== key))
|
|
56
|
+
}}
|
|
57
|
+
renderEmptyState={() => (
|
|
58
|
+
<Text color="neutralSecondary" size="small">
|
|
59
|
+
No items…
|
|
60
|
+
</Text>
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
{item => <Item key={item.value}>{item.label}</Item>}
|
|
64
|
+
</TagGroup>
|
|
65
|
+
</VStack>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function CheckboxesModeField(props: FieldProps<typeof controller>) {
|
|
70
|
+
const { field, onChange, value } = props
|
|
71
|
+
return (
|
|
72
|
+
<CheckboxGroup
|
|
73
|
+
label={field.label}
|
|
74
|
+
description={field.description}
|
|
75
|
+
isReadOnly={onChange === undefined}
|
|
76
|
+
value={value.map(x => x.value)}
|
|
77
|
+
onChange={keys => {
|
|
78
|
+
onChange?.(keys.map(key => field.valuesToOptionsWithStringValues[key]))
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{field.options.map(option => (
|
|
82
|
+
<Checkbox key={option.value} value={option.value}>
|
|
83
|
+
{option.label}
|
|
84
|
+
</Checkbox>
|
|
85
|
+
))}
|
|
86
|
+
</CheckboxGroup>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const Cell: CellComponent<typeof controller> = ({ value = [], field }) => {
|
|
91
|
+
const listFormatter = useListFormatter({ style: 'short', type: 'conjunction' })
|
|
92
|
+
const labels = (value as string[]).map(x => field.valuesToOptionsWithStringValues[x].label)
|
|
93
|
+
|
|
94
|
+
const cellContent =
|
|
95
|
+
value.length > 3
|
|
96
|
+
? listFormatter.format([labels[0], `${value.length - 1} more`])
|
|
97
|
+
: listFormatter.format(labels)
|
|
98
|
+
|
|
99
|
+
return <Text>{cellContent}</Text>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type AdminMultiSelectFieldMeta = {
|
|
103
|
+
options: readonly { label: string; value: string | number }[]
|
|
104
|
+
type: 'string' | 'integer' | 'enum'
|
|
105
|
+
displayMode: 'checkboxes' | 'select'
|
|
106
|
+
defaultValue: string[] | number[]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
type Config = FieldControllerConfig<AdminMultiSelectFieldMeta>
|
|
110
|
+
type Option = { label: string; value: string }
|
|
111
|
+
type Value = readonly Option[]
|
|
112
|
+
|
|
113
|
+
export function controller(config: Config): FieldController<Value, Option[]> & {
|
|
114
|
+
displayMode: 'checkboxes' | 'select'
|
|
115
|
+
options: Option[]
|
|
116
|
+
type: 'string' | 'integer' | 'enum'
|
|
117
|
+
valuesToOptionsWithStringValues: Record<string, Option>
|
|
118
|
+
} {
|
|
119
|
+
const optionsWithStringValues = config.fieldMeta.options.map(x => ({
|
|
120
|
+
label: x.label,
|
|
121
|
+
value: x.value.toString(),
|
|
122
|
+
}))
|
|
123
|
+
|
|
124
|
+
const valuesToOptionsWithStringValues = Object.fromEntries(
|
|
125
|
+
optionsWithStringValues.map(option => [option.value, option])
|
|
126
|
+
)
|
|
127
|
+
const parseValue = (value: string) =>
|
|
128
|
+
config.fieldMeta.type === 'integer' ? parseInt(value) : value
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
fieldKey: config.fieldKey,
|
|
132
|
+
label: config.label,
|
|
133
|
+
description: config.description,
|
|
134
|
+
displayMode: config.fieldMeta.displayMode,
|
|
135
|
+
type: config.fieldMeta.type,
|
|
136
|
+
options: optionsWithStringValues,
|
|
137
|
+
valuesToOptionsWithStringValues,
|
|
138
|
+
defaultValue: config.fieldMeta.defaultValue.map(x => valuesToOptionsWithStringValues[x]),
|
|
139
|
+
deserialize: data => {
|
|
140
|
+
// if we get null from the GraphQL API (which will only happen if field read access control failed)
|
|
141
|
+
// we'll just show it as nothing being selected for now.
|
|
142
|
+
const values: readonly string[] | readonly number[] = data[config.fieldKey] ?? []
|
|
143
|
+
const selectedOptions = values.map(x => valuesToOptionsWithStringValues[x])
|
|
144
|
+
return selectedOptions
|
|
145
|
+
},
|
|
146
|
+
serialize: value => ({ [config.fieldKey]: value.map(x => parseValue(x.value)) }),
|
|
147
|
+
graphqlSelection: config.fieldKey,
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -3,7 +3,7 @@ import bcryptjs from 'bcryptjs'
|
|
|
3
3
|
import dumbPasswords from 'dumb-passwords'
|
|
4
4
|
import { userInputError } from '../../../lib/core/graphql-errors'
|
|
5
5
|
import {
|
|
6
|
-
type
|
|
6
|
+
type BaseCollectionTypeInfo,
|
|
7
7
|
type CommonFieldConfig,
|
|
8
8
|
type FieldTypeFunc,
|
|
9
9
|
fieldType,
|
|
@@ -29,8 +29,8 @@ type FieldTypeInfo = {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export type PasswordFieldConfig<
|
|
33
|
-
|
|
32
|
+
export type PasswordFieldConfig<CollectionTypeInfo extends BaseCollectionTypeInfo> = CommonFieldConfig<
|
|
33
|
+
CollectionTypeInfo,
|
|
34
34
|
FieldTypeInfo
|
|
35
35
|
> & {
|
|
36
36
|
validation?: {
|
|
@@ -70,9 +70,9 @@ const PasswordFilter = g.inputObject({
|
|
|
70
70
|
},
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
-
export function password<
|
|
74
|
-
config: PasswordFieldConfig<
|
|
75
|
-
): FieldTypeFunc<
|
|
73
|
+
export function password<CollectionTypeInfo extends BaseCollectionTypeInfo>(
|
|
74
|
+
config: PasswordFieldConfig<CollectionTypeInfo> = {}
|
|
75
|
+
): FieldTypeFunc<CollectionTypeInfo> {
|
|
76
76
|
const {
|
|
77
77
|
kdf = {
|
|
78
78
|
hash: secret => {
|