@crownpeak/dqm-react-component 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +52 -24
  3. package/dist/DQMSidebar.d.ts.map +1 -1
  4. package/dist/ErrorBoundary.d.ts.map +1 -1
  5. package/dist/__tests__/setup.d.ts +1 -0
  6. package/dist/__tests__/setup.d.ts.map +1 -0
  7. package/dist/__tests__/utils.d.ts +145 -0
  8. package/dist/__tests__/utils.d.ts.map +1 -0
  9. package/dist/auth-ui/assets/index-YKFZYENy.js +158 -0
  10. package/dist/auth-ui/index.html +1 -1
  11. package/dist/components/auth/DQMLogin.d.ts.map +1 -1
  12. package/dist/components/auth/index.d.ts +0 -1
  13. package/dist/components/auth/index.d.ts.map +1 -1
  14. package/dist/components/cards/AISummaryCard.d.ts +2 -0
  15. package/dist/components/cards/AISummaryCard.d.ts.map +1 -0
  16. package/dist/components/cards/index.d.ts +1 -0
  17. package/dist/components/cards/index.d.ts.map +1 -1
  18. package/dist/components/common/LanguageSwitch.d.ts +5 -0
  19. package/dist/components/common/LanguageSwitch.d.ts.map +1 -0
  20. package/dist/components/common/LanguageSwitchBase.d.ts +16 -0
  21. package/dist/components/common/LanguageSwitchBase.d.ts.map +1 -0
  22. package/dist/components/common/index.d.ts +1 -0
  23. package/dist/components/common/index.d.ts.map +1 -1
  24. package/dist/components/modals/AISettingsDialog.d.ts +61 -0
  25. package/dist/components/modals/AISettingsDialog.d.ts.map +1 -0
  26. package/dist/components/modals/HighlightModal.d.ts +45 -0
  27. package/dist/components/modals/HighlightModal.d.ts.map +1 -0
  28. package/dist/components/modals/LoginOverlay.d.ts +22 -0
  29. package/dist/components/modals/LoginOverlay.d.ts.map +1 -0
  30. package/dist/components/modals/index.d.ts +9 -0
  31. package/dist/components/modals/index.d.ts.map +1 -0
  32. package/dist/components/renderers/BrowserViewRenderer.d.ts.map +1 -1
  33. package/dist/components/renderers/ShadowDOMRenderer.d.ts.map +1 -1
  34. package/dist/components/sidebar/index.d.ts +1 -0
  35. package/dist/components/sidebar/index.d.ts.map +1 -1
  36. package/dist/context/ai/AIContext.d.ts +13 -0
  37. package/dist/context/ai/AIContext.d.ts.map +1 -0
  38. package/dist/context/ai/index.d.ts +12 -0
  39. package/dist/context/ai/index.d.ts.map +1 -0
  40. package/dist/context/ai/types.d.ts +161 -0
  41. package/dist/context/ai/types.d.ts.map +1 -0
  42. package/dist/context/ai/useAIEngine.d.ts +10 -0
  43. package/dist/context/ai/useAIEngine.d.ts.map +1 -0
  44. package/dist/context/ai/useAISummary.d.ts +10 -0
  45. package/dist/context/ai/useAISummary.d.ts.map +1 -0
  46. package/dist/context/ai/useAITranslation.d.ts +10 -0
  47. package/dist/context/ai/useAITranslation.d.ts.map +1 -0
  48. package/dist/context/ai/useTranslationCache.d.ts +9 -0
  49. package/dist/context/ai/useTranslationCache.d.ts.map +1 -0
  50. package/dist/dqm-widget.esm.js +394 -264
  51. package/dist/dqm-widget.iife.js +76 -25
  52. package/dist/hooks/index.d.ts +10 -0
  53. package/dist/hooks/index.d.ts.map +1 -0
  54. package/dist/hooks/useAnalysis.d.ts +43 -0
  55. package/dist/hooks/useAnalysis.d.ts.map +1 -0
  56. package/dist/hooks/useAuthentication.d.ts +49 -0
  57. package/dist/hooks/useAuthentication.d.ts.map +1 -0
  58. package/dist/hooks/useHighlightActions.d.ts +37 -0
  59. package/dist/hooks/useHighlightActions.d.ts.map +1 -0
  60. package/dist/hooks/useHighlights.d.ts +72 -0
  61. package/dist/hooks/useHighlights.d.ts.map +1 -0
  62. package/dist/html-pages/DQMWidget.d.ts.map +1 -1
  63. package/dist/html-pages/index.d.ts.map +1 -1
  64. package/dist/i18n/auth/de.d.ts +25 -0
  65. package/dist/i18n/auth/de.d.ts.map +1 -0
  66. package/dist/i18n/auth/en.d.ts +26 -0
  67. package/dist/i18n/auth/en.d.ts.map +1 -0
  68. package/dist/i18n/auth/es.d.ts +25 -0
  69. package/dist/i18n/auth/es.d.ts.map +1 -0
  70. package/dist/i18n/auth/index.d.ts +8 -0
  71. package/dist/i18n/auth/index.d.ts.map +1 -0
  72. package/dist/i18n/common/de.d.ts +18 -0
  73. package/dist/i18n/common/de.d.ts.map +1 -0
  74. package/dist/i18n/common/en.d.ts +19 -0
  75. package/dist/i18n/common/en.d.ts.map +1 -0
  76. package/dist/i18n/common/es.d.ts +18 -0
  77. package/dist/i18n/common/es.d.ts.map +1 -0
  78. package/dist/i18n/common/index.d.ts +8 -0
  79. package/dist/i18n/common/index.d.ts.map +1 -0
  80. package/dist/i18n/demo/de.d.ts +104 -0
  81. package/dist/i18n/demo/de.d.ts.map +1 -0
  82. package/dist/i18n/demo/en.d.ts +105 -0
  83. package/dist/i18n/demo/en.d.ts.map +1 -0
  84. package/dist/i18n/demo/es.d.ts +104 -0
  85. package/dist/i18n/demo/es.d.ts.map +1 -0
  86. package/dist/i18n/demo/index.d.ts +8 -0
  87. package/dist/i18n/demo/index.d.ts.map +1 -0
  88. package/dist/i18n/index.d.ts +673 -0
  89. package/dist/i18n/index.d.ts.map +1 -0
  90. package/dist/i18n/sidebar/de.d.ts +89 -0
  91. package/dist/i18n/sidebar/de.d.ts.map +1 -0
  92. package/dist/i18n/sidebar/en.d.ts +90 -0
  93. package/dist/i18n/sidebar/en.d.ts.map +1 -0
  94. package/dist/i18n/sidebar/es.d.ts +89 -0
  95. package/dist/i18n/sidebar/es.d.ts.map +1 -0
  96. package/dist/i18n/sidebar/index.d.ts +8 -0
  97. package/dist/i18n/sidebar/index.d.ts.map +1 -0
  98. package/dist/i18n.d.ts +8 -0
  99. package/dist/i18n.d.ts.map +1 -0
  100. package/dist/index.cjs +61 -31
  101. package/dist/index.cjs.map +1 -1
  102. package/dist/index.d.ts +7 -1
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.html +3 -3
  105. package/dist/index.js +17795 -7252
  106. package/dist/index.js.map +1 -1
  107. package/dist/locale.d.ts +25 -0
  108. package/dist/locale.d.ts.map +1 -0
  109. package/dist/mocks/browser.d.ts +23 -0
  110. package/dist/mocks/browser.d.ts.map +1 -0
  111. package/dist/mocks/handlers.d.ts +32 -0
  112. package/dist/mocks/handlers.d.ts.map +1 -0
  113. package/dist/mocks/index.d.ts +7 -0
  114. package/dist/mocks/index.d.ts.map +1 -0
  115. package/dist/mocks/server.d.ts +24 -0
  116. package/dist/mocks/server.d.ts.map +1 -0
  117. package/dist/server/routes/auth.js +0 -10
  118. package/dist/server/routes/auth.js.map +1 -1
  119. package/dist/store/api/dqmApi.d.ts +1793 -0
  120. package/dist/store/api/dqmApi.d.ts.map +1 -0
  121. package/dist/store/api/index.d.ts +6 -0
  122. package/dist/store/api/index.d.ts.map +1 -0
  123. package/dist/store/index.d.ts +57 -0
  124. package/dist/store/index.d.ts.map +1 -0
  125. package/dist/store/localeSlice.d.ts +6 -0
  126. package/dist/store/localeSlice.d.ts.map +1 -0
  127. package/dist/store/slices/aiSlice.d.ts +134 -0
  128. package/dist/store/slices/aiSlice.d.ts.map +1 -0
  129. package/dist/store/slices/analysisSlice.d.ts +54 -0
  130. package/dist/store/slices/analysisSlice.d.ts.map +1 -0
  131. package/dist/store/slices/authSlice.d.ts +170 -0
  132. package/dist/store/slices/authSlice.d.ts.map +1 -0
  133. package/dist/store/slices/highlightSlice.d.ts +188 -0
  134. package/dist/store/slices/highlightSlice.d.ts.map +1 -0
  135. package/dist/store/slices/index.d.ts +12 -0
  136. package/dist/store/slices/index.d.ts.map +1 -0
  137. package/dist/types.d.ts +27 -8
  138. package/dist/types.d.ts.map +1 -1
  139. package/dist/utils/aiJsonClient.d.ts +23 -0
  140. package/dist/utils/aiJsonClient.d.ts.map +1 -0
  141. package/dist/utils/colors/GenerateCategoryColors.d.ts.map +1 -1
  142. package/dist/utils/logger.d.ts +107 -0
  143. package/dist/utils/logger.d.ts.map +1 -0
  144. package/dist/utils/openaiJsonClient.d.ts +8 -0
  145. package/dist/utils/openaiJsonClient.d.ts.map +1 -0
  146. package/dist/utils/sanitizeHtmlDocument.d.ts +4 -0
  147. package/dist/utils/sanitizeHtmlDocument.d.ts.map +1 -0
  148. package/dist/utils/secureStorage.d.ts +95 -0
  149. package/dist/utils/secureStorage.d.ts.map +1 -0
  150. package/dist/utils/storage.d.ts.map +1 -1
  151. package/dist/utils/translationCache.d.ts +45 -0
  152. package/dist/utils/translationCache.d.ts.map +1 -0
  153. package/dist/utils/translationUtils.d.ts +52 -0
  154. package/dist/utils/translationUtils.d.ts.map +1 -0
  155. package/package.json +48 -10
  156. package/AUTHENTICATION.md +0 -281
  157. package/BACKEND-API.md +0 -1829
  158. package/DEVELOPMENT.md +0 -374
  159. package/EXAMPLES.md +0 -381
  160. package/QUICKSTART.md +0 -207
  161. package/dist/auth-ui/assets/index-CczTRrba.js +0 -158
  162. package/dist/components/auth/OAuth2CallbackHandler.d.ts +0 -15
  163. package/dist/components/auth/OAuth2CallbackHandler.d.ts.map +0 -1
