@djangocfg/ui-nextjs 1.4.45
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 +152 -0
- package/package.json +110 -0
- package/src/animations/AnimatedBackground.tsx +645 -0
- package/src/animations/index.ts +2 -0
- package/src/blocks/ArticleCard.tsx +94 -0
- package/src/blocks/ArticleList.tsx +95 -0
- package/src/blocks/CTASection.tsx +136 -0
- package/src/blocks/FeatureSection.tsx +104 -0
- package/src/blocks/Hero.tsx +102 -0
- package/src/blocks/NewsletterSection.tsx +119 -0
- package/src/blocks/StatsSection.tsx +103 -0
- package/src/blocks/SuperHero.tsx +328 -0
- package/src/blocks/TestimonialSection.tsx +122 -0
- package/src/blocks/index.ts +9 -0
- package/src/components/README.md +2018 -0
- package/src/components/breadcrumb-navigation.tsx +127 -0
- package/src/components/breadcrumb.tsx +132 -0
- package/src/components/button-download.tsx +275 -0
- package/src/components/dropdown-menu.tsx +219 -0
- package/src/components/index.ts +86 -0
- package/src/components/markdown/MarkdownMessage.tsx +338 -0
- package/src/components/markdown/index.ts +5 -0
- package/src/components/menubar.tsx +274 -0
- package/src/components/multi-select-pro/async.tsx +608 -0
- package/src/components/multi-select-pro/helpers.tsx +84 -0
- package/src/components/multi-select-pro/index.tsx +622 -0
- package/src/components/navigation-menu.tsx +153 -0
- package/src/components/pagination-static.tsx +348 -0
- package/src/components/pagination.tsx +138 -0
- package/src/components/phone-input.tsx +276 -0
- package/src/components/sidebar.tsx +866 -0
- package/src/components/sonner.tsx +31 -0
- package/src/components/ssr-pagination.tsx +237 -0
- package/src/hooks/index.ts +19 -0
- package/src/hooks/useCfgRouter.ts +153 -0
- package/src/hooks/useLocalStorage.ts +221 -0
- package/src/hooks/useQueryParams.ts +73 -0
- package/src/hooks/useSessionStorage.ts +188 -0
- package/src/hooks/useTheme.ts +57 -0
- package/src/index.ts +24 -0
- package/src/lib/index.ts +2 -0
- package/src/styles/index.css +2 -0
- package/src/theme/ForceTheme.tsx +115 -0
- package/src/theme/ThemeProvider.tsx +82 -0
- package/src/theme/ThemeToggle.tsx +52 -0
- package/src/theme/index.ts +3 -0
- package/src/tools/JsonForm/JsonSchemaForm.tsx +199 -0
- package/src/tools/JsonForm/examples/BotConfigExample.tsx +245 -0
- package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +157 -0
- package/src/tools/JsonForm/index.ts +46 -0
- package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +46 -0
- package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +73 -0
- package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +106 -0
- package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +34 -0
- package/src/tools/JsonForm/templates/FieldTemplate.tsx +61 -0
- package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +43 -0
- package/src/tools/JsonForm/templates/index.ts +12 -0
- package/src/tools/JsonForm/types.ts +83 -0
- package/src/tools/JsonForm/utils.ts +212 -0
- package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +36 -0
- package/src/tools/JsonForm/widgets/NumberWidget.tsx +88 -0
- package/src/tools/JsonForm/widgets/SelectWidget.tsx +100 -0
- package/src/tools/JsonForm/widgets/SwitchWidget.tsx +34 -0
- package/src/tools/JsonForm/widgets/TextWidget.tsx +95 -0
- package/src/tools/JsonForm/widgets/index.ts +12 -0
- package/src/tools/JsonTree/index.tsx +252 -0
- package/src/tools/LottiePlayer/LottiePlayer.client.tsx +212 -0
- package/src/tools/LottiePlayer/index.tsx +54 -0
- package/src/tools/LottiePlayer/types.ts +108 -0
- package/src/tools/LottiePlayer/useLottie.ts +163 -0
- package/src/tools/Mermaid/Mermaid.client.tsx +341 -0
- package/src/tools/Mermaid/index.tsx +40 -0
- package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +144 -0
- package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +255 -0
- package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +123 -0
- package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +98 -0
- package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +164 -0
- package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +253 -0
- package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +169 -0
- package/src/tools/OpenapiViewer/components/VersionSelector.tsx +64 -0
- package/src/tools/OpenapiViewer/components/index.ts +14 -0
- package/src/tools/OpenapiViewer/constants.ts +39 -0
- package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +338 -0
- package/src/tools/OpenapiViewer/hooks/index.ts +8 -0
- package/src/tools/OpenapiViewer/hooks/useMobile.ts +10 -0
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +203 -0
- package/src/tools/OpenapiViewer/index.tsx +36 -0
- package/src/tools/OpenapiViewer/types.ts +152 -0
- package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +149 -0
- package/src/tools/OpenapiViewer/utils/formatters.ts +71 -0
- package/src/tools/OpenapiViewer/utils/index.ts +9 -0
- package/src/tools/OpenapiViewer/utils/versionManager.ts +161 -0
- package/src/tools/PrettyCode/PrettyCode.client.tsx +217 -0
- package/src/tools/PrettyCode/index.tsx +43 -0
- package/src/tools/VideoPlayer/README.md +239 -0
- package/src/tools/VideoPlayer/VideoControls.tsx +138 -0
- package/src/tools/VideoPlayer/VideoPlayer.tsx +230 -0
- package/src/tools/VideoPlayer/index.ts +9 -0
- package/src/tools/VideoPlayer/types.ts +62 -0
- package/src/tools/index.ts +43 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useMemo, useCallback } from 'react';
|
|
4
|
+
import Form from '@rjsf/core';
|
|
5
|
+
import validator from '@rjsf/validator-ajv8';
|
|
6
|
+
import { RegistryWidgetsType } from '@rjsf/utils';
|
|
7
|
+
import { Button, Alert, AlertDescription } from '@djangocfg/ui-core/components';
|
|
8
|
+
import { AlertCircle } from 'lucide-react';
|
|
9
|
+
import consola from 'consola';
|
|
10
|
+
|
|
11
|
+
import { JsonSchemaFormProps } from './types';
|
|
12
|
+
import {
|
|
13
|
+
TextWidget,
|
|
14
|
+
NumberWidget,
|
|
15
|
+
CheckboxWidget,
|
|
16
|
+
SelectWidget,
|
|
17
|
+
SwitchWidget,
|
|
18
|
+
} from './widgets';
|
|
19
|
+
import {
|
|
20
|
+
FieldTemplate,
|
|
21
|
+
ObjectFieldTemplate,
|
|
22
|
+
ArrayFieldTemplate,
|
|
23
|
+
ArrayFieldItemTemplate,
|
|
24
|
+
ErrorListTemplate,
|
|
25
|
+
BaseInputTemplate,
|
|
26
|
+
} from './templates';
|
|
27
|
+
import { validateSchema, normalizeFormData } from './utils';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* JSON Schema Form Component
|
|
31
|
+
*
|
|
32
|
+
* A fully-featured form generator that creates forms from JSON Schema.
|
|
33
|
+
* Built on top of react-jsonschema-form with custom widgets and templates
|
|
34
|
+
* using @djangocfg/ui components.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* const schema = {
|
|
39
|
+
* type: 'object',
|
|
40
|
+
* required: ['name'],
|
|
41
|
+
* properties: {
|
|
42
|
+
* name: { type: 'string', title: 'Name' },
|
|
43
|
+
* age: { type: 'number', title: 'Age' },
|
|
44
|
+
* active: { type: 'boolean', title: 'Active' }
|
|
45
|
+
* }
|
|
46
|
+
* };
|
|
47
|
+
*
|
|
48
|
+
* <JsonSchemaForm
|
|
49
|
+
* schema={schema}
|
|
50
|
+
* onSubmit={(data) => console.log(data.formData)}
|
|
51
|
+
* />
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function JsonSchemaForm<T = any>(props: JsonSchemaFormProps<T>) {
|
|
55
|
+
const {
|
|
56
|
+
schema,
|
|
57
|
+
uiSchema,
|
|
58
|
+
formData,
|
|
59
|
+
onSubmit,
|
|
60
|
+
onChange,
|
|
61
|
+
onError,
|
|
62
|
+
showErrorList = 'top',
|
|
63
|
+
liveValidate = false,
|
|
64
|
+
disabled = false,
|
|
65
|
+
readonly = false,
|
|
66
|
+
className,
|
|
67
|
+
showSubmitButton = true,
|
|
68
|
+
submitButtonText = 'Submit',
|
|
69
|
+
...restProps
|
|
70
|
+
} = props;
|
|
71
|
+
|
|
72
|
+
// Validate and normalize schema before render
|
|
73
|
+
const validatedSchema = useMemo(() => {
|
|
74
|
+
if (process.env.NODE_ENV === 'development') {
|
|
75
|
+
consola.info('[JsonSchemaForm] Validating schema...', schema);
|
|
76
|
+
}
|
|
77
|
+
const result = validateSchema(schema);
|
|
78
|
+
if (!result && process.env.NODE_ENV === 'development') {
|
|
79
|
+
consola.error('[JsonSchemaForm] Schema validation failed');
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}, [schema]);
|
|
83
|
+
|
|
84
|
+
// Normalize form data before render
|
|
85
|
+
const normalizedFormData = useMemo(() => {
|
|
86
|
+
if (!validatedSchema) {
|
|
87
|
+
if (process.env.NODE_ENV === 'development') {
|
|
88
|
+
consola.warn('[JsonSchemaForm] Cannot normalize formData - invalid schema');
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (process.env.NODE_ENV === 'development') {
|
|
93
|
+
consola.info('[JsonSchemaForm] Normalizing formData...', formData);
|
|
94
|
+
}
|
|
95
|
+
const normalized = normalizeFormData<T>(formData, validatedSchema);
|
|
96
|
+
if (process.env.NODE_ENV === 'development') {
|
|
97
|
+
consola.info('[JsonSchemaForm] Normalized formData:', normalized);
|
|
98
|
+
}
|
|
99
|
+
return normalized;
|
|
100
|
+
}, [formData, validatedSchema]);
|
|
101
|
+
|
|
102
|
+
// Memoize widgets mapping to prevent recreation on every render
|
|
103
|
+
// IMPORTANT: Widget keys must match RJSF's expected names:
|
|
104
|
+
// - For type: string -> uses 'TextWidget' or 'text'
|
|
105
|
+
// - For type: number/integer -> uses 'updown' or 'range'
|
|
106
|
+
// - For type: boolean -> uses 'checkbox' or 'select'
|
|
107
|
+
// - For enum fields -> uses 'SelectWidget' or 'select'
|
|
108
|
+
const widgets: RegistryWidgetsType = useMemo(() => ({
|
|
109
|
+
// Standard widget names (PascalCase) - used by RJSF internally
|
|
110
|
+
TextWidget,
|
|
111
|
+
NumberWidget,
|
|
112
|
+
CheckboxWidget,
|
|
113
|
+
SelectWidget,
|
|
114
|
+
SwitchWidget,
|
|
115
|
+
// Lowercase aliases - for uiSchema 'ui:widget' references
|
|
116
|
+
text: TextWidget,
|
|
117
|
+
number: NumberWidget,
|
|
118
|
+
checkbox: CheckboxWidget,
|
|
119
|
+
select: SelectWidget,
|
|
120
|
+
switch: SwitchWidget,
|
|
121
|
+
}), []);
|
|
122
|
+
|
|
123
|
+
// Memoize templates to prevent recreation on every render
|
|
124
|
+
const templates = useMemo(() => ({
|
|
125
|
+
FieldTemplate,
|
|
126
|
+
ObjectFieldTemplate,
|
|
127
|
+
ArrayFieldTemplate,
|
|
128
|
+
ArrayFieldItemTemplate,
|
|
129
|
+
ErrorListTemplate,
|
|
130
|
+
BaseInputTemplate,
|
|
131
|
+
}), []);
|
|
132
|
+
|
|
133
|
+
// Memoize callbacks
|
|
134
|
+
const handleSubmit = useCallback((data: any) => {
|
|
135
|
+
if (onSubmit) {
|
|
136
|
+
// Ensure clean data on submit
|
|
137
|
+
const cleanData = {
|
|
138
|
+
...data,
|
|
139
|
+
formData: normalizeFormData(data.formData, validatedSchema!),
|
|
140
|
+
};
|
|
141
|
+
onSubmit(cleanData);
|
|
142
|
+
}
|
|
143
|
+
}, [onSubmit, validatedSchema]);
|
|
144
|
+
|
|
145
|
+
const handleChange = useCallback((data: any) => {
|
|
146
|
+
if (onChange) {
|
|
147
|
+
onChange(data);
|
|
148
|
+
}
|
|
149
|
+
}, [onChange]);
|
|
150
|
+
|
|
151
|
+
const handleError = useCallback((errors: any) => {
|
|
152
|
+
if (onError) {
|
|
153
|
+
onError(errors);
|
|
154
|
+
}
|
|
155
|
+
}, [onError]);
|
|
156
|
+
|
|
157
|
+
// Early return if schema is invalid
|
|
158
|
+
if (!validatedSchema) {
|
|
159
|
+
return (
|
|
160
|
+
<div className={className}>
|
|
161
|
+
<Alert variant="destructive">
|
|
162
|
+
<AlertCircle className="h-4 w-4" />
|
|
163
|
+
<AlertDescription>
|
|
164
|
+
Invalid schema provided. Please check the schema format.
|
|
165
|
+
</AlertDescription>
|
|
166
|
+
</Alert>
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div className={className}>
|
|
173
|
+
<Form
|
|
174
|
+
schema={validatedSchema}
|
|
175
|
+
uiSchema={uiSchema}
|
|
176
|
+
formData={normalizedFormData}
|
|
177
|
+
validator={validator}
|
|
178
|
+
widgets={widgets}
|
|
179
|
+
templates={templates}
|
|
180
|
+
onSubmit={handleSubmit}
|
|
181
|
+
onChange={handleChange}
|
|
182
|
+
onError={handleError}
|
|
183
|
+
showErrorList={showErrorList}
|
|
184
|
+
liveValidate={liveValidate}
|
|
185
|
+
disabled={disabled}
|
|
186
|
+
readonly={readonly}
|
|
187
|
+
{...restProps}
|
|
188
|
+
>
|
|
189
|
+
{showSubmitButton && (
|
|
190
|
+
<div className="mt-6 flex gap-2">
|
|
191
|
+
<Button type="submit" disabled={disabled}>
|
|
192
|
+
{submitButtonText}
|
|
193
|
+
</Button>
|
|
194
|
+
</div>
|
|
195
|
+
)}
|
|
196
|
+
</Form>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { JsonSchemaForm } from '../JsonSchemaForm';
|
|
5
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@djangocfg/ui-core/components';
|
|
6
|
+
import { RJSFSchema, UiSchema } from '@rjsf/utils';
|
|
7
|
+
import consola from 'consola';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Example JSON Schema for Bot Configuration
|
|
11
|
+
*/
|
|
12
|
+
const botConfigSchema: RJSFSchema = {
|
|
13
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
14
|
+
title: 'Bot Configuration',
|
|
15
|
+
type: 'object',
|
|
16
|
+
required: ['name', 'exchange', 'bot_type'],
|
|
17
|
+
properties: {
|
|
18
|
+
name: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
title: 'Bot Name',
|
|
21
|
+
description: 'A unique name for your trading bot',
|
|
22
|
+
minLength: 3,
|
|
23
|
+
maxLength: 50,
|
|
24
|
+
},
|
|
25
|
+
active: {
|
|
26
|
+
type: 'boolean',
|
|
27
|
+
title: 'Active',
|
|
28
|
+
description: 'Enable or disable the bot',
|
|
29
|
+
default: true,
|
|
30
|
+
},
|
|
31
|
+
enabled: {
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
title: 'Enabled',
|
|
34
|
+
description: 'Whether the bot is enabled for trading',
|
|
35
|
+
default: false,
|
|
36
|
+
},
|
|
37
|
+
exchange: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
title: 'Exchange',
|
|
40
|
+
description: 'Select the trading exchange',
|
|
41
|
+
enum: ['binance', 'bybit', 'okx', 'kucoin'],
|
|
42
|
+
},
|
|
43
|
+
bot_type: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
title: 'Bot Type',
|
|
46
|
+
description: 'Type of trading bot',
|
|
47
|
+
enum: ['spot', 'futures', 'margin'],
|
|
48
|
+
},
|
|
49
|
+
settings: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
title: 'Bot Settings',
|
|
52
|
+
properties: {
|
|
53
|
+
max_trades: {
|
|
54
|
+
type: 'integer',
|
|
55
|
+
title: 'Maximum Trades',
|
|
56
|
+
description: 'Maximum number of concurrent trades',
|
|
57
|
+
minimum: 1,
|
|
58
|
+
maximum: 100,
|
|
59
|
+
default: 3,
|
|
60
|
+
},
|
|
61
|
+
trade_amount: {
|
|
62
|
+
type: 'number',
|
|
63
|
+
title: 'Trade Amount (USD)',
|
|
64
|
+
description: 'Amount to invest per trade',
|
|
65
|
+
minimum: 10,
|
|
66
|
+
maximum: 10000,
|
|
67
|
+
default: 100,
|
|
68
|
+
},
|
|
69
|
+
stop_loss: {
|
|
70
|
+
type: 'number',
|
|
71
|
+
title: 'Stop Loss (%)',
|
|
72
|
+
description: 'Stop loss percentage',
|
|
73
|
+
minimum: 0.1,
|
|
74
|
+
maximum: 50,
|
|
75
|
+
default: 5,
|
|
76
|
+
},
|
|
77
|
+
take_profit: {
|
|
78
|
+
type: 'number',
|
|
79
|
+
title: 'Take Profit (%)',
|
|
80
|
+
description: 'Take profit percentage',
|
|
81
|
+
minimum: 0.1,
|
|
82
|
+
maximum: 100,
|
|
83
|
+
default: 10,
|
|
84
|
+
},
|
|
85
|
+
strategy: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
title: 'Trading Strategy',
|
|
88
|
+
enum: ['scalping', 'swing', 'arbitrage', 'grid'],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
api_credentials: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
title: 'API Credentials',
|
|
95
|
+
required: ['api_key', 'api_secret'],
|
|
96
|
+
properties: {
|
|
97
|
+
api_key: {
|
|
98
|
+
type: 'string',
|
|
99
|
+
title: 'API Key',
|
|
100
|
+
description: 'Your exchange API key',
|
|
101
|
+
},
|
|
102
|
+
api_secret: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
title: 'API Secret',
|
|
105
|
+
description: 'Your exchange API secret',
|
|
106
|
+
},
|
|
107
|
+
testnet: {
|
|
108
|
+
type: 'boolean',
|
|
109
|
+
title: 'Use Testnet',
|
|
110
|
+
description: 'Use testnet environment for testing',
|
|
111
|
+
default: true,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
notifications: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
title: 'Notifications',
|
|
118
|
+
properties: {
|
|
119
|
+
email: {
|
|
120
|
+
type: 'boolean',
|
|
121
|
+
title: 'Email Notifications',
|
|
122
|
+
default: true,
|
|
123
|
+
},
|
|
124
|
+
telegram: {
|
|
125
|
+
type: 'boolean',
|
|
126
|
+
title: 'Telegram Notifications',
|
|
127
|
+
default: false,
|
|
128
|
+
},
|
|
129
|
+
webhook: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
title: 'Webhook URL',
|
|
132
|
+
format: 'uri',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* UI Schema for customizing form appearance
|
|
141
|
+
*/
|
|
142
|
+
const uiSchema: UiSchema = {
|
|
143
|
+
'ui:submitButtonOptions': {
|
|
144
|
+
submitText: 'Save Bot Configuration',
|
|
145
|
+
},
|
|
146
|
+
name: {
|
|
147
|
+
'ui:placeholder': 'My Trading Bot',
|
|
148
|
+
},
|
|
149
|
+
active: {
|
|
150
|
+
'ui:widget': 'SwitchWidget',
|
|
151
|
+
},
|
|
152
|
+
enabled: {
|
|
153
|
+
'ui:widget': 'SwitchWidget',
|
|
154
|
+
},
|
|
155
|
+
exchange: {
|
|
156
|
+
'ui:placeholder': 'Select exchange...',
|
|
157
|
+
},
|
|
158
|
+
bot_type: {
|
|
159
|
+
'ui:placeholder': 'Select bot type...',
|
|
160
|
+
},
|
|
161
|
+
settings: {
|
|
162
|
+
'ui:className': 'grid grid-cols-2 gap-4',
|
|
163
|
+
strategy: {
|
|
164
|
+
'ui:placeholder': 'Select strategy...',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
api_credentials: {
|
|
168
|
+
api_secret: {
|
|
169
|
+
'ui:widget': 'password',
|
|
170
|
+
},
|
|
171
|
+
testnet: {
|
|
172
|
+
'ui:widget': 'SwitchWidget',
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
notifications: {
|
|
176
|
+
email: {
|
|
177
|
+
'ui:widget': 'SwitchWidget',
|
|
178
|
+
},
|
|
179
|
+
telegram: {
|
|
180
|
+
'ui:widget': 'SwitchWidget',
|
|
181
|
+
},
|
|
182
|
+
webhook: {
|
|
183
|
+
'ui:placeholder': 'https://example.com/webhook',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Example component demonstrating JsonSchemaForm usage
|
|
190
|
+
*/
|
|
191
|
+
export function BotConfigExample() {
|
|
192
|
+
const [formData, setFormData] = useState<any>();
|
|
193
|
+
const [submittedData, setSubmittedData] = useState<any>(null);
|
|
194
|
+
|
|
195
|
+
const handleSubmit = (data: any) => {
|
|
196
|
+
consola.success('Form submitted:', data.formData);
|
|
197
|
+
setSubmittedData(data.formData);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const handleChange = (data: any) => {
|
|
201
|
+
setFormData(data.formData);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div className="container mx-auto p-6 max-w-4xl">
|
|
206
|
+
<div className="space-y-6">
|
|
207
|
+
<Card>
|
|
208
|
+
<CardHeader>
|
|
209
|
+
<CardTitle>Bot Configuration Form</CardTitle>
|
|
210
|
+
<CardDescription>
|
|
211
|
+
Example of JSON Schema Form with Bot Configuration
|
|
212
|
+
</CardDescription>
|
|
213
|
+
</CardHeader>
|
|
214
|
+
<CardContent>
|
|
215
|
+
<JsonSchemaForm
|
|
216
|
+
schema={botConfigSchema}
|
|
217
|
+
uiSchema={uiSchema}
|
|
218
|
+
formData={formData}
|
|
219
|
+
onSubmit={handleSubmit}
|
|
220
|
+
onChange={handleChange}
|
|
221
|
+
liveValidate={false}
|
|
222
|
+
showErrorList="top"
|
|
223
|
+
/>
|
|
224
|
+
</CardContent>
|
|
225
|
+
</Card>
|
|
226
|
+
|
|
227
|
+
{submittedData && (
|
|
228
|
+
<Card>
|
|
229
|
+
<CardHeader>
|
|
230
|
+
<CardTitle>Submitted Data</CardTitle>
|
|
231
|
+
<CardDescription>
|
|
232
|
+
The data that was submitted from the form
|
|
233
|
+
</CardDescription>
|
|
234
|
+
</CardHeader>
|
|
235
|
+
<CardContent>
|
|
236
|
+
<pre className="p-4 bg-muted rounded-md overflow-auto text-sm">
|
|
237
|
+
{JSON.stringify(submittedData, null, 2)}
|
|
238
|
+
</pre>
|
|
239
|
+
</CardContent>
|
|
240
|
+
</Card>
|
|
241
|
+
)}
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { JsonSchemaForm } from '../JsonSchemaForm';
|
|
5
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@djangocfg/ui-core/components';
|
|
6
|
+
import { RJSFSchema } from '@rjsf/utils';
|
|
7
|
+
import consola from 'consola';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Real Bot Config Schema from API
|
|
11
|
+
* This is the actual schema returned by the backend
|
|
12
|
+
*/
|
|
13
|
+
const realBotConfigSchema: RJSFSchema = {
|
|
14
|
+
type: 'object',
|
|
15
|
+
title: 'BotConfig',
|
|
16
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
17
|
+
required: ['name', 'exchange'],
|
|
18
|
+
properties: {
|
|
19
|
+
name: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'Bot name',
|
|
22
|
+
},
|
|
23
|
+
active: {
|
|
24
|
+
type: 'boolean',
|
|
25
|
+
description: 'Bot active',
|
|
26
|
+
},
|
|
27
|
+
enabled: {
|
|
28
|
+
type: 'boolean',
|
|
29
|
+
description: 'Bot enabled',
|
|
30
|
+
},
|
|
31
|
+
exchange: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'Exchange name (binance, bybit, etc)',
|
|
34
|
+
},
|
|
35
|
+
direction: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
description: 'Trading direction (long, short, both)',
|
|
38
|
+
},
|
|
39
|
+
amount_usdt: {
|
|
40
|
+
type: 'number',
|
|
41
|
+
description: 'Amount in USDT',
|
|
42
|
+
},
|
|
43
|
+
market_type: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Market type (spot, futures, swap)',
|
|
46
|
+
},
|
|
47
|
+
signal_type: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'Signal type (listing, technical, etc)',
|
|
50
|
+
},
|
|
51
|
+
allowed_quotes: {
|
|
52
|
+
type: 'array',
|
|
53
|
+
items: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
},
|
|
56
|
+
description: 'Allowed quote currencies',
|
|
57
|
+
},
|
|
58
|
+
allowed_sources: {
|
|
59
|
+
type: 'array',
|
|
60
|
+
items: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
},
|
|
63
|
+
description: 'Allowed signal sources',
|
|
64
|
+
},
|
|
65
|
+
force_market_close_timer: {
|
|
66
|
+
type: 'integer',
|
|
67
|
+
description: 'Force close timer in seconds',
|
|
68
|
+
},
|
|
69
|
+
force_market_close_enabled: {
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
description: 'Enable forced market close',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Real settings data from bot
|
|
78
|
+
*/
|
|
79
|
+
const realSettings = {
|
|
80
|
+
version: '1.0.0',
|
|
81
|
+
hostname: 'botserver',
|
|
82
|
+
supported_exchanges: ['binance'],
|
|
83
|
+
supported_strategies: ['default'],
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Example component with real bot config schema
|
|
88
|
+
*/
|
|
89
|
+
export function RealBotConfigExample() {
|
|
90
|
+
const [formData, setFormData] = useState<any>(realSettings);
|
|
91
|
+
const [submittedData, setSubmittedData] = useState<any>(null);
|
|
92
|
+
|
|
93
|
+
const handleSubmit = (data: any) => {
|
|
94
|
+
consola.success('Form submitted:', data.formData);
|
|
95
|
+
setSubmittedData(data.formData);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const handleChange = (data: any) => {
|
|
99
|
+
consola.info('Form changed:', data.formData);
|
|
100
|
+
setFormData(data.formData);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="container mx-auto p-6 max-w-4xl">
|
|
105
|
+
<div className="space-y-6">
|
|
106
|
+
<Card>
|
|
107
|
+
<CardHeader>
|
|
108
|
+
<CardTitle>Real Bot Configuration Form</CardTitle>
|
|
109
|
+
<CardDescription>
|
|
110
|
+
Using actual schema from API response
|
|
111
|
+
</CardDescription>
|
|
112
|
+
</CardHeader>
|
|
113
|
+
<CardContent>
|
|
114
|
+
<JsonSchemaForm
|
|
115
|
+
schema={realBotConfigSchema}
|
|
116
|
+
formData={formData}
|
|
117
|
+
onSubmit={handleSubmit}
|
|
118
|
+
onChange={handleChange}
|
|
119
|
+
liveValidate={false}
|
|
120
|
+
showErrorList="top"
|
|
121
|
+
/>
|
|
122
|
+
</CardContent>
|
|
123
|
+
</Card>
|
|
124
|
+
|
|
125
|
+
{submittedData && (
|
|
126
|
+
<Card>
|
|
127
|
+
<CardHeader>
|
|
128
|
+
<CardTitle>Submitted Data</CardTitle>
|
|
129
|
+
<CardDescription>
|
|
130
|
+
The data that was submitted from the form
|
|
131
|
+
</CardDescription>
|
|
132
|
+
</CardHeader>
|
|
133
|
+
<CardContent>
|
|
134
|
+
<pre className="p-4 bg-muted rounded-md overflow-auto text-sm">
|
|
135
|
+
{JSON.stringify(submittedData, null, 2)}
|
|
136
|
+
</pre>
|
|
137
|
+
</CardContent>
|
|
138
|
+
</Card>
|
|
139
|
+
)}
|
|
140
|
+
|
|
141
|
+
<Card>
|
|
142
|
+
<CardHeader>
|
|
143
|
+
<CardTitle>Current Form Data</CardTitle>
|
|
144
|
+
<CardDescription>
|
|
145
|
+
Real-time form data (onChange)
|
|
146
|
+
</CardDescription>
|
|
147
|
+
</CardHeader>
|
|
148
|
+
<CardContent>
|
|
149
|
+
<pre className="p-4 bg-muted rounded-md overflow-auto text-sm">
|
|
150
|
+
{JSON.stringify(formData, null, 2)}
|
|
151
|
+
</pre>
|
|
152
|
+
</CardContent>
|
|
153
|
+
</Card>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* JSON Schema Form Module
|
|
5
|
+
*
|
|
6
|
+
* A complete solution for generating forms from JSON Schema 7
|
|
7
|
+
* Built with React JSON Schema Form (rjsf), Radix UI, and Tailwind CSS
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Automatic form generation from JSON Schema
|
|
11
|
+
* - Custom widgets using @djangocfg/ui components
|
|
12
|
+
* - Validation with ajv8
|
|
13
|
+
* - TypeScript support
|
|
14
|
+
* - Responsive design
|
|
15
|
+
* - Dark mode support
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { JsonSchemaForm } from '@/components/JsonForm';
|
|
20
|
+
*
|
|
21
|
+
* const schema = {
|
|
22
|
+
* type: 'object',
|
|
23
|
+
* properties: {
|
|
24
|
+
* name: { type: 'string' },
|
|
25
|
+
* age: { type: 'number' }
|
|
26
|
+
* }
|
|
27
|
+
* };
|
|
28
|
+
*
|
|
29
|
+
* <JsonSchemaForm
|
|
30
|
+
* schema={schema}
|
|
31
|
+
* onSubmit={(data) => console.log(data)}
|
|
32
|
+
* />
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export { JsonSchemaForm } from './JsonSchemaForm';
|
|
37
|
+
export type { JsonSchemaFormProps } from './types';
|
|
38
|
+
|
|
39
|
+
// Export widgets for custom usage
|
|
40
|
+
export * from './widgets';
|
|
41
|
+
|
|
42
|
+
// Export templates for custom usage
|
|
43
|
+
export * from './templates';
|
|
44
|
+
|
|
45
|
+
// Export utilities for advanced usage
|
|
46
|
+
export * from './utils';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { ArrayFieldItemTemplateProps, getTemplate, getUiOptions } from '@rjsf/utils';
|
|
5
|
+
import { cn } from '@djangocfg/ui-core/lib';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Array field item template for JSON Schema Form
|
|
9
|
+
* Renders individual array items with proper styling and action buttons
|
|
10
|
+
*
|
|
11
|
+
* In RJSF v6, this template is responsible for rendering each item in an array,
|
|
12
|
+
* including the item content (children) and the action buttons (remove, move up/down, copy).
|
|
13
|
+
*/
|
|
14
|
+
export function ArrayFieldItemTemplate(props: ArrayFieldItemTemplateProps) {
|
|
15
|
+
const {
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
buttonsProps,
|
|
19
|
+
hasToolbar,
|
|
20
|
+
registry,
|
|
21
|
+
uiSchema,
|
|
22
|
+
} = props;
|
|
23
|
+
|
|
24
|
+
const uiOptions = getUiOptions(uiSchema);
|
|
25
|
+
const ArrayFieldItemButtonsTemplate = getTemplate(
|
|
26
|
+
'ArrayFieldItemButtonsTemplate',
|
|
27
|
+
registry,
|
|
28
|
+
uiOptions,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className={cn(
|
|
34
|
+
'flex gap-2 items-start p-4 rounded-md border bg-card',
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
>
|
|
38
|
+
<div className="flex-1">{children}</div>
|
|
39
|
+
{hasToolbar && (
|
|
40
|
+
<div className="flex items-center gap-1">
|
|
41
|
+
<ArrayFieldItemButtonsTemplate {...buttonsProps} />
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|