@strato-admin/core 0.1.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/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/core/Resource.d.ts +0 -0
- package/dist/core/Resource.js +1 -0
- package/dist/core/index.d.ts +0 -0
- package/dist/core/index.js +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/ra-messages.d.ts +1 -0
- package/dist/ra-messages.js +296 -0
- package/dist/resource/FieldSchema.d.ts +18 -0
- package/dist/resource/FieldSchema.js +19 -0
- package/dist/resource/InputSchema.d.ts +18 -0
- package/dist/resource/InputSchema.js +19 -0
- package/dist/resource/ResourceContext.d.ts +2 -0
- package/dist/resource/ResourceContext.js +3 -0
- package/dist/resource/ResourceSchema.d.ts +27 -0
- package/dist/resource/ResourceSchema.js +69 -0
- package/dist/resource/ResourceSchemaProvider.d.ts +15 -0
- package/dist/resource/ResourceSchemaProvider.js +71 -0
- package/dist/resource/SchemaRegistry.d.ts +45 -0
- package/dist/resource/SchemaRegistry.js +145 -0
- package/dist/resource/index.d.ts +6 -0
- package/dist/resource/index.js +6 -0
- package/package.json +54 -0
- package/src/core/Resource.tsx +0 -0
- package/src/core/index.ts +0 -0
- package/src/index.ts +5 -0
- package/src/ra-messages.ts +352 -0
- package/src/resource/FieldSchema.tsx +26 -0
- package/src/resource/InputSchema.tsx +26 -0
- package/src/resource/ResourceContext.tsx +5 -0
- package/src/resource/ResourceSchema.tsx +125 -0
- package/src/resource/ResourceSchemaProvider.tsx +114 -0
- package/src/resource/SchemaRegistry.tsx +190 -0
- package/src/resource/index.ts +6 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { createContext, useContext, useState, useCallback, useMemo, Fragment } from 'react';
|
|
3
|
+
import { required } from '@strato-admin/ra-core';
|
|
4
|
+
import { FieldSchema } from './FieldSchema';
|
|
5
|
+
import { InputSchema } from './InputSchema';
|
|
6
|
+
const SchemaRegistryContext = createContext(undefined);
|
|
7
|
+
// Use a global store for schemas to ensure they are available even before
|
|
8
|
+
// components have finished their first render/useEffect cycle.
|
|
9
|
+
const globalSchemaRegistry = {};
|
|
10
|
+
let globalDefaultComponents = {};
|
|
11
|
+
const globalFieldInputMapping = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Registers default input components for given field components.
|
|
14
|
+
* This mapping is used by ResourceSchemaProvider to infer forms.
|
|
15
|
+
*/
|
|
16
|
+
export const registerFieldInputMapping = (mapping) => {
|
|
17
|
+
mapping.forEach((value, key) => {
|
|
18
|
+
globalFieldInputMapping.set(key, value);
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves the registered default input component for a field.
|
|
23
|
+
*/
|
|
24
|
+
export const getDefaultInputForField = (fieldComponent) => {
|
|
25
|
+
return globalFieldInputMapping.get(fieldComponent);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Synchronously registers schemas for a resource.
|
|
29
|
+
* Can be called during render or outside of React.
|
|
30
|
+
*/
|
|
31
|
+
export const registerGlobalSchemas = (resource, schemas) => {
|
|
32
|
+
if (!resource)
|
|
33
|
+
return;
|
|
34
|
+
const existing = globalSchemaRegistry[resource];
|
|
35
|
+
// Only update if we actually have new schema content to avoid redundant re-renders
|
|
36
|
+
if (schemas.fieldSchema || schemas.inputSchema) {
|
|
37
|
+
globalSchemaRegistry[resource] = {
|
|
38
|
+
...existing,
|
|
39
|
+
fieldSchema: schemas.fieldSchema || existing?.fieldSchema,
|
|
40
|
+
inputSchema: schemas.inputSchema || existing?.inputSchema,
|
|
41
|
+
};
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Parses unified schema children (Field components) into separate
|
|
48
|
+
* fieldSchema and inputSchema arrays.
|
|
49
|
+
*/
|
|
50
|
+
export const parseUnifiedSchema = (children) => {
|
|
51
|
+
const fieldSchema = [];
|
|
52
|
+
const inputSchema = [];
|
|
53
|
+
const mergeValidation = (isRequired, validate) => {
|
|
54
|
+
if (!isRequired)
|
|
55
|
+
return validate;
|
|
56
|
+
const requiredValidator = required();
|
|
57
|
+
if (!validate)
|
|
58
|
+
return requiredValidator;
|
|
59
|
+
if (Array.isArray(validate)) {
|
|
60
|
+
return validate.some((v) => v.isRequired) ? validate : [requiredValidator, ...validate];
|
|
61
|
+
}
|
|
62
|
+
return validate.isRequired ? validate : [requiredValidator, validate];
|
|
63
|
+
};
|
|
64
|
+
const walk = (nodes) => {
|
|
65
|
+
React.Children.forEach(nodes, (child) => {
|
|
66
|
+
if (!React.isValidElement(child))
|
|
67
|
+
return;
|
|
68
|
+
// Handle Fragments and FieldSchema by recursing into their children
|
|
69
|
+
if (child.type === Fragment || child.type === FieldSchema) {
|
|
70
|
+
walk(child.props.children);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Handle explicit InputSchema by only adding to inputSchema
|
|
74
|
+
if (child.type === InputSchema) {
|
|
75
|
+
React.Children.forEach(child.props.children, (inputChild) => {
|
|
76
|
+
if (React.isValidElement(inputChild)) {
|
|
77
|
+
inputSchema.push(inputChild);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// The field component itself goes into the field schema
|
|
83
|
+
fieldSchema.push(child);
|
|
84
|
+
// Extract input configuration
|
|
85
|
+
const { source, input, isRequired, description, constraintText, ...rest } = child.props;
|
|
86
|
+
if (input === false) {
|
|
87
|
+
return; // Explicitly excluded from inputs
|
|
88
|
+
}
|
|
89
|
+
if (React.isValidElement(input)) {
|
|
90
|
+
// Escape hatch: explicit input component provided
|
|
91
|
+
const validate = mergeValidation(isRequired, input.props.validate);
|
|
92
|
+
inputSchema.push(React.cloneElement(input, { ...rest, source, isRequired, validate, description, constraintText }));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Infer default input component
|
|
96
|
+
const InputComponent = getDefaultInputForField(child.type);
|
|
97
|
+
if (InputComponent) {
|
|
98
|
+
const inputProps = input || {};
|
|
99
|
+
const validate = mergeValidation(isRequired, inputProps.validate);
|
|
100
|
+
inputSchema.push(_jsx(InputComponent, { ...rest, ...inputProps, source: source, isRequired: isRequired, validate: validate, description: description, constraintText: constraintText }, source));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
walk(children);
|
|
105
|
+
return {
|
|
106
|
+
fieldSchema: fieldSchema.length > 0 ? fieldSchema : undefined,
|
|
107
|
+
inputSchema: inputSchema.length > 0 ? inputSchema : undefined
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
export const getGlobalSchemas = (resource) => globalSchemaRegistry[resource];
|
|
111
|
+
/**
|
|
112
|
+
* Registers default components to be used by ResourceSchema when not explicitly provided.
|
|
113
|
+
*/
|
|
114
|
+
export const registerDefaultResourceComponents = (components) => {
|
|
115
|
+
globalDefaultComponents = { ...globalDefaultComponents, ...components };
|
|
116
|
+
};
|
|
117
|
+
export const getDefaultResourceComponents = () => globalDefaultComponents;
|
|
118
|
+
export const SchemaRegistryProvider = ({ children }) => {
|
|
119
|
+
// We still use state to trigger re-renders when new schemas are registered dynamically
|
|
120
|
+
const [, setTick] = useState(0);
|
|
121
|
+
const registerSchemas = useCallback((resource, schemas) => {
|
|
122
|
+
const updated = registerGlobalSchemas(resource, schemas);
|
|
123
|
+
if (updated) {
|
|
124
|
+
setTick((t) => t + 1);
|
|
125
|
+
}
|
|
126
|
+
}, []);
|
|
127
|
+
const getSchemas = useCallback((resource) => globalSchemaRegistry[resource], []);
|
|
128
|
+
const value = useMemo(() => ({
|
|
129
|
+
registerSchemas,
|
|
130
|
+
getSchemas,
|
|
131
|
+
defaultComponents: globalDefaultComponents
|
|
132
|
+
}), [registerSchemas, getSchemas]);
|
|
133
|
+
return (_jsx(SchemaRegistryContext.Provider, { value: value, children: children }));
|
|
134
|
+
};
|
|
135
|
+
export const useSchemaRegistry = () => {
|
|
136
|
+
const context = useContext(SchemaRegistryContext);
|
|
137
|
+
if (!context) {
|
|
138
|
+
return {
|
|
139
|
+
registerSchemas: registerGlobalSchemas,
|
|
140
|
+
getSchemas: getGlobalSchemas,
|
|
141
|
+
defaultComponents: globalDefaultComponents,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return context;
|
|
145
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@strato-admin/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Strato Admin Core Framework",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"strato",
|
|
24
|
+
"admin",
|
|
25
|
+
"react-admin",
|
|
26
|
+
"cloudscape"
|
|
27
|
+
],
|
|
28
|
+
"author": "Vadim Gubergrits <vadim.gubergrits@gmail.com>",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/vgrits/strato-admin.git",
|
|
33
|
+
"directory": "packages/strato-core"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"react-intl": "^8.1.3",
|
|
37
|
+
"@strato-admin/ra-core": "0.1.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
41
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/react": "^19.0.0",
|
|
45
|
+
"@types/react-dom": "^19.0.0",
|
|
46
|
+
"react": "^19.0.0",
|
|
47
|
+
"react-dom": "^19.0.0",
|
|
48
|
+
"typescript": "^5.1.3"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc -p tsconfig.build.json",
|
|
52
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
File without changes
|
|
File without changes
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This file contains a subset of react-admin messages used by ra-core directly.
|
|
3
|
+
|
|
4
|
+
Some translations have issues in languages with gender and case. There's no easy
|
|
5
|
+
fix for this. We cannot interpolate the resource name in a message like "Delete
|
|
6
|
+
{name}" and expect it to be grammatically correct in all languages.
|
|
7
|
+
|
|
8
|
+
A workaround requires the translator to torture the phrase in order to place the
|
|
9
|
+
interpolated variable in nominative case. Message with translation issues are
|
|
10
|
+
marked with a comment starting with "Translation issue".
|
|
11
|
+
*/
|
|
12
|
+
import { defineMessage } from 'react-intl';
|
|
13
|
+
|
|
14
|
+
defineMessage({
|
|
15
|
+
id: 'ra.action.add',
|
|
16
|
+
defaultMessage: 'Add',
|
|
17
|
+
description: 'Label for the button to add a new record',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
defineMessage({
|
|
21
|
+
id: 'ra.action.cancel',
|
|
22
|
+
defaultMessage: 'Cancel',
|
|
23
|
+
description: 'Label for the button to cancel an action',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
defineMessage({
|
|
27
|
+
id: 'ra.action.clear_array_input',
|
|
28
|
+
defaultMessage: 'Clear the list',
|
|
29
|
+
description: 'Label for the button to clear an array input',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
defineMessage({
|
|
33
|
+
id: 'ra.action.close',
|
|
34
|
+
defaultMessage: 'Close',
|
|
35
|
+
description: 'Label for the button to close a dialog or panel',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
defineMessage({
|
|
39
|
+
id: 'ra.action.confirm',
|
|
40
|
+
defaultMessage: 'Confirm',
|
|
41
|
+
description: 'Label for the button to confirm an action',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
defineMessage({
|
|
45
|
+
id: 'ra.action.create',
|
|
46
|
+
defaultMessage: 'Create',
|
|
47
|
+
description: 'Label for the button to create a new record',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
defineMessage({
|
|
51
|
+
id: 'ra.action.delete',
|
|
52
|
+
defaultMessage: 'Delete',
|
|
53
|
+
description: 'Label for the button to delete one or more records',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
defineMessage({
|
|
57
|
+
id: 'ra.action.edit',
|
|
58
|
+
defaultMessage: 'Edit',
|
|
59
|
+
description: 'Label for the button to edit a record',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
defineMessage({
|
|
63
|
+
id: 'ra.action.move_down',
|
|
64
|
+
defaultMessage: 'Move down',
|
|
65
|
+
description: 'Label for the button to move an item down in a list',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
defineMessage({
|
|
69
|
+
id: 'ra.action.move_up',
|
|
70
|
+
defaultMessage: 'Move up',
|
|
71
|
+
description: 'Label for the button to move an item up in a list',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
defineMessage({
|
|
75
|
+
id: 'ra.action.refresh',
|
|
76
|
+
defaultMessage: 'Refresh',
|
|
77
|
+
description: 'Label for the button to refresh the current view',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
defineMessage({
|
|
81
|
+
id: 'ra.action.remove',
|
|
82
|
+
defaultMessage: 'Remove',
|
|
83
|
+
description: 'Label for the button to remove an item',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
defineMessage({
|
|
87
|
+
id: 'ra.action.save',
|
|
88
|
+
defaultMessage: 'Save',
|
|
89
|
+
description: 'Label for the button to save changes',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
defineMessage({
|
|
93
|
+
id: 'ra.action.undo',
|
|
94
|
+
defaultMessage: 'Undo',
|
|
95
|
+
description: 'Label for the button to undo the last action',
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
defineMessage({
|
|
99
|
+
id: 'ra.action.update',
|
|
100
|
+
defaultMessage: 'Update',
|
|
101
|
+
description: 'Label for the button to update a record',
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
defineMessage({
|
|
105
|
+
id: 'ra.auth.auth_check_error',
|
|
106
|
+
defaultMessage: 'Please login to continue',
|
|
107
|
+
description: 'Message shown when the user needs to login',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
defineMessage({
|
|
111
|
+
id: 'ra.boolean.true',
|
|
112
|
+
defaultMessage: 'Yes',
|
|
113
|
+
description: 'Label for the true boolean value',
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
defineMessage({
|
|
117
|
+
id: 'ra.boolean.false',
|
|
118
|
+
defaultMessage: 'No',
|
|
119
|
+
description: 'Label for the false boolean value',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
defineMessage({
|
|
123
|
+
id: 'ra.input.references.all_missing',
|
|
124
|
+
defaultMessage: 'Unable to find references data.',
|
|
125
|
+
description: 'Error message when all references are missing',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
defineMessage({
|
|
129
|
+
id: 'ra.input.references.many_missing',
|
|
130
|
+
defaultMessage: 'At least one of the associated references no longer appears to be available.',
|
|
131
|
+
description: 'Error message when many references are missing',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
defineMessage({
|
|
135
|
+
id: 'ra.input.references.single_missing',
|
|
136
|
+
defaultMessage: 'Associated reference no longer appears to be available.',
|
|
137
|
+
description: 'Error message when a single reference is missing',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
defineMessage({
|
|
141
|
+
id: 'ra.message.clear_array_input',
|
|
142
|
+
defaultMessage: 'Are you sure you want to clear the whole list?',
|
|
143
|
+
description: 'Confirmation message when clearing an array input',
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Translation issue: {name} gender must agree with "this" (e.g., ce/cette, этот/эту).
|
|
147
|
+
defineMessage({
|
|
148
|
+
id: 'ra.message.delete_content',
|
|
149
|
+
defaultMessage: 'Are you sure you want to delete this {name}?',
|
|
150
|
+
description: 'Confirmation message when deleting a record',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Translation issue: {name} might require the Accusative case (e.g., Delete "Usera").
|
|
154
|
+
defineMessage({
|
|
155
|
+
id: 'ra.message.delete_title',
|
|
156
|
+
defaultMessage: 'Delete {name} {recordRepresentation}',
|
|
157
|
+
description: 'Title for the delete confirmation dialog',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
defineMessage({
|
|
161
|
+
id: 'ra.message.invalid_form',
|
|
162
|
+
defaultMessage: 'The form is not valid. Please check for errors',
|
|
163
|
+
description: 'Error message shown when a form is invalid',
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
defineMessage({
|
|
167
|
+
id: 'ra.message.select_all_limit_reached',
|
|
168
|
+
defaultMessage: `
|
|
169
|
+
{max, plural,
|
|
170
|
+
one {There are too many elements to select them all. Only the first element was selected.}
|
|
171
|
+
other {There are too many elements to select them all. Only the first # elements were selected.}
|
|
172
|
+
}`,
|
|
173
|
+
description: 'Message shown when select all reaches its limit',
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
defineMessage({
|
|
177
|
+
id: 'ra.message.unsaved_changes',
|
|
178
|
+
defaultMessage: "Some of your changes weren't saved. Are you sure you want to ignore them?",
|
|
179
|
+
description: 'Confirmation message when leaving a page with unsaved changes',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Translation issue: "update {name}" may require Accusative case; "these" must agree with gender of "items".
|
|
183
|
+
defineMessage({
|
|
184
|
+
id: 'ra.message.update_content',
|
|
185
|
+
defaultMessage:
|
|
186
|
+
'{smart_count, plural, one {Are you sure you want to update {name} {recordRepresentation}?} other {Are you sure you want to update these # items?}}',
|
|
187
|
+
description: 'Confirmation message when updating one or more records',
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Translation issue: {name} might require the Accusative case (e.g., Update "Usera").
|
|
191
|
+
defineMessage({
|
|
192
|
+
id: 'ra.message.update_title',
|
|
193
|
+
defaultMessage: '{smart_count, plural, one {Update {name} {recordRepresentation}} other {Update # {name}}}',
|
|
194
|
+
description: 'Title for the update confirmation dialog',
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
defineMessage({
|
|
198
|
+
id: 'ra.navigation.next',
|
|
199
|
+
defaultMessage: 'Go to next page',
|
|
200
|
+
description: 'Label for the button to go to the next page',
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
defineMessage({
|
|
204
|
+
id: 'ra.navigation.page',
|
|
205
|
+
defaultMessage: 'Go to page {page}',
|
|
206
|
+
description: 'Label for the button to go to a specific page',
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
defineMessage({
|
|
210
|
+
id: 'ra.navigation.page_range_info',
|
|
211
|
+
defaultMessage: '{offsetBegin}-{offsetEnd} of {total}',
|
|
212
|
+
description: 'Message showing the current page range and total number of records',
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
defineMessage({
|
|
216
|
+
id: 'ra.navigation.previous',
|
|
217
|
+
defaultMessage: 'Go to previous page',
|
|
218
|
+
description: 'Label for the button to go to the previous page',
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
defineMessage({
|
|
222
|
+
id: 'ra.notification.created',
|
|
223
|
+
defaultMessage: 'Element created',
|
|
224
|
+
description: 'Notification shown when a record is successfully created',
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
defineMessage({
|
|
228
|
+
id: 'ra.notification.data_provider_error',
|
|
229
|
+
defaultMessage: 'dataProvider error. Check the console for details.',
|
|
230
|
+
description: 'Notification shown when a dataProvider error occurs',
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
defineMessage({
|
|
234
|
+
id: 'ra.notification.deleted',
|
|
235
|
+
defaultMessage: '{smart_count, plural, one {Element deleted} other {# elements deleted}}',
|
|
236
|
+
description: 'Notification shown when one or more records are successfully deleted',
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
defineMessage({
|
|
240
|
+
id: 'ra.notification.http_error',
|
|
241
|
+
defaultMessage: 'Server communication error',
|
|
242
|
+
description: 'Notification shown when an HTTP error occurs',
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
defineMessage({
|
|
246
|
+
id: 'ra.notification.item_doesnt_exist',
|
|
247
|
+
defaultMessage: 'Element does not exist',
|
|
248
|
+
description: 'Notification shown when a record does not exist',
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
defineMessage({
|
|
252
|
+
id: 'ra.notification.logged_out',
|
|
253
|
+
defaultMessage: 'Your session has ended, please reconnect.',
|
|
254
|
+
description: 'Notification shown when the user is logged out',
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
defineMessage({
|
|
258
|
+
id: 'ra.notification.not_authorized',
|
|
259
|
+
defaultMessage: "You're not authorized to access this resource.",
|
|
260
|
+
description: 'Notification shown when the user is not authorized',
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
defineMessage({
|
|
264
|
+
id: 'ra.notification.updated',
|
|
265
|
+
defaultMessage: '{smart_count, plural, one {Element updated} other {# elements updated}}',
|
|
266
|
+
description: 'Notification shown when one or more records are successfully updated',
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Translation issue: {name} might require the Accusative case (e.g., Create "Usera").
|
|
270
|
+
defineMessage({
|
|
271
|
+
id: 'ra.page.create',
|
|
272
|
+
defaultMessage: 'Create {name}',
|
|
273
|
+
description: 'Title for the record creation page',
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
defineMessage({
|
|
277
|
+
id: 'ra.page.edit',
|
|
278
|
+
defaultMessage: '{name} {recordRepresentation}',
|
|
279
|
+
description: 'Title for the record edition page',
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
defineMessage({
|
|
283
|
+
id: 'ra.page.list',
|
|
284
|
+
defaultMessage: '{name}',
|
|
285
|
+
description: 'Title for the record list page',
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
defineMessage({
|
|
289
|
+
id: 'ra.page.show',
|
|
290
|
+
defaultMessage: '{name} {recordRepresentation}',
|
|
291
|
+
description: 'Title for the record show page',
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
defineMessage({
|
|
295
|
+
id: 'ra.validation.email',
|
|
296
|
+
defaultMessage: 'Must be a valid email',
|
|
297
|
+
description: 'Validation error message for email inputs',
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
defineMessage({
|
|
301
|
+
id: 'ra.validation.maxLength',
|
|
302
|
+
defaultMessage: '{max, plural, one {Must be # character or less} other {Must be # characters or less}}',
|
|
303
|
+
description: 'Validation error message for maxLength',
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
defineMessage({
|
|
307
|
+
id: 'ra.validation.maxValue',
|
|
308
|
+
defaultMessage: '{max, plural, other {Must be # or less}}',
|
|
309
|
+
description: 'Validation error message for maxValue',
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
defineMessage({
|
|
313
|
+
id: 'ra.validation.minLength',
|
|
314
|
+
defaultMessage: '{min, plural, one {Must be # character at least} other {Must be # characters at least}}',
|
|
315
|
+
description: 'Validation error message for minLength',
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
defineMessage({
|
|
319
|
+
id: 'ra.validation.minValue',
|
|
320
|
+
defaultMessage: '{min, plural, other {Must be at least #}}',
|
|
321
|
+
description: 'Validation error message for minValue',
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
defineMessage({
|
|
325
|
+
id: 'ra.validation.number',
|
|
326
|
+
defaultMessage: 'Must be a number',
|
|
327
|
+
description: 'Validation error message for number inputs',
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
defineMessage({
|
|
331
|
+
id: 'ra.validation.oneOf',
|
|
332
|
+
defaultMessage: 'Must be one of: {options}',
|
|
333
|
+
description: 'Validation error message for oneOf',
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
defineMessage({
|
|
337
|
+
id: 'ra.validation.regex',
|
|
338
|
+
defaultMessage: 'Must match a specific format (regexp): {pattern}',
|
|
339
|
+
description: 'Validation error message for regex',
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
defineMessage({
|
|
343
|
+
id: 'ra.validation.required',
|
|
344
|
+
defaultMessage: 'Required',
|
|
345
|
+
description: 'Validation error message for required inputs',
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
defineMessage({
|
|
349
|
+
id: 'ra.validation.unique',
|
|
350
|
+
defaultMessage: 'Must be unique',
|
|
351
|
+
description: 'Validation error message for unique inputs',
|
|
352
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createContext, useContext, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context for the field schema.
|
|
5
|
+
* Stores an array of React elements (fields) defined in the FieldSchema.
|
|
6
|
+
*/
|
|
7
|
+
export const FieldSchemaContext = createContext<ReactNode[]>([]);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook to access the field schema elements.
|
|
11
|
+
*/
|
|
12
|
+
export const useFieldSchema = () => {
|
|
13
|
+
return useContext(FieldSchemaContext);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface FieldSchemaProps {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A marker component to define the fields of a resource.
|
|
22
|
+
* It doesn't render anything by itself, it's used by StratoResource to capture the schema.
|
|
23
|
+
*/
|
|
24
|
+
export const FieldSchema = (_props: FieldSchemaProps) => {
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createContext, useContext, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context for the input schema.
|
|
5
|
+
* Stores an array of React elements (inputs) defined in the InputSchema.
|
|
6
|
+
*/
|
|
7
|
+
export const InputSchemaContext = createContext<ReactNode[]>([]);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook to access the input schema elements.
|
|
11
|
+
*/
|
|
12
|
+
export const useInputSchema = () => {
|
|
13
|
+
return useContext(InputSchemaContext);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface InputSchemaProps {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A marker component to define the form inputs of a resource.
|
|
22
|
+
* It doesn't render anything by itself, it's used by StratoResource to capture the schema.
|
|
23
|
+
*/
|
|
24
|
+
export const InputSchema = (_props: InputSchemaProps) => {
|
|
25
|
+
return null;
|
|
26
|
+
};
|