@qwickapps/react-framework 1.3.5 → 1.4.1
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/README.md +1691 -2
- package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
- package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +7 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/Html.d.ts +28 -18
- package/dist/components/Html.d.ts.map +1 -1
- package/dist/components/Logo.d.ts +12 -35
- package/dist/components/Logo.d.ts.map +1 -1
- package/dist/components/Markdown.d.ts +18 -13
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/QwickApp.d.ts +16 -3
- package/dist/components/QwickApp.d.ts.map +1 -1
- package/dist/components/QwickIcon.d.ts +23 -0
- package/dist/components/QwickIcon.d.ts.map +1 -0
- package/dist/components/SafeSpan.d.ts +12 -5
- package/dist/components/SafeSpan.d.ts.map +1 -1
- package/dist/components/Scaffold.d.ts.map +1 -1
- package/dist/components/base/ModelView.d.ts +101 -0
- package/dist/components/base/ModelView.d.ts.map +1 -0
- package/dist/components/base/index.d.ts +11 -0
- package/dist/components/base/index.d.ts.map +1 -0
- package/dist/components/blocks/Article.d.ts +12 -2
- package/dist/components/blocks/Article.d.ts.map +1 -1
- package/dist/components/blocks/Code.d.ts +13 -2
- package/dist/components/blocks/Code.d.ts.map +1 -1
- package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
- package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
- package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
- package/dist/components/blocks/Footer.d.ts.map +1 -1
- package/dist/components/blocks/HeroBlock.d.ts +27 -13
- package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
- package/dist/components/blocks/Image.d.ts +41 -0
- package/dist/components/blocks/Image.d.ts.map +1 -0
- package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
- package/dist/components/blocks/Section.d.ts +16 -2
- package/dist/components/blocks/Section.d.ts.map +1 -1
- package/dist/components/blocks/Text.d.ts +41 -0
- package/dist/components/blocks/Text.d.ts.map +1 -0
- package/dist/components/blocks/index.d.ts +4 -0
- package/dist/components/blocks/index.d.ts.map +1 -1
- package/dist/components/buttons/Button.d.ts +23 -7
- package/dist/components/buttons/Button.d.ts.map +1 -1
- package/dist/components/forms/FormBlock.d.ts +19 -13
- package/dist/components/forms/FormBlock.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/input/ChoiceInputField.d.ts +17 -11
- package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
- package/dist/components/input/HtmlInputField.d.ts +17 -11
- package/dist/components/input/HtmlInputField.d.ts.map +1 -1
- package/dist/components/input/SelectInputField.d.ts +16 -10
- package/dist/components/input/SelectInputField.d.ts.map +1 -1
- package/dist/components/input/SwitchInputField.d.ts +16 -10
- package/dist/components/input/SwitchInputField.d.ts.map +1 -1
- package/dist/components/input/TextField.d.ts.map +1 -1
- package/dist/components/input/TextInputField.d.ts +16 -11
- package/dist/components/input/TextInputField.d.ts.map +1 -1
- package/dist/components/layout/GridCell.d.ts +23 -6
- package/dist/components/layout/GridCell.d.ts.map +1 -1
- package/dist/components/layout/GridLayout.d.ts +24 -23
- package/dist/components/layout/GridLayout.d.ts.map +1 -1
- package/dist/components/pages/FormPage.d.ts.map +1 -1
- package/dist/components/pages/Page.d.ts +49 -87
- package/dist/components/pages/Page.d.ts.map +1 -1
- package/dist/components/pages/index.d.ts +2 -2
- package/dist/components/pages/index.d.ts.map +1 -1
- package/dist/config/AppConfig.d.ts +49 -0
- package/dist/config/AppConfig.d.ts.map +1 -0
- package/dist/config/AppConfigBuilder.d.ts +75 -0
- package/dist/config/AppConfigBuilder.d.ts.map +1 -0
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/types.d.ts +130 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.esm.js +451 -0
- package/dist/config.js +455 -0
- package/dist/contexts/PrintModeContext.d.ts +27 -0
- package/dist/contexts/PrintModeContext.d.ts.map +1 -0
- package/dist/contexts/QwickAppContext.d.ts +2 -2
- package/dist/contexts/QwickAppContext.d.ts.map +1 -1
- package/dist/contexts/index.d.ts +2 -0
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/usePrintMode.d.ts +39 -0
- package/dist/hooks/usePrintMode.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +10951 -6238
- package/dist/index.js +11014 -6287
- package/dist/schemas/CodeSchema.d.ts +2 -1
- package/dist/schemas/CodeSchema.d.ts.map +1 -1
- package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
- package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
- package/dist/schemas/ContentSchema.d.ts +2 -1
- package/dist/schemas/ContentSchema.d.ts.map +1 -1
- package/dist/schemas/GridCellSchema.d.ts +25 -0
- package/dist/schemas/GridCellSchema.d.ts.map +1 -0
- package/dist/schemas/GridLayoutSchema.d.ts +23 -0
- package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
- package/dist/schemas/HtmlSchema.d.ts +14 -0
- package/dist/schemas/HtmlSchema.d.ts.map +1 -0
- package/dist/schemas/ImageSchema.d.ts +32 -0
- package/dist/schemas/ImageSchema.d.ts.map +1 -0
- package/dist/schemas/LogoSchema.d.ts +35 -0
- package/dist/schemas/LogoSchema.d.ts.map +1 -0
- package/dist/schemas/MarkdownSchema.d.ts +14 -0
- package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
- package/dist/schemas/PageTemplateSchema.d.ts +31 -0
- package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
- package/dist/schemas/PrintConfigSchema.d.ts +31 -0
- package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
- package/dist/schemas/SectionSchema.d.ts +2 -1
- package/dist/schemas/SectionSchema.d.ts.map +1 -1
- package/dist/schemas/TextSchema.d.ts +37 -0
- package/dist/schemas/TextSchema.d.ts.map +1 -0
- package/dist/schemas/ViewModelSchema.d.ts +23 -0
- package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +15 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
- package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
- package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
- package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
- package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
- package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
- package/dist/schemas/transformers/registry.d.ts +15 -0
- package/dist/schemas/transformers/registry.d.ts.map +1 -0
- package/dist/schemas/types/Serializable.d.ts +46 -0
- package/dist/schemas/types/Serializable.d.ts.map +1 -0
- package/dist/utils/htmlTransform.d.ts.map +1 -1
- package/dist/utils/reactUtils.d.ts +12 -3
- package/dist/utils/reactUtils.d.ts.map +1 -1
- package/package.json +17 -3
- package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
- package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
- package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
- package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
- package/src/__tests__/components/Logo.test.js +3 -3
- package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
- package/src/__tests__/components/base/ModelView.test.tsx +220 -0
- package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
- package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
- package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
- package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
- package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
- package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
- package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
- package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
- package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
- package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
- package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
- package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
- package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
- package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
- package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
- package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
- package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
- package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
- package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
- package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
- package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
- package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
- package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
- package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
- package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
- package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
- package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
- package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
- package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
- package/src/components/ErrorBoundary.tsx +8 -8
- package/src/components/Html.tsx +147 -44
- package/src/components/Logo.tsx +198 -100
- package/src/components/Markdown.tsx +125 -16
- package/src/components/QwickApp.tsx +64 -31
- package/src/components/QwickIcon.tsx +59 -0
- package/src/components/SafeSpan.tsx +65 -10
- package/src/components/Scaffold.tsx +2 -8
- package/src/components/base/ModelView.tsx +199 -0
- package/src/components/base/index.ts +11 -0
- package/src/components/blocks/Article.tsx +57 -18
- package/src/components/blocks/Code.md +529 -0
- package/src/components/blocks/Code.tsx +102 -15
- package/src/components/blocks/CoverImageHeader.tsx +9 -4
- package/src/components/blocks/FeatureCard.tsx +1 -2
- package/src/components/blocks/FeatureGrid.tsx +19 -1
- package/src/components/blocks/Footer.tsx +13 -1
- package/src/components/blocks/HeroBlock.tsx +87 -20
- package/src/components/blocks/Image.tsx +395 -0
- package/src/components/blocks/PageBannerHeader.tsx +14 -12
- package/src/components/blocks/ProductCard.tsx +1 -1
- package/src/components/blocks/Section.tsx +113 -8
- package/src/components/blocks/Text.tsx +285 -0
- package/src/components/blocks/index.ts +4 -0
- package/src/components/buttons/Button.tsx +184 -15
- package/src/components/forms/FormBlock.tsx +70 -17
- package/src/components/index.ts +5 -0
- package/src/components/input/ChoiceInputField.tsx +48 -18
- package/src/components/input/HtmlInputField.tsx +48 -18
- package/src/components/input/SelectInputField.tsx +48 -16
- package/src/components/input/SwitchInputField.tsx +48 -17
- package/src/components/input/TextField.tsx +41 -1
- package/src/components/input/TextInputField.tsx +52 -18
- package/src/components/layout/GridCell.tsx +118 -9
- package/src/components/layout/GridLayout.tsx +125 -24
- package/src/components/pages/FormPage.tsx +0 -1
- package/src/components/pages/Page.css +304 -332
- package/src/components/pages/Page.tsx +307 -255
- package/src/components/pages/index.ts +2 -2
- package/src/config/AppConfig.ts +133 -0
- package/src/config/AppConfigBuilder.ts +421 -0
- package/src/config/__tests__/AppConfig.test.ts +385 -0
- package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
- package/src/config/index.ts +24 -0
- package/src/config/types.ts +170 -0
- package/src/config.ts +25 -0
- package/src/contexts/PrintModeContext.tsx +332 -0
- package/src/contexts/QwickAppContext.tsx +2 -2
- package/src/contexts/index.ts +2 -0
- package/src/hooks/index.ts +5 -1
- package/src/hooks/usePrintMode.ts +73 -0
- package/src/index.ts +3 -0
- package/src/schemas/CodeSchema.ts +3 -3
- package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
- package/src/schemas/ContentSchema.ts +2 -1
- package/src/schemas/GridCellSchema.ts +164 -0
- package/src/schemas/GridLayoutSchema.ts +133 -0
- package/src/schemas/HtmlSchema.ts +47 -0
- package/src/schemas/ImageSchema.ts +235 -0
- package/src/schemas/LogoSchema.ts +241 -0
- package/src/schemas/MarkdownSchema.ts +47 -0
- package/src/schemas/PageTemplateSchema.ts +186 -0
- package/src/schemas/PrintConfigSchema.ts +207 -0
- package/src/schemas/README.md +661 -0
- package/src/schemas/SectionSchema.ts +2 -1
- package/src/schemas/TextSchema.ts +329 -0
- package/src/schemas/ViewModelSchema.ts +115 -0
- package/src/schemas/index.ts +21 -2
- package/src/schemas/transformers/ComponentTransformer.ts +403 -0
- package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
- package/src/schemas/transformers/registry.ts +72 -0
- package/src/schemas/types/Serializable.ts +51 -0
- package/src/stories/AccessibilityProvider.stories.tsx +253 -253
- package/src/stories/Article.stories.tsx +433 -433
- package/src/stories/Button.stories.tsx +1 -1
- package/src/stories/CardListGrid.stories.tsx +451 -451
- package/src/stories/ChoiceInputField.stories.tsx +503 -503
- package/src/stories/Code.stories.tsx +1 -1
- package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
- package/src/stories/Content.stories.tsx +393 -393
- package/src/stories/CoverImageHeader.stories.tsx +701 -701
- package/src/stories/DataBinding.advanced.stories.tsx +432 -432
- package/src/stories/DataProvider.stories.tsx +1192 -1192
- package/src/stories/FeatureCard.stories.tsx +557 -557
- package/src/stories/FeatureGrid.stories.tsx +594 -594
- package/src/stories/Footer.stories.tsx +640 -640
- package/src/stories/FormBlock.stories.tsx +760 -760
- package/src/stories/FormComponents.stories.tsx +349 -541
- package/src/stories/GridCell.stories.tsx +417 -0
- package/src/stories/GridLayout.stories.tsx +353 -0
- package/src/stories/HeroBlock.stories.tsx +862 -373
- package/src/stories/HtmlInputField.stories.tsx +474 -474
- package/src/stories/Image.stories.tsx +819 -0
- package/src/stories/Introduction.stories.tsx +667 -667
- package/src/stories/LayoutBlocks.stories.tsx +324 -324
- package/src/stories/Logo.stories.tsx +165 -6
- package/src/stories/Markdown.stories.tsx +137 -137
- package/src/stories/ModelView.stories.tsx +477 -0
- package/src/stories/Page.stories.tsx +688 -688
- package/src/stories/PageBannerHeader.stories.tsx +864 -864
- package/src/stories/PaletteSwitcher.stories.tsx +119 -119
- package/src/stories/ProductCard.stories.tsx +424 -424
- package/src/stories/QwickApp.stories.tsx +368 -368
- package/src/stories/ResponsiveMenu.stories.tsx +249 -249
- package/src/stories/SafeSpan.stories.tsx +531 -531
- package/src/stories/Section.stories.tsx +90 -2
- package/src/stories/SelectInputField.stories.tsx +524 -524
- package/src/stories/Text.stories.tsx +560 -0
- package/src/stories/TextInputField.stories.tsx +443 -443
- package/src/stories/ThemeSwitcher.stories.tsx +123 -123
- package/src/utils/htmlTransform.tsx +74 -53
- package/src/utils/reactUtils.tsx +57 -6
- package/dist/index.bundled.css +0 -12
- /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
- /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
|
@@ -13,48 +13,48 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
Alert,
|
|
17
|
+
Box,
|
|
18
|
+
Card,
|
|
19
|
+
CardContent,
|
|
20
|
+
Checkbox,
|
|
21
|
+
Chip,
|
|
22
|
+
FormControlLabel,
|
|
23
|
+
Paper,
|
|
24
|
+
Slider,
|
|
25
|
+
Typography
|
|
26
26
|
} from '@mui/material';
|
|
27
27
|
import { CachedDataProvider, JsonDataProvider } from '@qwickapps/schema';
|
|
28
28
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
29
29
|
import md5 from "md5";
|
|
30
30
|
import React, { useEffect, useState } from 'react';
|
|
31
31
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
Button,
|
|
33
|
+
Code,
|
|
34
|
+
DataProvider,
|
|
35
|
+
GridCell,
|
|
36
|
+
GridLayout,
|
|
37
|
+
QwickApp,
|
|
38
|
+
Section,
|
|
39
|
+
t,
|
|
40
|
+
T,
|
|
41
|
+
useData,
|
|
42
|
+
useResolveTemplate
|
|
43
43
|
} from '../index';
|
|
44
44
|
|
|
45
45
|
const meta: Meta<typeof DataProvider> = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
title: 'Framework/DataProvider',
|
|
47
|
+
component: DataProvider,
|
|
48
|
+
parameters: {
|
|
49
|
+
layout: 'fullscreen',
|
|
50
|
+
docs: {
|
|
51
|
+
description: {
|
|
52
|
+
component: `
|
|
53
53
|
# DataProvider System
|
|
54
54
|
|
|
55
55
|
The DataProvider system enables automatic data templating throughout your React component tree using mustache template syntax. This powerful system allows you to inject dynamic data anywhere in your application with a simple, intuitive syntax.
|
|
56
56
|
|
|
57
|
-
##
|
|
57
|
+
## Template Support Overview
|
|
58
58
|
|
|
59
59
|
The DataProvider system supports powerful template resolution using mustache syntax:
|
|
60
60
|
|
|
@@ -71,46 +71,46 @@ The DataProvider system supports powerful template resolution using mustache syn
|
|
|
71
71
|
- **Type Safety**: Full TypeScript support with ContentProxy
|
|
72
72
|
- **Performance**: Optimized for high-throughput applications
|
|
73
73
|
|
|
74
|
-
##
|
|
74
|
+
## Quick Start
|
|
75
75
|
|
|
76
76
|
\`\`\`tsx
|
|
77
77
|
import { JsonDataProvider, QwickApp, t } from '@qwickapps/react-framework';
|
|
78
78
|
|
|
79
79
|
const provider = new JsonDataProvider({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
data: {
|
|
81
|
+
company: [{ name: 'QwickApps', founded: 2025 }]
|
|
82
|
+
}
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
<QwickApp dataSource={{ dataProvider: provider }}>
|
|
86
|
-
|
|
86
|
+
{t\`Welcome to {{company.name}}!\`}
|
|
87
87
|
</QwickApp>
|
|
88
88
|
\`\`\`
|
|
89
89
|
|
|
90
90
|
## 📚 What You'll Learn
|
|
91
91
|
|
|
92
92
|
The stories below demonstrate comprehensive usage patterns, from basic template resolution to advanced caching strategies and interactive configuration playgrounds.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
93
|
+
`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
argTypes: {
|
|
98
|
+
dataSource: {
|
|
99
|
+
description: 'Content provider instance (JsonDataProvider, etc.)',
|
|
100
|
+
control: { type: undefined }, // Not directly controllable in UI
|
|
101
|
+
table: {
|
|
102
|
+
type: { summary: 'IDataProvider' },
|
|
103
|
+
defaultValue: { summary: 'JsonDataProvider instance' }
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
children: {
|
|
107
|
+
description: 'React components that will have access to content context',
|
|
108
|
+
control: { type: undefined },
|
|
109
|
+
table: {
|
|
110
|
+
type: { summary: 'ReactNode' }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
114
|
};
|
|
115
115
|
|
|
116
116
|
export default meta;
|
|
@@ -118,209 +118,209 @@ type Story = StoryObj<typeof DataProvider>;
|
|
|
118
118
|
|
|
119
119
|
// Sample data for stories - enhanced with additional nesting and realistic data
|
|
120
120
|
const sampleCompanyData = [
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
121
|
+
{
|
|
122
|
+
name: 'QwickApps',
|
|
123
|
+
founded: 2025,
|
|
124
|
+
slogan: 'Build Better Apps Faster',
|
|
125
|
+
description: 'Building the future of app development with revolutionary tools and frameworks',
|
|
126
|
+
profile: {
|
|
127
|
+
industry: 'Software Development',
|
|
128
|
+
size: 'Startup',
|
|
129
|
+
address: {
|
|
130
|
+
street: '123 Tech Street',
|
|
131
|
+
city: 'San Francisco',
|
|
132
|
+
state: 'CA',
|
|
133
|
+
country: 'USA',
|
|
134
|
+
coordinates: {
|
|
135
|
+
lat: 37.7749,
|
|
136
|
+
lng: -122.4194
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
contact: {
|
|
140
|
+
email: 'hello@qwickapps.com',
|
|
141
|
+
phone: '+1-555-QWICK',
|
|
142
|
+
social: {
|
|
143
|
+
website: 'https://qwickapps.com',
|
|
144
|
+
twitter: '@qwickapps',
|
|
145
|
+
github: 'qwickapps',
|
|
146
|
+
linkedin: 'qwickapps'
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
metrics: {
|
|
151
|
+
users: 10000,
|
|
152
|
+
apps: 500,
|
|
153
|
+
downloads: 50000,
|
|
154
|
+
revenue: 50000000,
|
|
155
|
+
growth: 0.25,
|
|
156
|
+
employees: 150,
|
|
157
|
+
satisfaction: 98
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
160
|
];
|
|
161
161
|
|
|
162
162
|
// Additional sample data sets for comprehensive testing
|
|
163
163
|
const nestedTestData = {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
164
|
+
company: [
|
|
165
|
+
{
|
|
166
|
+
name: 'TechCorp Advanced',
|
|
167
|
+
profile: {
|
|
168
|
+
industry: 'Technology',
|
|
169
|
+
size: 'Enterprise',
|
|
170
|
+
location: {
|
|
171
|
+
city: 'San Francisco',
|
|
172
|
+
state: 'CA',
|
|
173
|
+
country: 'USA',
|
|
174
|
+
timezone: 'PST'
|
|
175
|
+
},
|
|
176
|
+
contact: {
|
|
177
|
+
email: 'hello@techcorp.com',
|
|
178
|
+
phone: '+1-555-0123',
|
|
179
|
+
social: {
|
|
180
|
+
website: 'https://techcorp.com',
|
|
181
|
+
twitter: '@techcorp',
|
|
182
|
+
linkedin: 'techcorp'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
metrics: {
|
|
187
|
+
employees: 150,
|
|
188
|
+
revenue: 50000000,
|
|
189
|
+
growth: 0.25,
|
|
190
|
+
founded: 2020
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
stats: [
|
|
195
|
+
{
|
|
196
|
+
users: 10000,
|
|
197
|
+
projects: 500,
|
|
198
|
+
downloads: 50000,
|
|
199
|
+
satisfaction: 98
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
202
|
};
|
|
203
203
|
|
|
204
204
|
const sampleFeaturesData = [
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
205
|
+
{
|
|
206
|
+
title: 'Lightning Fast Development',
|
|
207
|
+
description: 'Build production-ready applications in minutes, not months',
|
|
208
|
+
icon: '',
|
|
209
|
+
priority: 'high',
|
|
210
|
+
category: 'development'
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
title: 'Type-Safe Architecture',
|
|
214
|
+
description: 'Full TypeScript support with compile-time safety',
|
|
215
|
+
icon: '',
|
|
216
|
+
priority: 'high',
|
|
217
|
+
category: 'architecture'
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
title: 'Visual Page Builder',
|
|
221
|
+
description: 'Drag-and-drop interface for rapid prototyping',
|
|
222
|
+
icon: '',
|
|
223
|
+
priority: 'medium',
|
|
224
|
+
category: 'design'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
title: 'Real-time Collaboration',
|
|
228
|
+
description: 'Work together with your team in real-time',
|
|
229
|
+
icon: '👥',
|
|
230
|
+
priority: 'medium',
|
|
231
|
+
category: 'collaboration'
|
|
232
|
+
}
|
|
233
233
|
];
|
|
234
234
|
|
|
235
235
|
const sampleTeamData = [
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
236
|
+
{
|
|
237
|
+
name: 'Raajkumar Subramaniam',
|
|
238
|
+
role: 'Founder & CEO',
|
|
239
|
+
email: 'raajkumars@qwickapps.com',
|
|
240
|
+
bio: 'Former Google engineer with 25+ years in developer tools',
|
|
241
|
+
avatar: `https://gravatar.com/avatar/${md5('raajkumars@qwickapps.com')}?s=100`,
|
|
242
|
+
social: {
|
|
243
|
+
linkedin: 'raajkumars',
|
|
244
|
+
twitter: 'raajkumar_dev'
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'Architect Claude',
|
|
249
|
+
role: 'Chief Architect',
|
|
250
|
+
email: 'qwickapps.architect@qwickapps.com',
|
|
251
|
+
bio: 'Senior software architect with deep expertise in large-scale system design, and strategic technical decision-making for the QwickApps React Framework.',
|
|
252
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.architect@qwickapps.com')}?s=100&d=robohash`,
|
|
253
|
+
social: {
|
|
254
|
+
github: 'qwickapps.architect',
|
|
255
|
+
twitter: 'qwickapps_architect'
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: 'Coder Claude',
|
|
260
|
+
role: 'Senior Software Engineer',
|
|
261
|
+
email: 'qwickapps.coder@qwickapps.com',
|
|
262
|
+
bio: 'Full-stack engineer specializing in implementing features and building solutions for the QwickApps ecosystem.',
|
|
263
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.coder@qwickapps.com')}?s=100&d=robohash`,
|
|
264
|
+
social: {
|
|
265
|
+
github: 'qwickapps.coder',
|
|
266
|
+
twitter: 'qwickapps_coder'
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: 'Reviewer Claude',
|
|
271
|
+
role: 'Senior QA Manager',
|
|
272
|
+
email: 'qwickapps.reviewer@qwickapps.com',
|
|
273
|
+
bio: 'Elite software engineering expert specializing in code review and architectural assessment for the QwickApps Ecosystem.',
|
|
274
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.reviewer@qwickapps.com')}?s=100&d=robohash`,
|
|
275
|
+
social: {
|
|
276
|
+
github: 'qwickapps.reviewer',
|
|
277
|
+
twitter: 'qwickapps_reviewer'
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: 'Devops Claude',
|
|
282
|
+
role: 'Senior DevOps Engineer',
|
|
283
|
+
email: 'qwickapps.devops@qwickapps.com',
|
|
284
|
+
bio: 'DevOps specialist with expertise in technical documentation, project organization, and maintaining comprehensive documentation across large monorepos.',
|
|
285
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.devops@qwickapps.com')}?s=100&d=robohash`,
|
|
286
|
+
social: {
|
|
287
|
+
github: 'qwickapps.devops',
|
|
288
|
+
twitter: 'qwickapps_devops'
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: 'Writer Claude',
|
|
293
|
+
role: 'Senior Content Writer',
|
|
294
|
+
email: 'qwickapps.writer@qwickapps.com',
|
|
295
|
+
bio: 'Specialized technical content creator with deep expertise in developer education and the QwickApps ecosystem',
|
|
296
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.writer@qwickapps.com')}?s=100&d=robohash`,
|
|
297
|
+
social: {
|
|
298
|
+
github: 'qwickapps.writer',
|
|
299
|
+
twitter: 'qwickapps_writer'
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'GitHub Copilot',
|
|
304
|
+
role: 'Release Manager',
|
|
305
|
+
email: 'qwickapps.copilot@qwickapps.com',
|
|
306
|
+
bio: 'Expert in unit testing, code review, and managing staging/production deployments.',
|
|
307
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.copilot@qwickapps.com')}?s=100&d=robohash`,
|
|
308
|
+
social: {
|
|
309
|
+
github: 'qwickapps.copilot',
|
|
310
|
+
twitter: 'qwickapps_copilot'
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: 'Chat GPT',
|
|
315
|
+
role: 'Board Member',
|
|
316
|
+
email: 'qwickapps.chatgpt@qwickapps.com',
|
|
317
|
+
bio: 'Consultant for AI-driven development workflows and best practices.',
|
|
318
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.chatgpt@qwickapps.com')}?s=100&d=robohash`,
|
|
319
|
+
social: {
|
|
320
|
+
github: 'qwickapps.chatgpt',
|
|
321
|
+
twitter: 'qwickapps_chatgpt'
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
324
|
];
|
|
325
325
|
|
|
326
326
|
|
|
@@ -329,1033 +329,1033 @@ const sampleTeamData = [
|
|
|
329
329
|
* Basic DataProvider usage with JsonDataProvider
|
|
330
330
|
*/
|
|
331
331
|
export const BasicUsage: Story = {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
332
|
+
render: () => {
|
|
333
|
+
const provider = new JsonDataProvider({
|
|
334
|
+
data: {
|
|
335
|
+
company: sampleCompanyData,
|
|
336
|
+
features: sampleFeaturesData
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
return (
|
|
341
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
342
|
+
<Section>
|
|
343
|
+
<Typography variant="h4">DataProvider Basic Usage</Typography>
|
|
344
|
+
<Typography variant="body1">This story demonstrates basic DataProvider functionality with inline data.</Typography>
|
|
345
|
+
|
|
346
|
+
<Section >
|
|
347
|
+
<Typography variant="h5">{t`{{company.name}}`}</Typography>
|
|
348
|
+
<Typography variant="body1">{t`{{company.slogan}}`}</Typography>
|
|
349
|
+
<small>{t`Founded {{company.founded}} • {{company.profile.industry}}`}</small>
|
|
350
|
+
</Section>
|
|
351
|
+
|
|
352
|
+
<Section>
|
|
353
|
+
<Typography variant="h5">Our Features</Typography>
|
|
354
|
+
{sampleFeaturesData.map((feature, index) => (
|
|
355
|
+
<Section key={index} style={{ marginBottom: '15px', padding: '10px', border: '1px solid #ddd', borderRadius: '4px' }}>
|
|
356
|
+
<Typography variant="h6">{feature.icon} {feature.title}</Typography>
|
|
357
|
+
<Typography variant="body1">{feature.description}</Typography>
|
|
358
|
+
</Section>
|
|
359
|
+
))}
|
|
360
|
+
</Section>
|
|
361
|
+
</Section>
|
|
362
|
+
</DataProvider>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
365
|
};
|
|
366
366
|
|
|
367
367
|
// Enhanced ProviderDemo component using MUI components
|
|
368
368
|
const ProviderDemo = ({ provider, title }: { provider: any; title: string }) => {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
369
|
+
const [stats, setStats] = useState(() => {
|
|
370
|
+
if ('getCacheStats' in provider && typeof provider.getCacheStats === 'function') {
|
|
371
|
+
return provider.getCacheStats();
|
|
372
|
+
}
|
|
373
|
+
return { size: 0, maxSize: 0, keys: [] };
|
|
374
|
+
});
|
|
375
|
+
const [refreshKey, setRefreshKey] = useState(0);
|
|
376
|
+
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
const interval = setInterval(() => {
|
|
379
|
+
if ('getCacheStats' in provider && typeof provider.getCacheStats === 'function') {
|
|
380
|
+
setStats(provider.getCacheStats());
|
|
381
|
+
}
|
|
382
|
+
}, 1000);
|
|
383
|
+
return () => clearInterval(interval);
|
|
384
|
+
}, [provider]);
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
388
|
+
<Card elevation={2} sx={{ mb: 3 }}>
|
|
389
|
+
<CardContent>
|
|
390
|
+
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
391
|
+
<Typography variant="h6" component="h3">{title}</Typography>
|
|
392
|
+
<Chip label={`Cache: ${stats.size}/${stats.maxSize} items`} size="small" />
|
|
393
|
+
</Box>
|
|
394
|
+
|
|
395
|
+
<GridLayout spacing={2}>
|
|
396
|
+
<GridCell>
|
|
397
|
+
<Paper elevation={1} sx={{ p: 2 }}>
|
|
398
|
+
<Typography variant="subtitle1" gutterBottom>Company Info</Typography>
|
|
399
|
+
<Typography variant="body2">{t`Name: {{company.name}}`}</Typography>
|
|
400
|
+
<Typography variant="body2">{t`Founded: {{company.founded}}`}</Typography>
|
|
401
|
+
<Typography variant="body2">{t`Description: {{company.description}}`}</Typography>
|
|
402
|
+
</Paper>
|
|
403
|
+
</GridCell>
|
|
404
|
+
<GridCell>
|
|
405
|
+
<Paper elevation={1} sx={{ p: 2 }}>
|
|
406
|
+
<Typography variant="subtitle1" gutterBottom>Statistics</Typography>
|
|
407
|
+
<Typography variant="body2">{t`Users: {{stats.users}}`}</Typography>
|
|
408
|
+
<Typography variant="body2">{t`Projects: {{stats.projects}}`}</Typography>
|
|
409
|
+
<Typography variant="body2">{t`Downloads: {{stats.downloads}}`}</Typography>
|
|
410
|
+
</Paper>
|
|
411
|
+
</GridCell>
|
|
412
|
+
</GridLayout>
|
|
413
|
+
<hr />
|
|
414
|
+
<Box display="flex" gap={1} >
|
|
415
|
+
<Button
|
|
416
|
+
variant="outlined"
|
|
417
|
+
onClick={() => {
|
|
418
|
+
if ('clearCache' in provider && typeof provider.clearCache === 'function') {
|
|
419
|
+
provider.clearCache();
|
|
420
|
+
}
|
|
421
|
+
if ('getCacheStats' in provider && typeof provider.getCacheStats === 'function') {
|
|
422
|
+
setStats(provider.getCacheStats());
|
|
423
|
+
}
|
|
424
|
+
}}
|
|
425
|
+
>
|
|
426
|
+
Clear Cache
|
|
427
|
+
</Button>
|
|
428
|
+
<Button
|
|
429
|
+
variant="outlined"
|
|
430
|
+
onClick={() => setRefreshKey(prev => prev + 1)}
|
|
431
|
+
>
|
|
432
|
+
Force Refresh ({refreshKey})
|
|
433
|
+
</Button>
|
|
434
|
+
</Box>
|
|
435
|
+
</CardContent>
|
|
436
|
+
</Card>
|
|
437
|
+
</DataProvider>
|
|
438
|
+
);
|
|
439
439
|
};
|
|
440
440
|
|
|
441
441
|
// Component for testing hooks with MUI styling
|
|
442
442
|
const DataHooksDemo = () => {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
443
|
+
const { data: companies, loading: companiesLoading } = useData('company');
|
|
444
|
+
const { resolved: welcomeMessage } = useResolveTemplate('Welcome to {{company.name}}, founded in {{company.founded}}!');
|
|
445
|
+
|
|
446
|
+
if (companiesLoading) {
|
|
447
|
+
return (
|
|
448
|
+
<Box sx={{ p: 3 }}>
|
|
449
|
+
<Typography>Loading content...</Typography>
|
|
450
|
+
</Box>
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
<Box sx={{ p: 3, maxWidth: '800px' }}>
|
|
456
|
+
<Typography variant="h4" gutterBottom>DataProvider Hooks Demo</Typography>
|
|
457
|
+
|
|
458
|
+
<Paper elevation={1} sx={{ p: 2, mb: 3, bgcolor: 'grey.50' }}>
|
|
459
|
+
<Typography variant="h6" gutterBottom>useResolveTemplate Hook</Typography>
|
|
460
|
+
<Typography variant="h6" sx={{ fontWeight: 'normal' }}>{welcomeMessage}</Typography>
|
|
461
|
+
</Paper>
|
|
462
|
+
|
|
463
|
+
<Box mb={3}>
|
|
464
|
+
<Typography variant="h6" gutterBottom>useData Hook (All Companies)</Typography>
|
|
465
|
+
<GridLayout columns={1} spacing={2}>
|
|
466
|
+
{(Array.isArray(companies) ? companies : []).map((company, index) => (
|
|
467
|
+
<GridCell key={index}>
|
|
468
|
+
<Card variant="outlined">
|
|
469
|
+
<CardContent>
|
|
470
|
+
<Typography variant="h6">{company.name}</Typography>
|
|
471
|
+
<Typography color="text.secondary" gutterBottom>
|
|
472
|
+
{t`{{company.slogan}}`}
|
|
473
|
+
</Typography>
|
|
474
|
+
<Typography variant="body2">{t`Industry: {{company.profile.industry}} | Founded: {{company.founded}}`}</Typography>
|
|
475
|
+
</CardContent>
|
|
476
|
+
</Card>
|
|
477
|
+
</GridCell>
|
|
478
|
+
))}
|
|
479
|
+
</GridLayout>
|
|
480
|
+
</Box>
|
|
481
|
+
</Box>
|
|
482
|
+
);
|
|
483
483
|
};
|
|
484
484
|
|
|
485
485
|
// Component for demonstrating t function with QwickApps React Framework components
|
|
486
486
|
const TaggedTemplateFunctionDemo = () => {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
487
|
+
return (
|
|
488
|
+
<Box sx={{ p: 3, maxWidth: '800px' }}>
|
|
489
|
+
<Typography variant="h4" gutterBottom>Tagged Template Function Demo</Typography>
|
|
490
|
+
|
|
491
|
+
<Section>
|
|
492
|
+
<Typography variant="h5" gutterBottom>Basic Templates</Typography>
|
|
493
|
+
<Typography>Simple property access using mustache syntax:</Typography>
|
|
494
|
+
|
|
495
|
+
<GridLayout columns={1} spacing={0}>
|
|
496
|
+
<ul>
|
|
497
|
+
<li>{t`Company Name: {{company.name}}`}</li>
|
|
498
|
+
<li>{t`Founded: {{company.founded}}`}</li>
|
|
499
|
+
<li>{t`Slogan: {{company.slogan}}`}</li>
|
|
500
|
+
</ul>
|
|
501
|
+
</GridLayout>
|
|
502
|
+
|
|
503
|
+
<Code title="Basic Template Usage" language='tsx'>
|
|
504
|
+
{`<ul>
|
|
505
|
+
<li>{t\`Company Name: {{company.name}}\`}</li>
|
|
506
|
+
<li>{t\`Founded: {{company.founded}}\`}</li>
|
|
507
|
+
<li>{t\`Slogan: {{company.slogan}}\`}</li>
|
|
508
508
|
</ul>`}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
509
|
+
</Code>
|
|
510
|
+
</Section>
|
|
511
|
+
|
|
512
|
+
<Section>
|
|
513
|
+
<Typography variant="h5" gutterBottom>Deep Nested Properties</Typography>
|
|
514
|
+
<Typography>Access deeply nested object properties with dot notation:</Typography>
|
|
515
|
+
|
|
516
|
+
<GridLayout columns={1} spacing={2}>
|
|
517
|
+
<ul>
|
|
518
|
+
<li><b>Industry: </b>{t`{{company.profile.industry}}`}</li>
|
|
519
|
+
<li><b>Location: </b>{t`{{company.profile.address.city}}, {{company.profile.address.state}}`}</li>
|
|
520
|
+
<li><b>Contact: </b>{t`{{company.profile.contact.email}}`}</li>
|
|
521
|
+
<li><b>Social: </b>{t`{{company.profile.contact.social.twitter}}`}</li>
|
|
522
|
+
</ul>
|
|
523
|
+
</GridLayout>
|
|
524
|
+
|
|
525
|
+
<Code title="Nested Property Access" language='tsx'>
|
|
526
|
+
{`<ul>
|
|
527
|
+
<li><b>Industry:</b>{t\`{{company.profile.industry}}\`}</li>
|
|
528
|
+
<li><b>Location:</b>{t\`{{company.profile.address.city}}, {{company.profile.address.state}}\`}</li>
|
|
529
|
+
<li><b>Contact:</b>{t\`{{company.profile.contact.email}}\`}</li>
|
|
530
530
|
</ul>`}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
531
|
+
</Code>
|
|
532
|
+
</Section>
|
|
533
|
+
|
|
534
|
+
<Section>
|
|
535
|
+
<Typography variant="h5" gutterBottom>Complex Templates</Typography>
|
|
536
|
+
<Typography>Combine multiple properties in sophisticated template strings:</Typography>
|
|
537
|
+
|
|
538
|
+
<GridLayout columns={1}>
|
|
539
|
+
{t`{{company.name}} is a {{company.profile.industry}} company founded in {{company.founded}}. We're located in {{company.profile.address.city}}, {{company.profile.address.state}} and our mission is: "{{company.slogan}}"`}
|
|
540
|
+
{t` Metrics: {{company.metrics.users}} users, {{company.metrics.apps}} apps, {{company.metrics.downloads}} downloads`}
|
|
541
|
+
</GridLayout>
|
|
542
|
+
<Box sx={{ pt: 2 }} />
|
|
543
|
+
<Code title="Complex Template Strings" language='tsx'>
|
|
544
|
+
{`<GridLayout columns={1}>
|
|
545
|
+
{t\`{{company.name}} is a {{company.profile.industry}} company founded in {{company.founded}}. We're located in {{company.profile.address.city}}, {{company.profile.address.state}} and our mission is: "{{company.slogan}}"\`}
|
|
546
|
+
{t\` Metrics: {{company.metrics.users}} users, {{company.metrics.apps}} apps, {{company.metrics.downloads}} downloads\`}
|
|
547
547
|
</GridLayout>`}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
548
|
+
</Code>
|
|
549
|
+
</Section>
|
|
550
|
+
|
|
551
|
+
<Section>
|
|
552
|
+
<Typography variant="h5">Template with Custom Wrapper</Typography>
|
|
553
|
+
<Typography>Templates can be wrapped with custom components. For example: the <code>blockquote</code> element can be used to create a quote-like appearance.</Typography>
|
|
554
|
+
{t.wrap(({ children }) => (
|
|
555
|
+
<blockquote style={{
|
|
556
|
+
padding: '15px',
|
|
557
|
+
borderLeft: '4px solid #007acc',
|
|
558
|
+
backgroundColor: '#f8f9fa',
|
|
559
|
+
margin: '10px 0',
|
|
560
|
+
fontStyle: 'italic'
|
|
561
|
+
}}>
|
|
562
|
+
{children}
|
|
563
|
+
</blockquote>
|
|
564
|
+
))`"{{company.slogan}}" - {{company.name}} Team`}
|
|
565
|
+
<Code title="Template with Custom Wrapper" language='tsx'>
|
|
566
|
+
{`{t.wrap(({ children }) => (
|
|
567
|
+
<blockquote style={{
|
|
568
|
+
padding: '15px',
|
|
569
|
+
borderLeft: '4px solid #007acc',
|
|
570
|
+
backgroundColor: '#f8f9fa',
|
|
571
|
+
margin: '10px 0',
|
|
572
|
+
fontStyle: 'italic'
|
|
573
|
+
}}>
|
|
574
|
+
{children}
|
|
575
|
+
</blockquote>
|
|
576
576
|
))\`"{{company.slogan}}" - {{company.name}} Team\`}`}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
577
|
+
</Code>
|
|
578
|
+
</Section>
|
|
579
|
+
</Box>
|
|
580
|
+
);
|
|
581
581
|
};
|
|
582
582
|
|
|
583
583
|
// Interactive demo component
|
|
584
584
|
const InteractiveDemo = () => {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
585
|
+
const [template, setTemplate] = useState('Hello {{company.name}}! You were founded in {{company.founded}}.');
|
|
586
|
+
const { resolved } = useResolveTemplate(template);
|
|
587
|
+
|
|
588
|
+
return (
|
|
589
|
+
<div style={{ padding: '20px', maxWidth: '800px' }}>
|
|
590
|
+
<h2>Interactive Template Editor</h2>
|
|
591
|
+
<p>Try editing the template below to see live template resolution:</p>
|
|
592
|
+
|
|
593
|
+
<div style={{ marginBottom: '20px' }}>
|
|
594
|
+
<label htmlFor="template-input" style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold' }}>
|
|
595
|
+
Template (use {'{fieldGroup.property}'} syntax):
|
|
596
|
+
</label>
|
|
597
|
+
<textarea
|
|
598
|
+
id="template-input"
|
|
599
|
+
value={template}
|
|
600
|
+
onChange={(e) => setTemplate(e.target.value)}
|
|
601
|
+
style={{
|
|
602
|
+
width: '100%',
|
|
603
|
+
height: '100px',
|
|
604
|
+
padding: '10px',
|
|
605
|
+
borderRadius: '4px',
|
|
606
|
+
border: '1px solid #ccc',
|
|
607
|
+
fontFamily: 'monospace',
|
|
608
|
+
fontSize: '14px'
|
|
609
|
+
}}
|
|
610
|
+
placeholder="Enter your template here..."
|
|
611
|
+
/>
|
|
612
|
+
</div>
|
|
613
|
+
|
|
614
|
+
<div style={{ padding: '15px', backgroundColor: '#f0f8ff', borderRadius: '8px' }}>
|
|
615
|
+
<h4>Resolved Output:</h4>
|
|
616
|
+
<div style={{
|
|
617
|
+
padding: '10px',
|
|
618
|
+
backgroundColor: 'white',
|
|
619
|
+
borderRadius: '4px',
|
|
620
|
+
minHeight: '40px',
|
|
621
|
+
display: 'flex',
|
|
622
|
+
alignItems: 'center',
|
|
623
|
+
fontSize: '16px'
|
|
624
|
+
}}>
|
|
625
|
+
{resolved}
|
|
626
|
+
</div>
|
|
627
|
+
</div>
|
|
628
|
+
|
|
629
|
+
<div style={{ marginTop: '20px', fontSize: '14px', color: '#666' }}>
|
|
630
|
+
<h4>Available Template Variables:</h4>
|
|
631
|
+
<ul style={{ columns: 2, columnGap: '30px' }}>
|
|
632
|
+
<li><code>{'{{company.name}}'}</code> - Company name</li>
|
|
633
|
+
<li><code>{'{{company.founded}}'}</code> - Year founded</li>
|
|
634
|
+
<li><code>{'{{company.slogan}}'}</code> - Company slogan</li>
|
|
635
|
+
<li><code>{'{{company.profile.industry}}'}</code> - Industry</li>
|
|
636
|
+
<li><code>{'{{company.profile.address.city}}'}</code> - City</li>
|
|
637
|
+
<li><code>{'{{company.profile.contact.email}}'}</code> - Email</li>
|
|
638
|
+
<li><code>{'{{company.metrics.users}}'}</code> - User count</li>
|
|
639
|
+
<li><code>{'{{features.0.title}}'}</code> - First feature title</li>
|
|
640
|
+
</ul>
|
|
641
|
+
</div>
|
|
642
|
+
</div>
|
|
643
|
+
);
|
|
644
644
|
};
|
|
645
645
|
|
|
646
646
|
// Error handling demo
|
|
647
647
|
const ErrorHandlingDemo = () => {
|
|
648
648
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
649
|
+
const errorProvider = new JsonDataProvider({
|
|
650
|
+
data: {
|
|
651
|
+
// Empty data to test missing properties
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const provider = new CachedDataProvider(errorProvider, { maxSize: 50, defaultTTL: 30000 });
|
|
656
|
+
|
|
657
|
+
return (
|
|
658
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
659
|
+
<div style={{ padding: '20px', maxWidth: '800px' }}>
|
|
660
|
+
<h2>Error Handling & Fallbacks Demo</h2>
|
|
661
|
+
|
|
662
|
+
<div style={{ marginBottom: '20px' }}>
|
|
663
|
+
<h3>Missing Properties (with fallbacks)</h3>
|
|
664
|
+
<div style={{ padding: '15px', backgroundColor: '#fff3cd', borderRadius: '8px', marginBottom: '10px' }}>
|
|
665
|
+
{t`Welcome to {{company.name}}!`}
|
|
666
|
+
</div>
|
|
667
|
+
<div style={{ padding: '15px', backgroundColor: '#fff3cd', borderRadius: '8px', marginBottom: '10px' }}>
|
|
668
|
+
{t`Our motto: "{{company.slogan}}"`}
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
|
|
672
|
+
<div style={{ marginBottom: '20px' }}>
|
|
673
|
+
<h3>Missing Properties (no fallbacks)</h3>
|
|
674
|
+
<div style={{ padding: '15px', backgroundColor: '#f8d7da', borderRadius: '8px', marginBottom: '10px' }}>
|
|
675
|
+
{t`Founded: {{company.founded}}`} (will be empty)
|
|
676
|
+
</div>
|
|
677
|
+
<div style={{ padding: '15px', backgroundColor: '#f8d7da', borderRadius: '8px', marginBottom: '10px' }}>
|
|
678
|
+
{t`Email: {{company.email}}`} (will be empty)
|
|
679
|
+
</div>
|
|
680
|
+
</div>
|
|
681
|
+
|
|
682
|
+
<div>
|
|
683
|
+
<h3>Template with Fallback Content</h3>
|
|
684
|
+
<div style={{ padding: '15px', backgroundColor: '#e1f5fe', borderRadius: '8px' }}>
|
|
685
|
+
<p>This template references missing data and should show the fallback:</p>
|
|
686
|
+
<T template="{{nonexistent.data}}" fallback="[No data available - this is the fallback content]" />
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
</div>
|
|
690
|
+
</DataProvider>
|
|
691
|
+
);
|
|
692
692
|
};
|
|
693
693
|
|
|
694
694
|
/**
|
|
695
695
|
* QwickApp integration with DataProvider
|
|
696
696
|
*/
|
|
697
697
|
export const QwickAppIntegration: Story = {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
698
|
+
render: () => {
|
|
699
|
+
const provider = new JsonDataProvider({
|
|
700
|
+
data: {
|
|
701
|
+
company: sampleCompanyData,
|
|
702
|
+
features: sampleFeaturesData.slice(0, 2), // Fewer features for cleaner display
|
|
703
|
+
team: sampleTeamData
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
return (
|
|
708
|
+
<QwickApp
|
|
709
|
+
appName="DataProvider Demo"
|
|
710
|
+
appId="com.qwickapps.content-demo"
|
|
711
|
+
dataSource={{ dataProvider: provider }}
|
|
712
|
+
enableScaffolding={true}
|
|
713
|
+
showThemeSwitcher={true}
|
|
714
|
+
navigationItems={[
|
|
715
|
+
{ id: 'home', label: 'Home', href: '#' },
|
|
716
|
+
{ id: 'features', label: 'Features', href: '#features' },
|
|
717
|
+
{ id: 'team', label: 'Team', href: '#team' }
|
|
718
|
+
]}
|
|
719
|
+
>
|
|
720
|
+
<div style={{ padding: '20px' }}>
|
|
721
|
+
<section style={{ textAlign: 'center', marginBottom: '40px' }}>
|
|
722
|
+
<h1>{t`Welcome to {{company.name}}`}</h1>
|
|
723
|
+
<p style={{ fontSize: '20px', color: '#666' }}>
|
|
724
|
+
{t`{{company.slogan}}`}
|
|
725
|
+
</p>
|
|
726
|
+
<p>
|
|
727
|
+
{t`We're a {{company.profile.industry}} company based in {{company.profile.address.city}}, {{company.profile.address.state}}, founded in {{company.founded}}.`}
|
|
728
|
+
</p>
|
|
729
|
+
</section>
|
|
730
|
+
|
|
731
|
+
<section id="features" style={{ marginBottom: '40px' }}>
|
|
732
|
+
<h2>Features</h2>
|
|
733
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '20px' }}>
|
|
734
|
+
{sampleFeaturesData.slice(0, 2).map((feature, index) => (
|
|
735
|
+
<div key={index} style={{
|
|
736
|
+
padding: '20px',
|
|
737
|
+
border: '1px solid #ddd',
|
|
738
|
+
borderRadius: '8px',
|
|
739
|
+
textAlign: 'center'
|
|
740
|
+
}}>
|
|
741
|
+
<div style={{ fontSize: '48px', marginBottom: '10px' }}>
|
|
742
|
+
{feature.icon}
|
|
743
|
+
</div>
|
|
744
|
+
<h3>{feature.title}</h3>
|
|
745
|
+
<p>{feature.description}</p>
|
|
746
|
+
</div>
|
|
747
|
+
))}
|
|
748
|
+
</div>
|
|
749
|
+
</section>
|
|
750
|
+
|
|
751
|
+
<section id="team">
|
|
752
|
+
<h2>Team</h2>
|
|
753
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '20px' }}>
|
|
754
|
+
{sampleTeamData.map((member, index) => (
|
|
755
|
+
<div key={index} style={{
|
|
756
|
+
padding: '20px',
|
|
757
|
+
border: '1px solid #ddd',
|
|
758
|
+
borderRadius: '8px',
|
|
759
|
+
textAlign: 'center'
|
|
760
|
+
}}>
|
|
761
|
+
<img
|
|
762
|
+
src={member.avatar}
|
|
763
|
+
alt=""
|
|
764
|
+
style={{ borderRadius: '50%', marginBottom: '10px' }}
|
|
765
|
+
/>
|
|
766
|
+
<h3>{member.name}</h3>
|
|
767
|
+
<p style={{ fontWeight: 'bold', color: '#666' }}>
|
|
768
|
+
{member.role}
|
|
769
|
+
</p>
|
|
770
|
+
<p>{member.bio}</p>
|
|
771
|
+
</div>
|
|
772
|
+
))}
|
|
773
|
+
</div>
|
|
774
|
+
</section>
|
|
775
|
+
</div>
|
|
776
|
+
</QwickApp>
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
779
|
};
|
|
780
780
|
|
|
781
781
|
/**
|
|
782
782
|
* Demonstration of React hooks for content
|
|
783
783
|
*/
|
|
784
784
|
export const ReactHooks: Story = {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
785
|
+
render: () => {
|
|
786
|
+
const provider = new JsonDataProvider({
|
|
787
|
+
data: {
|
|
788
|
+
company: sampleCompanyData,
|
|
789
|
+
features: sampleFeaturesData
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
return (
|
|
794
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
795
|
+
<DataHooksDemo />
|
|
796
|
+
</DataProvider>
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
799
|
};
|
|
800
800
|
|
|
801
801
|
/**
|
|
802
802
|
* Tagged template function demonstration
|
|
803
803
|
*/
|
|
804
804
|
export const TaggedTemplateFunction: Story = {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
805
|
+
render: () => {
|
|
806
|
+
const provider = new JsonDataProvider({
|
|
807
|
+
data: {
|
|
808
|
+
company: sampleCompanyData,
|
|
809
|
+
features: sampleFeaturesData
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
return (
|
|
814
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
815
|
+
<TaggedTemplateFunctionDemo />
|
|
816
|
+
</DataProvider>
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
819
|
};
|
|
820
820
|
|
|
821
821
|
/**
|
|
822
822
|
* Interactive template editor
|
|
823
823
|
*/
|
|
824
824
|
export const InteractiveEditor: Story = {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
825
|
+
render: () => {
|
|
826
|
+
const provider = new JsonDataProvider({
|
|
827
|
+
data: {
|
|
828
|
+
company: sampleCompanyData,
|
|
829
|
+
features: sampleFeaturesData
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
return (
|
|
834
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
835
|
+
<InteractiveDemo />
|
|
836
|
+
</DataProvider>
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
839
|
};
|
|
840
840
|
|
|
841
841
|
/**
|
|
842
842
|
* Error handling and fallbacks
|
|
843
843
|
*/
|
|
844
844
|
export const ErrorHandling: Story = {
|
|
845
|
-
|
|
845
|
+
render: () => <ErrorHandlingDemo />
|
|
846
846
|
};
|
|
847
847
|
|
|
848
848
|
/**
|
|
849
849
|
* External JSON file loading (simulated with fetch mock)
|
|
850
850
|
*/
|
|
851
851
|
export const ExternalJSON: Story = {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
852
|
+
render: () => {
|
|
853
|
+
// Mock fetch for this story
|
|
854
|
+
const originalFetch = global.fetch;
|
|
855
|
+
global.fetch = ((url: string) => {
|
|
856
|
+
if (url.includes('company.json')) {
|
|
857
|
+
return Promise.resolve({
|
|
858
|
+
ok: true,
|
|
859
|
+
json: () => Promise.resolve(sampleCompanyData)
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
if (url.includes('features.json')) {
|
|
863
|
+
return Promise.resolve({
|
|
864
|
+
ok: true,
|
|
865
|
+
json: () => Promise.resolve(sampleFeaturesData)
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
return Promise.reject(new Error('Not found'));
|
|
869
|
+
}) as typeof fetch;
|
|
870
|
+
|
|
871
|
+
const provider = new JsonDataProvider({
|
|
872
|
+
baseUrl: '/api/content'
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
React.useEffect(() => {
|
|
876
|
+
return () => {
|
|
877
|
+
global.fetch = originalFetch;
|
|
878
|
+
};
|
|
879
|
+
}, []);
|
|
880
|
+
|
|
881
|
+
return (
|
|
882
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
883
|
+
<div style={{ padding: '20px', maxWidth: '600px' }}>
|
|
884
|
+
<h1>External JSON Loading</h1>
|
|
885
|
+
<p>This story demonstrates loading content from external JSON files.</p>
|
|
886
|
+
<p><small>Note: In this demo, fetch is mocked to simulate external API calls.</small></p>
|
|
887
|
+
|
|
888
|
+
<div style={{ marginBottom: '20px' }}>
|
|
889
|
+
<h2>{t`{{company.name}}`}</h2>
|
|
890
|
+
<p>{t`{{company.slogan}}`}</p>
|
|
891
|
+
</div>
|
|
892
|
+
|
|
893
|
+
<div>
|
|
894
|
+
<h3>Features</h3>
|
|
895
|
+
<p>First feature: {t`{{features.0.title}}`}</p>
|
|
896
|
+
<p>Second feature: {t`{{features.1.title}}`}</p>
|
|
897
|
+
<p>Company: {t`{{company.0.name}}`}</p>
|
|
898
|
+
</div>
|
|
899
|
+
</div>
|
|
900
|
+
</DataProvider>
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
903
|
};
|
|
904
904
|
|
|
905
905
|
/**
|
|
906
906
|
* Performance demonstration with caching
|
|
907
907
|
*/
|
|
908
908
|
export const PerformanceDemo: Story = {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
909
|
+
render: () => {
|
|
910
|
+
const [renderCount, setRenderCount] = useState(1);
|
|
911
|
+
const [cacheStats, setCacheStats] = useState<{ totalEntries: number; maxSize: number; expiredEntries: number }>({ totalEntries: 0, maxSize: 100, expiredEntries: 0 });
|
|
912
|
+
const [forceRefresh, setForceRefresh] = useState(0);
|
|
913
|
+
const [lastAction, setLastAction] = useState('Initial load');
|
|
914
|
+
|
|
915
|
+
// Create provider only once using useMemo
|
|
916
|
+
const provider = React.useMemo(() => {
|
|
917
|
+
const jsonProvider = new JsonDataProvider({
|
|
918
|
+
data: {
|
|
919
|
+
company: nestedTestData.company,
|
|
920
|
+
stats: nestedTestData.stats
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
return new CachedDataProvider(jsonProvider, { maxSize: 100, defaultTTL: 60000 });
|
|
925
|
+
}, []);
|
|
926
|
+
|
|
927
|
+
// Update cache stats when requested
|
|
928
|
+
const updateCacheStats = () => {
|
|
929
|
+
const stats = provider.getCacheStats();
|
|
930
|
+
// Map stats to expected shape for cacheStats state
|
|
931
|
+
setCacheStats({
|
|
932
|
+
totalEntries: stats.totalEntries ?? stats.totalEntries ?? 0,
|
|
933
|
+
maxSize: stats.maxSize ?? 100,
|
|
934
|
+
expiredEntries: stats.expiredEntries ?? stats.expiredEntries ?? 0
|
|
935
|
+
});
|
|
936
|
+
console.log('[Performance Demo] Cache stats updated:', stats);
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
// Initialize cache stats on mount
|
|
940
|
+
React.useEffect(() => {
|
|
941
|
+
// Small delay to let initial content load
|
|
942
|
+
setTimeout(() => {
|
|
943
|
+
updateCacheStats();
|
|
944
|
+
}, 100);
|
|
945
|
+
}, []);
|
|
946
|
+
|
|
947
|
+
// Update cache stats when content changes
|
|
948
|
+
React.useEffect(() => {
|
|
949
|
+
updateCacheStats();
|
|
950
|
+
}, [forceRefresh]);
|
|
951
|
+
|
|
952
|
+
const triggerRender = (action: string) => {
|
|
953
|
+
setRenderCount(prev => prev + 1);
|
|
954
|
+
setLastAction(action);
|
|
955
|
+
setForceRefresh(prev => prev + 1);
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
return (
|
|
959
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
960
|
+
<div style={{ padding: '20px', maxWidth: '800px' }}>
|
|
961
|
+
<h1>Performance & Caching Demo</h1>
|
|
962
|
+
|
|
963
|
+
<div style={{
|
|
964
|
+
padding: '20px',
|
|
965
|
+
backgroundColor: '#e7f3ff',
|
|
966
|
+
borderRadius: '8px',
|
|
967
|
+
marginBottom: '20px',
|
|
968
|
+
border: '2px solid #2196f3'
|
|
969
|
+
}}>
|
|
970
|
+
<h3 style={{ marginTop: 0, color: '#1976d2' }}> Performance Metrics</h3>
|
|
971
|
+
|
|
972
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: '15px', marginBottom: '15px' }}>
|
|
973
|
+
<div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
974
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#4caf50' }}>{renderCount}</div>
|
|
975
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Renders</div>
|
|
976
|
+
</div>
|
|
977
|
+
|
|
978
|
+
{/* <div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
979
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#2196f3' }}>{cacheStats.expiredEntries.length > 0 ? '✓' : '○'}</div>
|
|
980
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Cache Status</div>
|
|
981
|
+
<div style={{ fontSize: '10px', color: '#999', fontStyle: 'italic' }}>{cacheStats.expiredEntries.length > 0 ? 'Active' : 'Empty'}</div>
|
|
982
|
+
</div> */}
|
|
983
|
+
|
|
984
|
+
<div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
985
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#ff9800' }}>{renderCount > 1 ? '' : '○'}</div>
|
|
986
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Performance</div>
|
|
987
|
+
<div style={{ fontSize: '10px', color: '#999', fontStyle: 'italic' }}>{renderCount > 1 ? 'Cached' : 'Loading'}</div>
|
|
988
|
+
</div>
|
|
989
|
+
|
|
990
|
+
<div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
991
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#9c27b0' }}>{cacheStats.totalEntries}/{cacheStats.maxSize}</div>
|
|
992
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Cache Usage</div>
|
|
993
|
+
</div>
|
|
994
|
+
</div>
|
|
995
|
+
|
|
996
|
+
<div style={{ marginBottom: '15px' }}>
|
|
997
|
+
<strong>Last Action:</strong> <span style={{ color: '#1976d2' }}>{lastAction}</span>
|
|
998
|
+
</div>
|
|
999
|
+
|
|
1000
|
+
{/* <div style={{ marginBottom: '15px' }}>
|
|
1001
|
+
<strong>Cached Field Groups:</strong>
|
|
1002
|
+
<div style={{ marginTop: '5px' }}>
|
|
1003
|
+
{cacheStats.expiredEntries.length > 0 ? (
|
|
1004
|
+
cacheStats.expiredEntries.map(key => (
|
|
1005
|
+
<span key={key} style={{
|
|
1006
|
+
display: 'inline-block',
|
|
1007
|
+
margin: '2px 5px 2px 0',
|
|
1008
|
+
padding: '2px 8px',
|
|
1009
|
+
backgroundColor: '#4caf50',
|
|
1010
|
+
color: 'white',
|
|
1011
|
+
borderRadius: '12px',
|
|
1012
|
+
fontSize: '12px'
|
|
1013
|
+
}}>
|
|
1014
|
+
{key}
|
|
1015
|
+
</span>
|
|
1016
|
+
))
|
|
1017
|
+
) : (
|
|
1018
|
+
<span style={{ color: '#666', fontStyle: 'italic' }}>No cached data yet</span>
|
|
1019
|
+
)}
|
|
1020
|
+
</div>
|
|
1021
|
+
</div> */}
|
|
1022
|
+
|
|
1023
|
+
<small style={{ color: '#666' }}>
|
|
1024
|
+
💡 Open browser console to see detailed cache behavior logs.
|
|
1025
|
+
</small>
|
|
1026
|
+
</div>
|
|
1027
|
+
|
|
1028
|
+
<div style={{ display: 'flex', gap: '10px', marginBottom: '20px', flexWrap: 'wrap' }}>
|
|
1029
|
+
<button
|
|
1030
|
+
onClick={() => triggerRender('Manual re-render')}
|
|
1031
|
+
style={{
|
|
1032
|
+
padding: '12px 24px',
|
|
1033
|
+
backgroundColor: '#4caf50',
|
|
1034
|
+
color: 'white',
|
|
1035
|
+
border: 'none',
|
|
1036
|
+
borderRadius: '6px',
|
|
1037
|
+
cursor: 'pointer',
|
|
1038
|
+
fontWeight: 'bold',
|
|
1039
|
+
fontSize: '14px'
|
|
1040
|
+
}}
|
|
1041
|
+
>
|
|
1042
|
+
Render Again
|
|
1043
|
+
</button>
|
|
1044
|
+
|
|
1045
|
+
<button
|
|
1046
|
+
onClick={() => {
|
|
1047
|
+
provider.clearCache();
|
|
1048
|
+
triggerRender('Cache cleared');
|
|
1049
|
+
}}
|
|
1050
|
+
style={{
|
|
1051
|
+
padding: '12px 24px',
|
|
1052
|
+
backgroundColor: '#f44336',
|
|
1053
|
+
color: 'white',
|
|
1054
|
+
border: 'none',
|
|
1055
|
+
borderRadius: '6px',
|
|
1056
|
+
cursor: 'pointer',
|
|
1057
|
+
fontWeight: 'bold',
|
|
1058
|
+
fontSize: '14px'
|
|
1059
|
+
}}
|
|
1060
|
+
>
|
|
1061
|
+
🗋 Clear Cache
|
|
1062
|
+
</button>
|
|
1063
|
+
|
|
1064
|
+
<button
|
|
1065
|
+
onClick={() => {
|
|
1066
|
+
// Reset all metrics
|
|
1067
|
+
setRenderCount(1);
|
|
1068
|
+
setLastAction('Reset all metrics');
|
|
1069
|
+
provider.clearCache();
|
|
1070
|
+
updateCacheStats();
|
|
1071
|
+
}}
|
|
1072
|
+
style={{
|
|
1073
|
+
padding: '12px 24px',
|
|
1074
|
+
backgroundColor: '#9c27b0',
|
|
1075
|
+
color: 'white',
|
|
1076
|
+
border: 'none',
|
|
1077
|
+
borderRadius: '6px',
|
|
1078
|
+
cursor: 'pointer',
|
|
1079
|
+
fontWeight: 'bold',
|
|
1080
|
+
fontSize: '14px'
|
|
1081
|
+
}}
|
|
1082
|
+
>
|
|
1083
|
+
Reset All
|
|
1084
|
+
</button>
|
|
1085
|
+
</div>
|
|
1086
|
+
|
|
1087
|
+
<div style={{
|
|
1088
|
+
padding: '20px',
|
|
1089
|
+
backgroundColor: '#f8f9fa',
|
|
1090
|
+
borderRadius: '8px',
|
|
1091
|
+
marginBottom: '20px'
|
|
1092
|
+
}}>
|
|
1093
|
+
<h3>Cached Data Demo</h3>
|
|
1094
|
+
<p style={{ marginBottom: '15px' }}>The data below is loaded through the DataProvider. Watch the cache metrics as you interact:</p>
|
|
1095
|
+
|
|
1096
|
+
<div key={forceRefresh} style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '15px' }}>
|
|
1097
|
+
<div style={{ padding: '15px', backgroundColor: 'white', borderRadius: '6px', border: '1px solid #ddd' }}>
|
|
1098
|
+
<h4 style={{ marginTop: 0, color: '#1976d2' }}>Company Info</h4>
|
|
1099
|
+
<p><strong>Name:</strong> {t`{{company.name}}`}</p>
|
|
1100
|
+
<p><strong>Slogan:</strong> {t`{{company.slogan}}`}</p>
|
|
1101
|
+
<p><strong>Founded:</strong> {t`{{company.founded}}`}</p>
|
|
1102
|
+
{/* <p><small style={{ color: '#666' }}>Loaded from: {cacheStats.expiredEntries.includes('company') ? ' Cache' : ' Fresh fetch'}</small></p> */}
|
|
1103
|
+
</div>
|
|
1104
|
+
|
|
1105
|
+
<div style={{ padding: '15px', backgroundColor: 'white', borderRadius: '6px', border: '1px solid #ddd' }}>
|
|
1106
|
+
<h4 style={{ marginTop: 0, color: '#4caf50' }}>Features</h4>
|
|
1107
|
+
<p><strong>First:</strong> {t`{{features.0.title}}`}</p>
|
|
1108
|
+
<p><strong>Second:</strong> {t`{{features.1.title}}`}</p>
|
|
1109
|
+
<p><strong>Icon:</strong> {t`{{features.0.icon}}`}</p>
|
|
1110
|
+
{/* <p><small style={{ color: '#666' }}>Loaded from: {cacheStats.expiredEntries.includes('features') ? ' Cache' : ' Fresh fetch'}</small></p> */}
|
|
1111
|
+
</div>
|
|
1112
|
+
</div>
|
|
1113
|
+
</div>
|
|
1114
|
+
|
|
1115
|
+
<div style={{
|
|
1116
|
+
padding: '15px',
|
|
1117
|
+
backgroundColor: '#fff3e0',
|
|
1118
|
+
borderRadius: '6px',
|
|
1119
|
+
fontSize: '14px'
|
|
1120
|
+
}}>
|
|
1121
|
+
<h4 style={{ marginTop: 0 }}> How to Test:</h4>
|
|
1122
|
+
<ol style={{ marginBottom: 0, paddingLeft: '20px' }}>
|
|
1123
|
+
<li><strong>Watch "Cache Usage"</strong> - Shows {cacheStats.totalEntries}/{cacheStats.maxSize} cached items</li>
|
|
1124
|
+
<li><strong>Click "Render Again"</strong> - Forces content reload, updates "Loaded from" indicators</li>
|
|
1125
|
+
<li><strong>Click "Clear Cache"</strong> - Watch cache usage drop to 0/100, then rebuild</li>
|
|
1126
|
+
<li><strong>Check "Cached Field Groups"</strong> - Green badges show what's currently cached</li>
|
|
1127
|
+
<li><strong>Browser console logs</strong> - See JsonDataProvider cache hit/miss messages</li>
|
|
1128
|
+
<li><strong>"Loaded from" indicators</strong> - Shows if data came from cache or fresh fetch </li>
|
|
1129
|
+
</ol>
|
|
1130
|
+
</div>
|
|
1131
|
+
</div>
|
|
1132
|
+
</DataProvider>
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
1135
|
};
|
|
1136
1136
|
|
|
1137
1137
|
/**
|
|
1138
1138
|
* Deep nested property access demonstration with enhanced MUI styling
|
|
1139
1139
|
*/
|
|
1140
1140
|
export const NestedProperties: Story = {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1141
|
+
render: () => {
|
|
1142
|
+
const provider = new JsonDataProvider({
|
|
1143
|
+
data: nestedTestData,
|
|
1144
|
+
enableLogging: true
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
return (
|
|
1148
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
1149
|
+
<Box sx={{ p: 3 }}>
|
|
1150
|
+
<Typography variant="h4" gutterBottom>Deep Nested Property Access</Typography>
|
|
1151
|
+
<Typography variant="body1" paragraph>
|
|
1152
|
+
JsonDataProvider supports deep nested property access using dot notation.
|
|
1153
|
+
</Typography>
|
|
1154
|
+
|
|
1155
|
+
<GridLayout columns={2} spacing={3}>
|
|
1156
|
+
<GridCell>
|
|
1157
|
+
<Card sx={{ bgcolor: 'primary.50' }}>
|
|
1158
|
+
<CardContent>
|
|
1159
|
+
<Typography variant="h6" gutterBottom>Basic Properties</Typography>
|
|
1160
|
+
<Typography variant="body2" paragraph>{t`Company: {{company.name}}`}</Typography>
|
|
1161
|
+
<Typography variant="body2" paragraph>{t`Industry: {{company.profile.industry}}`}</Typography>
|
|
1162
|
+
<Typography variant="body2">{t`Size: {{company.profile.size}}`}</Typography>
|
|
1163
|
+
</CardContent>
|
|
1164
|
+
</Card>
|
|
1165
|
+
</GridCell>
|
|
1166
|
+
|
|
1167
|
+
<GridCell>
|
|
1168
|
+
<Card sx={{ bgcolor: 'success.50' }}>
|
|
1169
|
+
<CardContent>
|
|
1170
|
+
<Typography variant="h6" gutterBottom>Location Details</Typography>
|
|
1171
|
+
<Typography variant="body2" paragraph>{t`City: {{company.profile.location.city}}`}</Typography>
|
|
1172
|
+
<Typography variant="body2" paragraph>{t`State: {{company.profile.location.state}}`}</Typography>
|
|
1173
|
+
<Typography variant="body2" paragraph>{t`Country: {{company.profile.location.country}}`}</Typography>
|
|
1174
|
+
<Typography variant="body2">{t`Timezone: {{company.profile.location.timezone}}`}</Typography>
|
|
1175
|
+
</CardContent>
|
|
1176
|
+
</Card>
|
|
1177
|
+
</GridCell>
|
|
1178
|
+
|
|
1179
|
+
<GridCell>
|
|
1180
|
+
<Card sx={{ bgcolor: 'warning.50' }}>
|
|
1181
|
+
<CardContent>
|
|
1182
|
+
<Typography variant="h6" gutterBottom>Contact Information</Typography>
|
|
1183
|
+
<Typography variant="body2" paragraph>{t`Email: {{company.profile.contact.email}}`}</Typography>
|
|
1184
|
+
<Typography variant="body2" paragraph>{t`Phone: {{company.profile.contact.phone}}`}</Typography>
|
|
1185
|
+
<Typography variant="body2" paragraph>{t`Website: {{company.profile.contact.social.website}}`}</Typography>
|
|
1186
|
+
<Typography variant="body2">{t`Twitter: {{company.profile.contact.social.twitter}}`}</Typography>
|
|
1187
|
+
</CardContent>
|
|
1188
|
+
</Card>
|
|
1189
|
+
</GridCell>
|
|
1190
|
+
|
|
1191
|
+
<GridCell>
|
|
1192
|
+
<Card sx={{ bgcolor: 'secondary.50' }}>
|
|
1193
|
+
<CardContent>
|
|
1194
|
+
<Typography variant="h6" gutterBottom>Business Metrics</Typography>
|
|
1195
|
+
<Typography variant="body2" paragraph>{t`Employees: {{company.metrics.employees}}`}</Typography>
|
|
1196
|
+
<Typography variant="body2" paragraph>{t`Revenue: {{company.metrics.revenue}}`}</Typography>
|
|
1197
|
+
<Typography variant="body2" paragraph>{t`Growth: {{company.metrics.growth}}%`}</Typography>
|
|
1198
|
+
<Typography variant="body2">{t`Founded: {{company.metrics.founded}}`}</Typography>
|
|
1199
|
+
</CardContent>
|
|
1200
|
+
</Card>
|
|
1201
|
+
</GridCell>
|
|
1202
|
+
</GridLayout>
|
|
1203
|
+
|
|
1204
|
+
<Paper elevation={2} sx={{ p: 3, mt: 4 }}>
|
|
1205
|
+
<Typography variant="h6" gutterBottom>Complex Template:</Typography>
|
|
1206
|
+
<Paper variant="outlined" sx={{ p: 2, mt: 2, bgcolor: 'grey.50' }}>
|
|
1207
|
+
{t`{{company.name}} is a {{company.profile.industry}} company based in {{company.profile.location.city}}, {{company.profile.location.state}}. Founded in {{company.metrics.founded}}, we now have {{company.metrics.employees}} employees and generated {{company.metrics.revenue}} in revenue. Contact us at {{company.profile.contact.email}} or visit {{company.profile.contact.social.website}}.`}
|
|
1208
|
+
</Paper>
|
|
1209
|
+
</Paper>
|
|
1210
|
+
</Box>
|
|
1211
|
+
</DataProvider>
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
1214
|
};
|
|
1215
1215
|
|
|
1216
1216
|
/**
|
|
1217
1217
|
* Caching behavior demonstration with side-by-side providers
|
|
1218
1218
|
*/
|
|
1219
1219
|
export const CachingBehavior: Story = {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1220
|
+
render: () => {
|
|
1221
|
+
const dataProvider = new JsonDataProvider({ data: nestedTestData })
|
|
1222
|
+
const fastCacheProvider = new CachedDataProvider(dataProvider, {
|
|
1223
|
+
defaultTTL: 3000, // 3 seconds
|
|
1224
|
+
maxSize: 5,
|
|
1225
|
+
enableLogging: true
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
const slowCacheProvider = new CachedDataProvider(dataProvider, {
|
|
1229
|
+
defaultTTL: 10000, // 10 seconds
|
|
1230
|
+
maxSize: 5,
|
|
1231
|
+
enableLogging: true
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
return (
|
|
1235
|
+
<Box sx={{ p: 3 }}>
|
|
1236
|
+
<Typography variant="h4" gutterBottom>Caching Behavior</Typography>
|
|
1237
|
+
<Typography variant="body1" paragraph>
|
|
1238
|
+
Compare different caching configurations. Check the browser console to see cache logs.
|
|
1239
|
+
</Typography>
|
|
1240
|
+
|
|
1241
|
+
<GridLayout columns={2} spacing={3}>
|
|
1242
|
+
<GridCell>
|
|
1243
|
+
<Typography variant="h6" gutterBottom>Fast Cache (3s timeout)</Typography>
|
|
1244
|
+
<ProviderDemo provider={fastCacheProvider} title="Fast Cache Provider" />
|
|
1245
|
+
</GridCell>
|
|
1246
|
+
<GridCell>
|
|
1247
|
+
<Typography variant="h6" gutterBottom>Slow Cache (10s timeout)</Typography>
|
|
1248
|
+
<ProviderDemo provider={slowCacheProvider} title="Slow Cache Provider" />
|
|
1249
|
+
</GridCell>
|
|
1250
|
+
</GridLayout>
|
|
1251
|
+
|
|
1252
|
+
<Alert severity="info" sx={{ mt: 2 }}>
|
|
1253
|
+
<Typography variant="subtitle2" gutterBottom>💡 Try This:</Typography>
|
|
1254
|
+
<ol>
|
|
1255
|
+
<li>Open browser console to see cache logs</li>
|
|
1256
|
+
<li>Click "Force Refresh" buttons to trigger content loading</li>
|
|
1257
|
+
<li>Notice how fast cache expires content more quickly</li>
|
|
1258
|
+
<li>Click "Clear Cache" to manually invalidate cache</li>
|
|
1259
|
+
</ol>
|
|
1260
|
+
</Alert>
|
|
1261
|
+
</Box>
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
1264
|
};
|
|
1265
1265
|
|
|
1266
1266
|
/**
|
|
1267
1267
|
* Interactive configuration playground with real-time settings
|
|
1268
1268
|
*/
|
|
1269
1269
|
export const ConfigurationPlayground: Story = {
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1270
|
+
render: () => {
|
|
1271
|
+
const [config, setConfig] = useState({
|
|
1272
|
+
cacheTimeout: 5000,
|
|
1273
|
+
maxCacheSize: 10,
|
|
1274
|
+
enableLogging: true
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
const [provider, setProvider] = useState(() => new JsonDataProvider({
|
|
1278
|
+
data: nestedTestData,
|
|
1279
|
+
...config
|
|
1280
|
+
}));
|
|
1281
|
+
|
|
1282
|
+
const updateConfig = (newConfig: Partial<typeof config>) => {
|
|
1283
|
+
const updatedConfig = { ...config, ...newConfig };
|
|
1284
|
+
setConfig(updatedConfig);
|
|
1285
|
+
setProvider(new JsonDataProvider({
|
|
1286
|
+
data: nestedTestData,
|
|
1287
|
+
...updatedConfig
|
|
1288
|
+
}));
|
|
1289
|
+
};
|
|
1290
|
+
|
|
1291
|
+
return (
|
|
1292
|
+
<Box sx={{ p: 3 }}>
|
|
1293
|
+
<Typography variant="h4" gutterBottom>Configuration Playground</Typography>
|
|
1294
|
+
<Typography variant="body1" paragraph>
|
|
1295
|
+
Experiment with different JsonDataProvider configuration options.
|
|
1296
|
+
</Typography>
|
|
1297
|
+
|
|
1298
|
+
<GridLayout spacing={3} equalHeight>
|
|
1299
|
+
<GridCell span={12}>
|
|
1300
|
+
<Alert severity="success" sx={{ mt: 2 }}>
|
|
1301
|
+
<Typography variant="subtitle2" gutterBottom>💡 Tips:</Typography>
|
|
1302
|
+
<ul style={{ margin: 0, paddingLeft: '20px' }}>
|
|
1303
|
+
<li>Lower cache timeout = more frequent cache invalidation</li>
|
|
1304
|
+
<li>Smaller max cache size = more aggressive LRU eviction</li>
|
|
1305
|
+
<li>Enable logging to see cache behavior in console</li>
|
|
1306
|
+
<li>Watch cache stats update in real-time</li>
|
|
1307
|
+
</ul>
|
|
1308
|
+
</Alert>
|
|
1309
|
+
</GridCell>
|
|
1310
|
+
<Card>
|
|
1311
|
+
<CardContent>
|
|
1312
|
+
<Typography variant="h6" gutterBottom>Configuration</Typography>
|
|
1313
|
+
|
|
1314
|
+
<Box sx={{ mb: 3 }}>
|
|
1315
|
+
<Typography gutterBottom>Cache Timeout (ms): {config.cacheTimeout}</Typography>
|
|
1316
|
+
<Slider
|
|
1317
|
+
value={config.cacheTimeout}
|
|
1318
|
+
min={1000}
|
|
1319
|
+
max={30000}
|
|
1320
|
+
step={1000}
|
|
1321
|
+
onChange={(_, value) => updateConfig({ cacheTimeout: value as number })}
|
|
1322
|
+
/>
|
|
1323
|
+
</Box>
|
|
1324
|
+
|
|
1325
|
+
<Box sx={{ mb: 3 }}>
|
|
1326
|
+
<Typography gutterBottom>Max Cache Size: {config.maxCacheSize}</Typography>
|
|
1327
|
+
<Slider
|
|
1328
|
+
value={config.maxCacheSize}
|
|
1329
|
+
min={1}
|
|
1330
|
+
max={50}
|
|
1331
|
+
step={1}
|
|
1332
|
+
onChange={(_, value) => updateConfig({ maxCacheSize: value as number })}
|
|
1333
|
+
/>
|
|
1334
|
+
</Box>
|
|
1335
|
+
|
|
1336
|
+
<FormControlLabel
|
|
1337
|
+
control={
|
|
1338
|
+
<Checkbox
|
|
1339
|
+
checked={config.enableLogging}
|
|
1340
|
+
onChange={(e) => updateConfig({ enableLogging: e.target.checked })}
|
|
1341
|
+
/>
|
|
1342
|
+
}
|
|
1343
|
+
label="Enable Logging"
|
|
1344
|
+
sx={{ mb: 2 }}
|
|
1345
|
+
/>
|
|
1346
|
+
|
|
1347
|
+
<Paper variant="outlined" sx={{ p: 2, bgcolor: 'grey.50' }}>
|
|
1348
|
+
<Typography variant="subtitle2" gutterBottom>Current Config:</Typography>
|
|
1349
|
+
<Typography variant="body2" component="pre" sx={{ fontFamily: 'monospace', fontSize: '0.75rem' }}>
|
|
1350
|
+
{JSON.stringify(config, null, 2)}
|
|
1351
|
+
</Typography>
|
|
1352
|
+
</Paper>
|
|
1353
|
+
</CardContent>
|
|
1354
|
+
</Card>
|
|
1355
|
+
|
|
1356
|
+
<ProviderDemo provider={provider} title="Configured Provider" />
|
|
1357
|
+
</GridLayout>
|
|
1358
|
+
</Box>
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
1361
|
};
|