@@ -0,0 +1,52 @@
1
+ import { AnalysisData } from '../types';
2
+ import { JsonChatClient } from './aiJsonClient';
3
+ import { TranslationCache } from './translationCache';
4
+ export type SummaryStats = {
5
+ chunked: boolean;
6
+ chunkCount: number;
7
+ totalFailed: number;
8
+ attempts: number;
9
+ emptyResponses: number;
10
+ fallbackUsed: 'none' | 'chunk' | 'single' | 'tiny' | 'fail';
11
+ modelId?: string;
12
+ targetLang?: string;
13
+ durationMs: number;
14
+ };
15
+ export type TranslationProgress = {
16
+ translatedCheckpoints: number;
17
+ totalCheckpoints: number;
18
+ isPartial: boolean;
19
+ };
20
+ export declare const summarizeDqmResults: (opts: {
21
+ client: JsonChatClient;
22
+ data: AnalysisData;
23
+ targetLanguage: string;
24
+ modelId?: string;
25
+ cache?: TranslationCache;
26
+ signal?: AbortSignal;
27
+ }) => Promise<{
28
+ bullets: string[];
29
+ stats: SummaryStats;
30
+ }>;
31
+ export declare const translateDqmResults: (opts: {
32
+ client: JsonChatClient;
33
+ data: AnalysisData;
34
+ targetLanguage: string;
35
+ modelId: string;
36
+ cache?: TranslationCache;
37
+ computeBudgetMs?: number;
38
+ maxConcurrentBatches?: number;
39
+ maxItemsPerBatch?: number;
40
+ forceSerial?: boolean;
41
+ onProgress?: (progress: TranslationProgress) => void;
42
+ onBatchStatus?: (info: {
43
+ ids: string[];
44
+ status: "translating" | "done";
45
+ }) => void;
46
+ onPartialResult?: (data: AnalysisData) => void;
47
+ signal?: AbortSignal;
48
+ }) => Promise<{
49
+ data: AnalysisData;
50
+ progress: TranslationProgress;
51
+ }>;
52
+ //# sourceMappingURL=translationUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translationUtils.d.ts","sourceRoot":"","sources":["../../src/utils/translationUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAQ3D,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAoPF,MAAM,MAAM,mBAAmB,GAAG;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AA0DF,eAAO,MAAM,mBAAmB,GAAU,MAAM;IAC9C,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAgXrD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAU,MAAM;IAC9C,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAClF,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KAAG,OAAO,CAAC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAA;CAAE,CA6kBhE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crownpeak/dqm-react-component",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "private": false,
5
5
  "description": "A React component for Crownpeak Digital Quality Management (DQM) integration",
6
6
  "type": "module",
@@ -58,10 +58,10 @@
58
58
  },
59
59
  "homepage": "https://github.com/Crownpeak/dqm-react-component#readme",
60
60
  "scripts": {
61
- "dev": "concurrently \"npm run dev:client\" \"npm run dev:server\"",
62
- "dev:client": "vite",
63
- "dev:server": "REDIS_URL=redis://localhost:6379 tsx watch server/index.ts",
64
- "dev:auth-ui": "cd server-ui && vite",
61
+ "dev": "npm run build:auth-ui && npm run dev:client",
62
+ "dev:client": "vite --host 0.0.0.0",
63
+ "dev:server": "concurrently \"redis-server\" \"REDIS_URL=redis://localhost:6379 tsx watch server/index.ts\"",
64
+ "dev:auth-ui": "cd server-ui && vite --host 0.0.0.0",
65
65
  "build": "npm run build:lib && npm run build:widget && npm run build:server && npm run build:auth-ui",
66
66
  "build:lib": "tsc && vite build --mode library",
67
67
  "build:widget": "vite build --mode widget && cp src/html-pages/dqm-widget.d.ts dist/",
@@ -70,10 +70,30 @@
70
70
  "start": "npm run build && concurrently \"npm run start:server\" \"vite\"",
71
71
  "start:server": "REDIS_URL=redis://localhost:6379 node dist/server/index.js",
72
72
  "serve:widget": "npx serve -l 4173 -c serve.json",
73
- "prepublishOnly": "npm run build && npm run lint",
73
+ "prepublishOnly": "npm run build && npm run lint && npm run test:ci",
74
74
  "lint": "eslint . || true",
75
- "preview": "vite preview --host"
75
+ "preview": "vite preview --host",
76
+ "test": "vitest",
77
+ "test:ui": "vitest --ui",
78
+ "test:run": "vitest run",
79
+ "test:coverage": "vitest run --coverage",
80
+ "test:ci": "vitest run --reporter=verbose",
81
+ "test:e2e": "playwright test",
82
+ "test:e2e:ui": "playwright test --ui",
83
+ "test:e2e:headed": "playwright test --headed",
84
+ "test:e2e:debug": "playwright test --debug",
85
+ "wiki:build": "./scripts/wiki-build.sh",
86
+ "wiki:deploy": "./scripts/wiki-deploy.sh",
87
+ "setVersion": "npm version --workspaces --no-git-tag-version",
88
+ "licenses:generate": "generate-license-file --config .glfrc.json",
89
+ "licenses:check": "license-checker --onlyAllow 'MIT;ISC;Apache-2.0;BSD-2-Clause;BSD-3-Clause;0BSD;Unlicense;CC0-1.0;CC-BY-3.0;CC-BY-4.0;Python-2.0;BlueOak-1.0.0;Zlib;WTFPL' --production",
90
+ "licenses:check:all": "npm run licenses:check && npm run licenses:check --prefix mcp-server",
91
+ "licenses:check:ci": "npm run licenses:check:all || (echo 'License check failed! See above for incompatible licenses.' && exit 1)",
92
+ "prepare": "husky"
76
93
  },
94
+ "workspaces": [
95
+ "mcp-server"
96
+ ],
77
97
  "peerDependencies": {
78
98
  "@mui/icons-material": ">=5.0.0",
79
99
  "@mui/material": ">=5.0.0",
@@ -83,26 +103,40 @@
83
103
  "dependencies": {
84
104
  "@emotion/react": "^11.14.0",
85
105
  "@emotion/styled": "^11.14.1",
106
+ "@reduxjs/toolkit": "^2.3.0",
86
107
  "@types/ioredis": "^5.0.0",
108
+ "@webcontainer/env": "^1.1.1",
87
109
  "axios": "^1.13.2",
88
110
  "chroma-js": "^3.2.0",
89
111
  "cors": "^2.8.5",
90
112
  "dompurify": "^3.3.0",
113
+ "dotenv": "^17.2.3",
91
114
  "express": "^5.2.1",
92
115
  "framer-motion": "^12.23.25",
93
116
  "helmet": "^8.1.0",
94
117
  "html-react-parser": "^5.2.10",
118
+ "i18next": "^23.16.8",
95
119
  "ioredis": "^5.8.2",
96
- "lodash.sortby": "^4.7.0"
120
+ "lodash.sortby": "^4.7.0",
121
+ "react-i18next": "^15.1.0",
122
+ "react-redux": "^9.2.0"
97
123
  },
98
124
  "devDependencies": {
99
125
  "@codemirror/lang-html": "^6.4.11",
100
126
  "@codemirror/theme-one-dark": "^6.1.3",
101
127
  "@eslint/js": "^9.39.1",
128
+ "generate-license-file": "^3.5.1",
129
+ "husky": "^9.1.7",
130
+ "license-checker": "^25.0.1",
102
131
  "@mui/icons-material": "^7.3.6",
103
132
  "@mui/material": "^7.3.6",
104
133
  "@mui/styled-engine": "^7.3.6",
105
134
  "@mui/system": "^7.3.6",
135
+ "@playwright/test": "^1.50.0",
136
+ "@testing-library/dom": "^10.4.1",
137
+ "@testing-library/jest-dom": "^6.6.0",
138
+ "@testing-library/react": "^16.0.0",
139
+ "@testing-library/user-event": "^14.5.0",
106
140
  "@types/chroma-js": "^3.1.2",
107
141
  "@types/cors": "^2.8.19",
108
142
  "@types/dompurify": "^3.2.0",
@@ -113,13 +147,16 @@
113
147
  "@types/react-dom": "^19.2.3",
114
148
  "@uiw/react-codemirror": "^4.25.3",
115
149
  "@vitejs/plugin-react-swc": "^4.2.2",
150
+ "@vitest/coverage-v8": "^2.1.0",
151
+ "@vitest/ui": "^2.1.0",
116
152
  "concurrently": "^9.2.1",
117
- "dotenv": "^17.2.3",
118
153
  "eslint": "^9.39.1",
119
154
  "eslint-plugin-react-hooks": "^7.0.1",
120
155
  "eslint-plugin-react-refresh": "^0.4.24",
121
156
  "globals": "^16.5.0",
157
+ "jsdom": "^25.0.0",
122
158
  "magic-string": "^0.30.21",
159
+ "msw": "^2.4.0",
123
160
  "react": "^19.2.1",
124
161
  "react-dom": "^19.2.1",
125
162
  "terser": "^5.44.1",
@@ -127,7 +164,8 @@
127
164
  "typescript": "~5.9.3",
128
165
  "typescript-eslint": "^8.48.1",
129
166
  "vite": "^7.2.7",
130
- "vite-plugin-dts": "^4.5.4"
167
+ "vite-plugin-dts": "^4.5.4",
168
+ "vitest": "^2.1.0"
131
169
  },
132
170
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
133
171
  }
package/AUTHENTICATION.md DELETED
@@ -1,281 +0,0 @@
1
- # DQM Authentication Configuration Examples
2
-
3
- This document shows different ways to configure authentication for the DQM Sidebar component.
4
-
5
- ## 1. Direct Credentials (Simplest)
6
-
7
- Pass API credentials directly as props:
8
-
9
- ```tsx
10
- import { DQMSidebar } from '@crownpeak/dqm-react-component';
11
-
12
- function App() {
13
- const [open, setOpen] = useState(false);
14
-
15
- return (
16
- <DQMSidebar
17
- open={open}
18
- onClose={() => setOpen(false)}
19
- onOpen={() => setOpen(true)}
20
- config={{
21
- apiKey: process.env.REACT_APP_DQM_API_KEY,
22
- websiteId: process.env.REACT_APP_DQM_WEBSITE_ID,
23
- }}
24
- />
25
- );
26
- }
27
- ```
28
-
29
- ## 2. LocalStorage (Default Behavior)
30
-
31
- If no credentials are provided via props, the component will check `localStorage` and show a login form if credentials are missing:
32
-
33
- ```tsx
34
- import { DQMSidebar } from '@crownpeak/dqm-react-component';
35
-
36
- function App() {
37
- const [open, setOpen] = useState(false);
38
-
39
- // On first open, user will see login form
40
- // Credentials are stored in localStorage after successful login
41
- return (
42
- <DQMSidebar
43
- open={open}
44
- onClose={() => setOpen(false)}
45
- onOpen={() => setOpen(true)}
46
- config={{
47
- useLocalStorage: true, // Default: true
48
- }}
49
- />
50
- );
51
- }
52
- ```
53
-
54
- ## 3. Backend Authentication (Custom Token Exchange)
55
-
56
- Use your own Express.js backend to manage credentials:
57
-
58
- ```tsx
59
- import { DQMSidebar } from '@crownpeak/dqm-react-component';
60
-
61
- function App() {
62
- const [open, setOpen] = useState(false);
63
-
64
- return (
65
- <DQMSidebar
66
- open={open}
67
- onClose={() => setOpen(false)}
68
- onOpen={() => setOpen(true)}
69
- config={{
70
- authBackendUrl: 'https://api.yourcompany.com',
71
- useLocalStorage: true, // Optional: cache credentials
72
- }}
73
- onAuthSuccess={(credentials) => {
74
- console.log('Authenticated:', credentials);
75
- }}
76
- onAuthError={(error) => {
77
- console.error('Auth failed:', error);
78
- }}
79
- />
80
- );
81
- }
82
- ```
83
-
84
- ### Backend API Requirements
85
-
86
- Your backend must implement this endpoint:
87
-
88
- ```typescript
89
- // POST /auth/token
90
- // Response:
91
- {
92
- "apiKey": "your-dqm-api-key",
93
- "websiteId": "your-website-id"
94
- }
95
- ```
96
-
97
- ## 4. OAuth2 Flow
98
-
99
- For enterprise SSO integration:
100
-
101
- ```tsx
102
- import { DQMSidebar } from '@crownpeak/dqm-react-component';
103
-
104
- function App() {
105
- const [open, setOpen] = useState(false);
106
-
107
- // TODO: verify that your backend supports OAuth2 token exchange
108
-
109
- return (
110
- <DQMSidebar
111
- open={open}
112
- onClose={() => setOpen(false)}
113
- onOpen={() => setOpen(true)}
114
- config={{
115
- authBackendUrl: 'https://api.yourcompany.com',
116
- oauth2Config: {
117
- authUrl: 'https://oauth.yourcompany.com/authorize',
118
- tokenUrl: 'https://oauth.yourcompany.com/token',
119
- clientId: 'your-oauth-client-id',
120
- redirectUri: window.location.origin + '/dqm/callback',
121
- scope: 'dqm:read',
122
- },
123
- }}
124
- />
125
- );
126
- }
127
- ```
128
-
129
- ### OAuth2 Backend Requirements
130
-
131
- Your backend must implement:
132
-
133
- ```typescript
134
- // POST /auth/oauth2/callback
135
- // Body: { code: string, redirectUri: string }
136
- // Response:
137
- {
138
- "apiKey": "your-dqm-api-key",
139
- "websiteId": "your-website-id"
140
- }
141
- ```
142
-
143
- ## 5. Hybrid Configuration
144
-
145
- Combine multiple authentication methods with priority:
146
-
147
- ```tsx
148
- import { DQMSidebar } from '@crownpeak/dqm-react-component';
149
-
150
- function App() {
151
- const [open, setOpen] = useState(false);
152
-
153
- return (
154
- <DQMSidebar
155
- open={open}
156
- onClose={() => setOpen(false)}
157
- onOpen={() => setOpen(true)}
158
- config={{
159
- // Priority 1: Direct credentials (if provided)
160
- apiKey: process.env.REACT_APP_DQM_API_KEY,
161
- websiteId: process.env.REACT_APP_DQM_WEBSITE_ID,
162
-
163
- // Priority 2: LocalStorage (if no props provided)
164
- useLocalStorage: true,
165
-
166
- // Priority 3: Backend authentication (fallback)
167
- authBackendUrl: 'https://api.yourcompany.com',
168
- oauth2Config: {
169
- authUrl: 'https://oauth.yourcompany.com/authorize',
170
- tokenUrl: 'https://oauth.yourcompany.com/token',
171
- clientId: 'your-oauth-client-id',
172
- redirectUri: window.location.origin + '/dqm/callback',
173
- },
174
- }}
175
- onAuthSuccess={(credentials) => {
176
- // Optional: Send to analytics
177
- analytics.track('DQM Auth Success');
178
- }}
179
- />
180
- );
181
- }
182
- ```
183
-
184
- ## Express.js Backend Example
185
-
186
- Here's a complete Express.js backend example:
187
-
188
- ```typescript
189
- import express from 'express';
190
- import axios from 'axios';
191
-
192
- const app = express();
193
- app.use(express.json());
194
-
195
- // Simple token exchange (custom session-based)
196
- app.post('/auth/token', async (req, res) => {
197
- try {
198
- // Verify user session (implement your own logic)
199
- if (!req.session?.userId) {
200
- return res.status(401).json({ error: 'Not authenticated' });
201
- }
202
-
203
- // Fetch user's DQM credentials from your database
204
- const user = await database.users.findById(req.session.userId);
205
-
206
- res.json({
207
- apiKey: user.dqmApiKey,
208
- websiteId: user.dqmWebsiteId,
209
- });
210
- } catch (error) {
211
- res.status(500).json({ error: 'Internal server error' });
212
- }
213
- });
214
-
215
- // OAuth2 callback handler
216
- app.post('/auth/oauth2/callback', async (req, res) => {
217
- const { code, redirectUri } = req.body;
218
-
219
- try {
220
- // Exchange authorization code for tokens
221
- const tokenResponse = await axios.post('https://oauth.yourcompany.com/token', {
222
- grant_type: 'authorization_code',
223
- code,
224
- redirect_uri: redirectUri,
225
- client_id: process.env.OAUTH_CLIENT_ID,
226
- client_secret: process.env.OAUTH_CLIENT_SECRET,
227
- });
228
-
229
- const { access_token } = tokenResponse.data;
230
-
231
- // Use access token to fetch user's DQM credentials
232
- const userInfo = await axios.get('https://api.yourcompany.com/user/dqm-credentials', {
233
- headers: { Authorization: `Bearer ${access_token}` },
234
- });
235
-
236
- res.json({
237
- apiKey: userInfo.data.apiKey,
238
- websiteId: userInfo.data.websiteId,
239
- });
240
- } catch (error) {
241
- res.status(500).json({ error: 'OAuth2 flow failed' });
242
- }
243
- });
244
-
245
- app.listen(3000, () => {
246
- console.log('DQM Auth Backend running on port 3000');
247
- });
248
- ```
249
-
250
- ## Security Best Practices
251
-
252
- 1. **Never expose API keys in client-side code** for production
253
- 2. **Use HTTPS** for all authentication endpoints
254
- 3. **Implement CSRF protection** for OAuth2 flows
255
- 4. **Validate redirect URIs** in OAuth2 configuration
256
- 5. **Use short-lived sessions** and implement token refresh
257
- 6. **Log authentication events** for security monitoring
258
- 7. **Rate limit** authentication endpoints
259
-
260
- ## TypeScript Support
261
-
262
- All configuration options are fully typed:
263
-
264
- ```tsx
265
- import type { DQMConfig, OAuth2Config } from '@crownpeak/dqm-react-component';
266
-
267
- const config: DQMConfig = {
268
- apiKey: '...',
269
- websiteId: '...',
270
- authBackendUrl: '...',
271
- oauth2Config: {
272
- authUrl: '...',
273
- tokenUrl: '...',
274
- clientId: '...',
275
- redirectUri: '...',
276
- scope: 'dqm:read',
277
- },
278
- useLocalStorage: true,
279
- apiEndpoint: 'https://api.crownpeak.net/dqm-cms/v1', // Optional: custom endpoint
280
- };
281
- ```