openstack-uicore-foundation 5.0.22 → 6.0.0-beta.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/.claude/settings.local.json +13 -0
- package/lib/components/attendance-tracker.js.map +1 -1
- package/lib/components/clock.js.map +1 -1
- package/lib/components/extra-questions.js.map +1 -1
- package/lib/components/forms/simple-form.js.map +1 -1
- package/lib/components/free-text-search.js.map +1 -1
- package/lib/components/google-map.js.map +1 -1
- package/lib/components/index.js +1 -1
- package/lib/components/index.js.map +1 -1
- package/lib/components/inputs/access-levels-input.js.map +1 -1
- package/lib/components/inputs/attendee-input.js.map +1 -1
- package/lib/components/inputs/company-input-v2.js +1 -1
- package/lib/components/inputs/company-input-v2.js.map +1 -1
- package/lib/components/inputs/company-input.js.map +1 -1
- package/lib/components/inputs/country-dropdown.js.map +1 -1
- package/lib/components/inputs/country-input.js.map +1 -1
- package/lib/components/inputs/event-input.js.map +1 -1
- package/lib/components/inputs/group-input.js.map +1 -1
- package/lib/components/inputs/language-input.js.map +1 -1
- package/lib/components/inputs/member-input.js.map +1 -1
- package/lib/components/inputs/organization-input.js.map +1 -1
- package/lib/components/inputs/promocode-input.js.map +1 -1
- package/lib/components/inputs/registration-company-input.js.map +1 -1
- package/lib/components/inputs/speaker-input.js.map +1 -1
- package/lib/components/inputs/sponsor-input.js.map +1 -1
- package/lib/components/inputs/summit-input.js.map +1 -1
- package/lib/components/inputs/tag-input.js.map +1 -1
- package/lib/components/inputs/ticket-types-input.js.map +1 -1
- package/lib/components/inputs/upload-input-v2.js.map +1 -1
- package/lib/components/inputs/upload-input-v3.js +1 -1
- package/lib/components/inputs/upload-input-v3.js.map +1 -1
- package/lib/components/mui/cards/inline-card.js.map +1 -1
- package/lib/components/mui/cards/table-card.js.map +1 -1
- package/lib/components/mui/cards.js.map +1 -1
- package/lib/components/mui/form-item-table.js +1 -1
- package/lib/components/mui/form-item-table.js.map +1 -1
- package/lib/components/mui/formik-inputs/additional-input-list.js +1 -1
- package/lib/components/mui/formik-inputs/additional-input-list.js.map +1 -1
- package/lib/components/mui/formik-inputs/additional-input.js +1 -1
- package/lib/components/mui/formik-inputs/additional-input.js.map +1 -1
- package/lib/components/mui/formik-inputs/async-select.js +1 -1
- package/lib/components/mui/formik-inputs/async-select.js.map +1 -1
- package/lib/components/mui/formik-inputs/company-input.js +1 -1
- package/lib/components/mui/formik-inputs/company-input.js.map +1 -1
- package/lib/components/mui/formik-inputs/discount-field.js +1 -1
- package/lib/components/mui/formik-inputs/discount-field.js.map +1 -1
- package/lib/components/mui/formik-inputs/file-size-field.js +1 -1
- package/lib/components/mui/formik-inputs/file-size-field.js.map +1 -1
- package/lib/components/mui/formik-inputs/item-price-tiers.js +1 -1
- package/lib/components/mui/formik-inputs/item-price-tiers.js.map +1 -1
- package/lib/components/mui/formik-inputs/price-field.js +1 -1
- package/lib/components/mui/formik-inputs/price-field.js.map +1 -1
- package/lib/components/mui/formik-inputs/quantity-field.js +1 -1
- package/lib/components/mui/formik-inputs/quantity-field.js.map +1 -1
- package/lib/components/mui/formik-inputs/sponsor-input.js +1 -1
- package/lib/components/mui/formik-inputs/sponsor-input.js.map +1 -1
- package/lib/components/mui/formik-inputs/sponsorship-input.js +1 -1
- package/lib/components/mui/formik-inputs/sponsorship-input.js.map +1 -1
- package/lib/components/mui/formik-inputs/sponsorship-summit-select.js.map +1 -1
- package/lib/components/mui/formik-inputs/summit-addon-select.js.map +1 -1
- package/lib/components/mui/formik-inputs/textfield.js +1 -1
- package/lib/components/mui/formik-inputs/textfield.js.map +1 -1
- package/lib/components/mui/formik-inputs/upload.js +1 -1
- package/lib/components/mui/formik-inputs/upload.js.map +1 -1
- package/lib/components/mui/item-settings-modal.js +1 -1
- package/lib/components/mui/item-settings-modal.js.map +1 -1
- package/lib/components/mui/menu-button.js +1 -1
- package/lib/components/mui/menu-button.js.map +1 -1
- package/lib/components/mui/snackbar-notification.js.map +1 -1
- package/lib/components/mui/sponsor-addon-select.js.map +1 -1
- package/lib/components/mui/sponsor-order-grid.js.map +1 -1
- package/lib/components/mui/stripe-payment.js.map +1 -1
- package/lib/components/mui/summit-addon-select.js.map +1 -1
- package/lib/components/mui/summits-dropdown.js.map +1 -1
- package/lib/components/mui/table/extra-rows.js.map +1 -1
- package/lib/components/mui/upload-dialog.js +1 -1
- package/lib/components/mui/upload-dialog.js.map +1 -1
- package/lib/components/schedule-builder-view.js.map +1 -1
- package/lib/components/sponsored-project-input.js.map +1 -1
- package/lib/components/table-editable.js.map +1 -1
- package/lib/i18n.js.map +1 -1
- package/lib/security/abstract-auth-callback-route-v2.js.map +1 -1
- package/lib/security/abstract-auth-callback-route.js.map +1 -1
- package/lib/security/actions.js.map +1 -1
- package/lib/security/methods.js.map +1 -1
- package/lib/security/reducers.js.map +1 -1
- package/lib/security/session-checker.js.map +1 -1
- package/lib/utils/actions.js.map +1 -1
- package/lib/utils/methods.js.map +1 -1
- package/lib/utils/query-actions.js.map +1 -1
- package/lib/utils/questions-set.js.map +1 -1
- package/package.json +16 -16
- package/.claude/rules/openstack-uicore-foundation-components.md +0 -62
- package/.claude/rules/openstack-uicore-foundation-project.md +0 -64
- package/.claude/rules/openstack-uicore-foundation-security.md +0 -39
- package/.codegraph/config.json +0 -140
- package/docs/plans/2026-04-09-showconfirmdialog-react16-compat.md +0 -83
- package/docs/plans/2026-04-22-dropzone-pooling-ux.md +0 -129
- package/docs/plans/2026-04-23-uploadv3-duplicate-file-max-reached.md +0 -109
- package/docs/plans/2026-04-23-uploadv3-premature-complete-on-202.md +0 -99
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils/questions-set.js","mappings":"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","sources":["webpack://openstack-uicore-foundation/webpack/universalModuleDefinition","webpack://openstack-uicore-foundation/./src/utils/methods.js","webpack://openstack-uicore-foundation/external commonjs \"@babel/runtime/helpers/defineProperty\"","webpack://openstack-uicore-foundation/external commonjs \"moment-timezone\"","webpack://openstack-uicore-foundation/external commonjs \"urijs\"","webpack://openstack-uicore-foundation/webpack/bootstrap","webpack://openstack-uicore-foundation/webpack/runtime/compat get default export","webpack://openstack-uicore-foundation/webpack/runtime/define property getters","webpack://openstack-uicore-foundation/webpack/runtime/hasOwnProperty shorthand","webpack://openstack-uicore-foundation/webpack/runtime/make namespace object","webpack://openstack-uicore-foundation/./src/utils/questions-set.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"openstack-uicore-foundation\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"openstack-uicore-foundation\"] = factory();\n\telse\n\t\troot[\"openstack-uicore-foundation\"] = factory();\n})(this, () => {\nreturn ","/**\n * Copyright 2018 OpenStack Foundation\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n **/\n\nimport moment from 'moment-timezone';\nimport URI from \"urijs\";\n\nexport const findElementPos = (obj) => {\n var curtop = -70;\n if (obj.offsetParent) {\n do {\n curtop += obj.offsetTop;\n } while (obj = obj.offsetParent);\n return [curtop];\n }\n};\n\nexport const epochToMoment = (atime) => {\n if(!atime) return atime;\n atime = atime * 1000;\n return moment(atime);\n};\n\nexport const epochToMomentTimeZone = (atime, time_zone) => {\n if(!atime) return atime;\n atime = atime * 1000;\n return moment(atime).tz(time_zone);\n};\n\nexport const formatEpoch = (atime, format = 'M/D/YYYY h:mm a') => {\n if(!atime) return atime;\n return epochToMoment(atime).format(format);\n};\n\nexport const parseLocationHour = (hour) => {\n let parsedHour = hour.toString();\n if(parsedHour.length < 4) parsedHour = `0${parsedHour}`;\n parsedHour = parsedHour.match(/.{2}/g);\n parsedHour = parsedHour.join(':');\n return parsedHour;\n}\n\nexport const objectToQueryString = (obj) => {\n var str = \"\";\n for (var key in obj) {\n if (str != \"\") {\n str += \"&\";\n }\n str += key + \"=\" + encodeURIComponent(obj[key]);\n }\n\n return str;\n};\n\nexport const getBackURL = () => {\n let url = URI(window.location.href);\n let query = url.search(true);\n let fragment = url.fragment();\n let backUrl = query.hasOwnProperty('BackUrl') ? query['BackUrl'] : null;\n if(backUrl != null && fragment != null && fragment != ''){\n backUrl += `#${fragment}`;\n }\n return backUrl;\n};\n\nexport const toSlug = (text) =>{\n text = text.toLowerCase();\n return text.replace(/[^a-zA-Z0-9]+/g,'_');\n}\n\nexport const getAuthCallback = () => {\n if(typeof window !== 'undefined') {\n return `${window.location.origin}/auth/callback`;\n }\n return null;\n};\n\nexport const getCurrentLocation = () => {\n let location = '';\n if(typeof window !== 'undefined') {\n location = window.location;\n // check if we are on iframe\n if (window.top)\n location = window.top.location;\n }\n return location;\n};\n\nexport const getOrigin = () => {\n if(typeof window !== 'undefined') {\n return window.location.origin;\n }\n return null;\n};\n\nexport const getCurrentPathName = () => {\n if(typeof window !== 'undefined') {\n return window.location.pathname;\n }\n return null;\n};\n\nexport const getCurrentHref = () => {\n if(typeof window !== 'undefined') {\n return window.location.href;\n }\n return null;\n};\n\nexport const getAllowedUserGroups = () => {\n if(typeof window !== 'undefined') {\n return window.ALLOWED_USER_GROUPS || '';\n }\n return null;\n};\n\nexport const buildAPIBaseUrl = (relativeUrl) => {\n if(typeof window !== 'undefined'){\n return `${window.API_BASE_URL}${relativeUrl}`;\n }\n return null``;\n};\n\nexport const putOnLocalStorage = (key, value) => {\n if(typeof window !== 'undefined') {\n window.localStorage.setItem(key, value);\n }\n};\n\nexport const getFromLocalStorage = (key, removeIt) => {\n if(typeof window !== 'undefined') {\n let val = window.localStorage.getItem(key);\n if(removeIt){\n console.log(`getFromLocalStorage removing key ${key}`);\n removeFromLocalStorage(key);\n }\n return val;\n }\n return null;\n};\n\nexport const removeFromLocalStorage = (key) => {\n if(typeof window !== 'undefined') {\n window.localStorage.removeItem(key);\n }\n}\n\nexport const isClearingSessionState = () => {\n if(typeof window !== 'undefined') {\n return window.clearing_session_state;\n }\n return false;\n};\n\nexport const setSessionClearingState = (val) => {\n if(typeof window !== 'undefined') {\n window.clearing_session_state = val;\n }\n};\n\nexport const getCurrentUserLanguage = () => {\n let language = 'en';\n if(typeof navigator !== 'undefined') {\n language = (navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage;\n }\n return language;\n};\n\nexport const scrollToError = (errors) => {\n if(Object.keys(errors).length > 0) {\n const firstError = Object.keys(errors)[0];\n const firstNode = document.getElementById(firstError);\n if (firstNode) window.scrollTo(0, findElementPos(firstNode));\n }\n};\n\nexport const hasErrors = (field, errors) => {\n if(field in errors) {\n return errors[field];\n }\n return '';\n};\n\nexport const shallowEqual = (object1, object2) => {\n const keys1 = Object.keys(object1);\n const keys2 = Object.keys(object2);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (let key of keys1) {\n if (object1[key] !== object2[key]) {\n return false;\n }\n }\n\n return true;\n};\n\nexport const arraysEqual = (a1, a2) =>\n a1.length === a2.length && a1.every((o, idx) => shallowEqual(o, a2[idx]));\n\nexport const isEmpty = (obj) => {\n return Object.keys(obj).length === 0;\n};\n\n\nexport const base64URLEncode = (str) => {\n return str\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n}\n\nexport const retryPromise = async (\n cb,\n maxNumberOfRetries = 3\n) => {\n for (let i = 0; i < maxNumberOfRetries; i++) {\n if (await cb()) {\n return true;\n }\n }\n\n return false;\n}\n\nexport const getTimeServiceUrl = () => {\n if(typeof window !== 'undefined') {\n return window.TIMEINTERVALSINCE1970_API_URL || process.env.TIMEINTERVALSINCE1970_API_URL;\n }\n return null;\n};\n\nexport const getEventLocation = (event, summitVenueCount, summitShowLocDate = null, nowUtc = null) => {\n const shouldShowVenues = (summitShowLocDate && nowUtc) ? summitShowLocDate * 1000 < nowUtc : true;\n const locationName = [];\n const { location } = event;\n\n if (!shouldShowVenues) return 'TBA';\n\n if (!location) return 'TBA';\n\n if (summitVenueCount > 1 && location.venue?.name) locationName.push(location.venue.name);\n if (location.floor?.name) locationName.push(location.floor.name);\n if (location.name) locationName.push(location.name);\n\n return locationName.length > 0 ? locationName.join(' - ') : 'TBA';\n};\n\nexport const getEventHosts = (event) => {\n let hosts = [];\n if (event.speakers?.length > 0) {\n hosts = [...event.speakers];\n }\n if (event.moderator) hosts.push(event.moderator);\n\n return hosts;\n};\n\nconst loadImage = async url => {\n const img = document.createElement('img')\n img.src = url\n img.crossOrigin = 'anonymous'\n\n return new Promise((resolve, reject) => {\n img.onload = () => resolve(img)\n img.onerror = reject\n })\n}\n\nexport const convertSVGtoImg = async (svgUrl) => {\n const img = await loadImage(svgUrl)\n const newWidth = 100\n const newHeight = Math.floor(img.naturalHeight * 100 / img.naturalWidth)\n\n const canvas = document.createElement('canvas')\n canvas.width = newWidth\n canvas.height = newHeight\n canvas.getContext('2d').drawImage(img, 0, 0, newWidth, newHeight)\n\n const url = await canvas.toDataURL(`image/png`, 1.0)\n console.log(url, newWidth, newHeight);\n return {url, width: newWidth, height: newHeight}\n}\n\nexport const isRateEnabled = (value) =>\n value !== null && value !== undefined && value !== \"\";\n\n/**\n * Returns true if value is null, undefined, empty/whitespace string,\n * empty array, or empty object.\n */\nexport const empty = (value) => {\n if (value === null || value === undefined) return true;\n if (typeof value === \"string\") return value.trim().length === 0;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === \"object\") return Object.keys(value).length === 0;\n return false;\n};\n\nexport const isSentryInitialized = () => typeof window !== \"undefined\" && !!window.SENTRY_DSN;\n","module.exports = require(\"@babel/runtime/helpers/defineProperty\");","module.exports = require(\"moment-timezone\");","module.exports = require(\"urijs\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export const CheckBoxQuestionType = 'CheckBox';\nexport const ComboBoxQuestionType = 'ComboBox'\nexport const CheckBoxListQuestionType = 'CheckBoxList';\nexport const RadioButtonListQuestionType = 'RadioButtonList';\nexport const AllowedMultipleValueQuestionType = [ComboBoxQuestionType, CheckBoxListQuestionType, RadioButtonListQuestionType];\nexport const AnswerValuesOperator_And = 'And';\nexport const AnswerValuesOperator_Or = 'Or';\nexport const VisibilityCondition_Equal = 'Equal';\nexport const VisibilityCondition_NotEqual = 'NotEqual';\nexport const Visibility_Visible = 'Visible';\nexport const MainQuestionClassType = 'MainQuestion';\nimport {toSlug} from \"./methods\";\n\nexport default class QuestionsSet {\n\n constructor(questions, answers = []) {\n this.questions = questions;\n this.originalAnswers = answers\n this.answers = [];\n // map answers to associate array\n for (let a of this.originalAnswers)\n this.answers[a.question_id] = a;\n this.questionByName = {}\n this.questionById = {}\n // associative array ( rule id , rule);\n this.rules = {};\n this._parseQuestions();\n }\n\n _parseQuestion = (q) => {\n this.questionByName[toSlug(q.name)] = q;\n this.questionById[parseInt(q.id)] = q;\n if(q.hasOwnProperty('sub_question_rules'))\n for (let r of q.sub_question_rules) {\n this.rules[parseInt(r.id)] = r;\n this._parseQuestion(r.sub_question);\n }\n }\n\n _parseQuestions = () => {\n for (let q of this.questions) {\n this._parseQuestion(q);\n }\n }\n\n _allowsValues = (q) => {\n return AllowedMultipleValueQuestionType.includes(q.type);\n }\n\n _allowsValue = (q, answer) => {\n let value = answer.value.split(',').map(v => parseInt(v));\n for (let av of value) {\n if (!q.values.map(e => e.id).includes(av))\n return false;\n }\n return true;\n }\n\n _getAnswerFor = (q) => {\n let id = Number.isInteger(q) ? q : q.id;\n let a = this.answers[id] || null;\n return a ? a : null;\n }\n\n _hasValue = (answer) => {\n return answer.value !== '';\n }\n\n _answerContains = (answer, val) => {\n return answer.value.split(',').includes(val);\n }\n\n _isSubQuestionVisible = (rule) => {\n let initialCondition = rule.answer_values_operator === AnswerValuesOperator_And ? true : false;\n const parentQuestionAnswer = this._getAnswerFor(rule.parent_question_id);\n if (!parentQuestionAnswer) {\n initialCondition = rule.visibility_condition === VisibilityCondition_Equal ? false : true;\n } else {\n switch (rule.visibility_condition) {\n case VisibilityCondition_Equal: {\n for (let answerValue of rule.answer_values) {\n if (rule.answer_values_operator === AnswerValuesOperator_And)\n initialCondition = initialCondition && this._answerContains(parentQuestionAnswer, answerValue);\n else\n initialCondition = initialCondition || this._answerContains(parentQuestionAnswer, answerValue);\n }\n }\n break;\n case VisibilityCondition_NotEqual: {\n for (let answerValue of rule.answer_values) {\n if (rule.answer_values_operator === AnswerValuesOperator_And)\n initialCondition = initialCondition && !this._answerContains(parentQuestionAnswer, answerValue);\n else\n initialCondition = initialCondition || !this._answerContains(parentQuestionAnswer, answerValue);\n }\n }\n break;\n }\n }\n // final visibility check\n if (rule.visibility === Visibility_Visible) {\n return initialCondition;\n }\n // not visible\n return !initialCondition;\n }\n\n _isAnswered = (q) => {\n const answer = this._getAnswerFor(q);\n\n if (q.class === MainQuestionClassType) {\n if (!q.mandatory) return true;\n if (!answer) return false;\n if (!this._hasValue(answer)) return false;\n if (this._allowsValues(q) && !this._allowsValue(q, answer))\n return false;\n return true;\n }\n\n // check parent rules ...\n for (let ruleId of q.parent_rules) {\n if (!this._isSubQuestionVisible(this.rules[ruleId])) // if question is not visible skip it\n continue;\n if (!q.mandatory) return true;\n if (!answer) return false;\n if (!this._hasValue(answer)) return false;\n if (this._allowsValues(q) && !this._allowsValue(q, answer))\n return false;\n return true;\n }\n\n return true;\n }\n\n _checkQuestion = (q) => {\n let res = this._isAnswered(q);\n if(q.hasOwnProperty('sub_question_rules'))\n for (let rule of q.sub_question_rules) {\n // check recursive all the tree till leaves ...\n res = res && this._checkQuestion(rule.sub_question);\n }\n return res;\n }\n\n _formatQuestionAnswer = (question) => {\n let res = {};\n const slug = toSlug(question.name);\n let userAnswer = this.originalAnswers.find(a => a.question_id === question.id)?.value;\n if(!userAnswer && question?.values?.length > 0){\n // check default value\n const defaultVal = question.values.find(v => v.is_default);\n if(defaultVal) userAnswer = defaultVal.id.toString();\n }\n if(userAnswer) {\n if (question.type === CheckBoxQuestionType) userAnswer = userAnswer === 'false' ? false : !!userAnswer;\n if (question.type === RadioButtonListQuestionType || question.type === ComboBoxQuestionType) userAnswer = parseInt(userAnswer);\n if (question.type === CheckBoxListQuestionType) userAnswer = userAnswer.split(',').map(ansVal => parseInt(ansVal)) || [];\n }\n\n res[slug] = userAnswer || '';\n if(question.type === CheckBoxListQuestionType && res[slug] === '') res[slug] = []\n if(question.hasOwnProperty('sub_question_rules'))\n for (let rule of question.sub_question_rules) {\n // check recursive all the tree till leaves ...\n let res1 = this._formatQuestionAnswer(rule.sub_question);\n res = {...res, ...res1};\n }\n return res;\n }\n\n formatAnswers = () => {\n let res = {}\n this.questions.forEach(q => {\n let res1 = this._formatQuestionAnswer(q);\n res = {...res,...res1};\n });\n return res;\n }\n\n completed = () => {\n let res = true;\n for (let q of this.questions) {\n res = res && this._checkQuestion(q);\n }\n return res;\n }\n\n getQuestionByName = (name) => {\n const slug = toSlug(name)\n return this.questionByName[name] || this.questionByName[slug] || null;\n }\n\n getQuestionById = (id) => {\n return this.questionById[parseInt(id)] || null;\n }\n}\n"],"names":["root","factory","exports","module","define","amd","this","toSlug","text","toLowerCase","replace","require","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","CheckBoxQuestionType","ComboBoxQuestionType","CheckBoxListQuestionType","RadioButtonListQuestionType","AllowedMultipleValueQuestionType","AnswerValuesOperator_And","AnswerValuesOperator_Or","VisibilityCondition_Equal","VisibilityCondition_NotEqual","Visibility_Visible","MainQuestionClassType","QuestionsSet","constructor","questions","answers","_defineProperty","q","questionByName","name","questionById","parseInt","id","sub_question_rules","rules","_parseQuestion","sub_question","includes","type","answer","split","map","v","av","values","e","Number","isInteger","val","rule","initialCondition","answer_values_operator","parentQuestionAnswer","_getAnswerFor","parent_question_id","visibility_condition","answerValue","answer_values","_answerContains","visibility","class","mandatory","_hasValue","_allowsValues","_allowsValue","ruleId","parent_rules","_isSubQuestionVisible","res","_isAnswered","_checkQuestion","question","_this$originalAnswers","_question$values","slug","userAnswer","originalAnswers","find","question_id","length","defaultVal","is_default","toString","ansVal","res1","_formatQuestionAnswer","_objectSpread","forEach","_parseQuestions"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"utils/questions-set.js","mappings":"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","sources":["webpack://openstack-uicore-foundation/webpack/universalModuleDefinition","webpack://openstack-uicore-foundation/./src/utils/methods.js","webpack://openstack-uicore-foundation/external commonjs \"@babel/runtime/helpers/defineProperty\"","webpack://openstack-uicore-foundation/external commonjs \"moment-timezone\"","webpack://openstack-uicore-foundation/external commonjs \"urijs\"","webpack://openstack-uicore-foundation/webpack/bootstrap","webpack://openstack-uicore-foundation/webpack/runtime/compat get default export","webpack://openstack-uicore-foundation/webpack/runtime/define property getters","webpack://openstack-uicore-foundation/webpack/runtime/hasOwnProperty shorthand","webpack://openstack-uicore-foundation/webpack/runtime/make namespace object","webpack://openstack-uicore-foundation/./src/utils/questions-set.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"openstack-uicore-foundation\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"openstack-uicore-foundation\"] = factory();\n\telse\n\t\troot[\"openstack-uicore-foundation\"] = factory();\n})(this, () => {\nreturn ","/**\n * Copyright 2018 OpenStack Foundation\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n **/\n\nimport moment from 'moment-timezone';\nimport URI from \"urijs\";\n\nexport const findElementPos = (obj) => {\n var curtop = -70;\n if (obj.offsetParent) {\n do {\n curtop += obj.offsetTop;\n } while (obj = obj.offsetParent);\n return [curtop];\n }\n};\n\nexport const epochToMoment = (atime) => {\n if(!atime) return atime;\n atime = atime * 1000;\n return moment(atime);\n};\n\nexport const epochToMomentTimeZone = (atime, time_zone) => {\n if(!atime) return atime;\n atime = atime * 1000;\n return moment(atime).tz(time_zone);\n};\n\nexport const formatEpoch = (atime, format = 'M/D/YYYY h:mm a') => {\n if(!atime) return atime;\n return epochToMoment(atime).format(format);\n};\n\nexport const parseLocationHour = (hour) => {\n let parsedHour = hour.toString();\n if(parsedHour.length < 4) parsedHour = `0${parsedHour}`;\n parsedHour = parsedHour.match(/.{2}/g);\n parsedHour = parsedHour.join(':');\n return parsedHour;\n}\n\nexport const objectToQueryString = (obj) => {\n var str = \"\";\n for (var key in obj) {\n if (str != \"\") {\n str += \"&\";\n }\n str += key + \"=\" + encodeURIComponent(obj[key]);\n }\n\n return str;\n};\n\nexport const getBackURL = () => {\n let url = URI(window.location.href);\n let query = url.search(true);\n let fragment = url.fragment();\n let backUrl = query.hasOwnProperty('BackUrl') ? query['BackUrl'] : null;\n if(backUrl != null && fragment != null && fragment != ''){\n backUrl += `#${fragment}`;\n }\n return backUrl;\n};\n\nexport const toSlug = (text) =>{\n text = text.toLowerCase();\n return text.replace(/[^a-zA-Z0-9]+/g,'_');\n}\n\nexport const getAuthCallback = () => {\n if(typeof window !== 'undefined') {\n return `${window.location.origin}/auth/callback`;\n }\n return null;\n};\n\nexport const getCurrentLocation = () => {\n let location = '';\n if(typeof window !== 'undefined') {\n location = window.location;\n // check if we are on iframe\n if (window.top)\n location = window.top.location;\n }\n return location;\n};\n\nexport const getOrigin = () => {\n if(typeof window !== 'undefined') {\n return window.location.origin;\n }\n return null;\n};\n\nexport const getCurrentPathName = () => {\n if(typeof window !== 'undefined') {\n return window.location.pathname;\n }\n return null;\n};\n\nexport const getCurrentHref = () => {\n if(typeof window !== 'undefined') {\n return window.location.href;\n }\n return null;\n};\n\nexport const getAllowedUserGroups = () => {\n if(typeof window !== 'undefined') {\n return window.ALLOWED_USER_GROUPS || '';\n }\n return null;\n};\n\nexport const buildAPIBaseUrl = (relativeUrl) => {\n if(typeof window !== 'undefined'){\n return `${window.API_BASE_URL}${relativeUrl}`;\n }\n return null``;\n};\n\nexport const putOnLocalStorage = (key, value) => {\n if(typeof window !== 'undefined') {\n window.localStorage.setItem(key, value);\n }\n};\n\nexport const getFromLocalStorage = (key, removeIt) => {\n if(typeof window !== 'undefined') {\n let val = window.localStorage.getItem(key);\n if(removeIt){\n console.log(`getFromLocalStorage removing key ${key}`);\n removeFromLocalStorage(key);\n }\n return val;\n }\n return null;\n};\n\nexport const removeFromLocalStorage = (key) => {\n if(typeof window !== 'undefined') {\n window.localStorage.removeItem(key);\n }\n}\n\nexport const isClearingSessionState = () => {\n if(typeof window !== 'undefined') {\n return window.clearing_session_state;\n }\n return false;\n};\n\nexport const setSessionClearingState = (val) => {\n if(typeof window !== 'undefined') {\n window.clearing_session_state = val;\n }\n};\n\nexport const getCurrentUserLanguage = () => {\n let language = 'en';\n if(typeof navigator !== 'undefined') {\n language = (navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage;\n }\n return language;\n};\n\nexport const scrollToError = (errors) => {\n if(Object.keys(errors).length > 0) {\n const firstError = Object.keys(errors)[0];\n const firstNode = document.getElementById(firstError);\n if (firstNode) window.scrollTo(0, findElementPos(firstNode));\n }\n};\n\nexport const hasErrors = (field, errors) => {\n if(field in errors) {\n return errors[field];\n }\n return '';\n};\n\nexport const shallowEqual = (object1, object2) => {\n const keys1 = Object.keys(object1);\n const keys2 = Object.keys(object2);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (let key of keys1) {\n if (object1[key] !== object2[key]) {\n return false;\n }\n }\n\n return true;\n};\n\nexport const arraysEqual = (a1, a2) =>\n a1.length === a2.length && a1.every((o, idx) => shallowEqual(o, a2[idx]));\n\nexport const isEmpty = (obj) => {\n return Object.keys(obj).length === 0;\n};\n\n\nexport const base64URLEncode = (str) => {\n return str\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\nexport const retryPromise = async (\n cb,\n maxNumberOfRetries = 3\n) => {\n for (let i = 0; i < maxNumberOfRetries; i++) {\n if (await cb()) {\n return true;\n }\n }\n\n return false;\n}\n\nexport const getTimeServiceUrl = () => {\n if(typeof window !== 'undefined') {\n return window.TIMEINTERVALSINCE1970_API_URL || process.env.TIMEINTERVALSINCE1970_API_URL;\n }\n return null;\n};\n\nexport const getEventLocation = (event, summitVenueCount, summitShowLocDate = null, nowUtc = null) => {\n const shouldShowVenues = (summitShowLocDate && nowUtc) ? summitShowLocDate * 1000 < nowUtc : true;\n const locationName = [];\n const { location } = event;\n\n if (!shouldShowVenues) return 'TBA';\n\n if (!location) return 'TBA';\n\n if (summitVenueCount > 1 && location.venue?.name) locationName.push(location.venue.name);\n if (location.floor?.name) locationName.push(location.floor.name);\n if (location.name) locationName.push(location.name);\n\n return locationName.length > 0 ? locationName.join(' - ') : 'TBA';\n};\n\nexport const getEventHosts = (event) => {\n let hosts = [];\n if (event.speakers?.length > 0) {\n hosts = [...event.speakers];\n }\n if (event.moderator) hosts.push(event.moderator);\n\n return hosts;\n};\n\nconst loadImage = async url => {\n const img = document.createElement('img')\n img.src = url\n img.crossOrigin = 'anonymous'\n\n return new Promise((resolve, reject) => {\n img.onload = () => resolve(img)\n img.onerror = reject\n })\n}\n\nexport const convertSVGtoImg = async (svgUrl) => {\n const img = await loadImage(svgUrl)\n const newWidth = 100\n const newHeight = Math.floor(img.naturalHeight * 100 / img.naturalWidth)\n\n const canvas = document.createElement('canvas')\n canvas.width = newWidth\n canvas.height = newHeight\n canvas.getContext('2d').drawImage(img, 0, 0, newWidth, newHeight)\n\n const url = await canvas.toDataURL(`image/png`, 1.0)\n console.log(url, newWidth, newHeight);\n return {url, width: newWidth, height: newHeight}\n}\n\nexport const isRateEnabled = (value) =>\n value !== null && value !== undefined && value !== \"\";\n\n/**\n * Returns true if value is null, undefined, empty/whitespace string,\n * empty array, or empty object.\n */\nexport const empty = (value) => {\n if (value === null || value === undefined) return true;\n if (typeof value === \"string\") return value.trim().length === 0;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === \"object\") return Object.keys(value).length === 0;\n return false;\n};\n\nexport const isSentryInitialized = () => typeof window !== \"undefined\" && !!window.SENTRY_DSN;\n","module.exports = require(\"@babel/runtime/helpers/defineProperty\");","module.exports = require(\"moment-timezone\");","module.exports = require(\"urijs\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export const CheckBoxQuestionType = 'CheckBox';\nexport const ComboBoxQuestionType = 'ComboBox'\nexport const CheckBoxListQuestionType = 'CheckBoxList';\nexport const RadioButtonListQuestionType = 'RadioButtonList';\nexport const AllowedMultipleValueQuestionType = [ComboBoxQuestionType, CheckBoxListQuestionType, RadioButtonListQuestionType];\nexport const AnswerValuesOperator_And = 'And';\nexport const AnswerValuesOperator_Or = 'Or';\nexport const VisibilityCondition_Equal = 'Equal';\nexport const VisibilityCondition_NotEqual = 'NotEqual';\nexport const Visibility_Visible = 'Visible';\nexport const MainQuestionClassType = 'MainQuestion';\nimport {toSlug} from \"./methods\";\n\nexport default class QuestionsSet {\n\n constructor(questions, answers = []) {\n this.questions = questions;\n this.originalAnswers = answers\n this.answers = [];\n // map answers to associate array\n for (let a of this.originalAnswers)\n this.answers[a.question_id] = a;\n this.questionByName = {}\n this.questionById = {}\n // associative array ( rule id , rule);\n this.rules = {};\n this._parseQuestions();\n }\n\n _parseQuestion = (q) => {\n this.questionByName[toSlug(q.name)] = q;\n this.questionById[parseInt(q.id)] = q;\n if(q.hasOwnProperty('sub_question_rules'))\n for (let r of q.sub_question_rules) {\n this.rules[parseInt(r.id)] = r;\n this._parseQuestion(r.sub_question);\n }\n }\n\n _parseQuestions = () => {\n for (let q of this.questions) {\n this._parseQuestion(q);\n }\n }\n\n _allowsValues = (q) => {\n return AllowedMultipleValueQuestionType.includes(q.type);\n }\n\n _allowsValue = (q, answer) => {\n let value = answer.value.split(',').map(v => parseInt(v));\n for (let av of value) {\n if (!q.values.map(e => e.id).includes(av))\n return false;\n }\n return true;\n }\n\n _getAnswerFor = (q) => {\n let id = Number.isInteger(q) ? q : q.id;\n let a = this.answers[id] || null;\n return a ? a : null;\n }\n\n _hasValue = (answer) => {\n return answer.value !== '';\n }\n\n _answerContains = (answer, val) => {\n return answer.value.split(',').includes(val);\n }\n\n _isSubQuestionVisible = (rule) => {\n let initialCondition = rule.answer_values_operator === AnswerValuesOperator_And ? true : false;\n const parentQuestionAnswer = this._getAnswerFor(rule.parent_question_id);\n if (!parentQuestionAnswer) {\n initialCondition = rule.visibility_condition === VisibilityCondition_Equal ? false : true;\n } else {\n switch (rule.visibility_condition) {\n case VisibilityCondition_Equal: {\n for (let answerValue of rule.answer_values) {\n if (rule.answer_values_operator === AnswerValuesOperator_And)\n initialCondition = initialCondition && this._answerContains(parentQuestionAnswer, answerValue);\n else\n initialCondition = initialCondition || this._answerContains(parentQuestionAnswer, answerValue);\n }\n }\n break;\n case VisibilityCondition_NotEqual: {\n for (let answerValue of rule.answer_values) {\n if (rule.answer_values_operator === AnswerValuesOperator_And)\n initialCondition = initialCondition && !this._answerContains(parentQuestionAnswer, answerValue);\n else\n initialCondition = initialCondition || !this._answerContains(parentQuestionAnswer, answerValue);\n }\n }\n break;\n }\n }\n // final visibility check\n if (rule.visibility === Visibility_Visible) {\n return initialCondition;\n }\n // not visible\n return !initialCondition;\n }\n\n _isAnswered = (q) => {\n const answer = this._getAnswerFor(q);\n\n if (q.class === MainQuestionClassType) {\n if (!q.mandatory) return true;\n if (!answer) return false;\n if (!this._hasValue(answer)) return false;\n if (this._allowsValues(q) && !this._allowsValue(q, answer))\n return false;\n return true;\n }\n\n // check parent rules ...\n for (let ruleId of q.parent_rules) {\n if (!this._isSubQuestionVisible(this.rules[ruleId])) // if question is not visible skip it\n continue;\n if (!q.mandatory) return true;\n if (!answer) return false;\n if (!this._hasValue(answer)) return false;\n if (this._allowsValues(q) && !this._allowsValue(q, answer))\n return false;\n return true;\n }\n\n return true;\n }\n\n _checkQuestion = (q) => {\n let res = this._isAnswered(q);\n if(q.hasOwnProperty('sub_question_rules'))\n for (let rule of q.sub_question_rules) {\n // check recursive all the tree till leaves ...\n res = res && this._checkQuestion(rule.sub_question);\n }\n return res;\n }\n\n _formatQuestionAnswer = (question) => {\n let res = {};\n const slug = toSlug(question.name);\n let userAnswer = this.originalAnswers.find(a => a.question_id === question.id)?.value;\n if(!userAnswer && question?.values?.length > 0){\n // check default value\n const defaultVal = question.values.find(v => v.is_default);\n if(defaultVal) userAnswer = defaultVal.id.toString();\n }\n if(userAnswer) {\n if (question.type === CheckBoxQuestionType) userAnswer = userAnswer === 'false' ? false : !!userAnswer;\n if (question.type === RadioButtonListQuestionType || question.type === ComboBoxQuestionType) userAnswer = parseInt(userAnswer);\n if (question.type === CheckBoxListQuestionType) userAnswer = userAnswer.split(',').map(ansVal => parseInt(ansVal)) || [];\n }\n\n res[slug] = userAnswer || '';\n if(question.type === CheckBoxListQuestionType && res[slug] === '') res[slug] = []\n if(question.hasOwnProperty('sub_question_rules'))\n for (let rule of question.sub_question_rules) {\n // check recursive all the tree till leaves ...\n let res1 = this._formatQuestionAnswer(rule.sub_question);\n res = {...res, ...res1};\n }\n return res;\n }\n\n formatAnswers = () => {\n let res = {}\n this.questions.forEach(q => {\n let res1 = this._formatQuestionAnswer(q);\n res = {...res,...res1};\n });\n return res;\n }\n\n completed = () => {\n let res = true;\n for (let q of this.questions) {\n res = res && this._checkQuestion(q);\n }\n return res;\n }\n\n getQuestionByName = (name) => {\n const slug = toSlug(name)\n return this.questionByName[name] || this.questionByName[slug] || null;\n }\n\n getQuestionById = (id) => {\n return this.questionById[parseInt(id)] || null;\n }\n}\n"],"names":["root","factory","exports","module","define","amd","this","toSlug","text","toLowerCase","replace","require","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","CheckBoxQuestionType","ComboBoxQuestionType","CheckBoxListQuestionType","RadioButtonListQuestionType","AllowedMultipleValueQuestionType","AnswerValuesOperator_And","AnswerValuesOperator_Or","VisibilityCondition_Equal","VisibilityCondition_NotEqual","Visibility_Visible","MainQuestionClassType","QuestionsSet","constructor","questions","answers","_defineProperty","q","questionByName","name","questionById","parseInt","id","sub_question_rules","rules","_parseQuestion","sub_question","includes","type","answer","split","map","v","av","values","e","Number","isInteger","val","rule","initialCondition","answer_values_operator","parentQuestionAnswer","_getAnswerFor","parent_question_id","visibility_condition","answerValue","answer_values","_answerContains","visibility","class","mandatory","_hasValue","_allowsValues","_allowsValue","ruleId","parent_rules","_isSubQuestionVisible","res","_isAnswered","_checkQuestion","question","_this$originalAnswers","_question$values","slug","userAnswer","originalAnswers","find","question_id","length","defaultVal","is_default","toString","ansVal","res1","_formatQuestionAnswer","_objectSpread","forEach","_parseQuestions"],"sourceRoot":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openstack-uicore-foundation",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0-beta.1",
|
|
4
4
|
"description": "ui reactjs components for openstack marketing site",
|
|
5
5
|
"main": "lib/openstack-uicore-foundation.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,18 +20,18 @@
|
|
|
20
20
|
"@babel/preset-flow": "^7.7.4",
|
|
21
21
|
"@babel/preset-react": "^7.7.4",
|
|
22
22
|
"@babel/runtime": "^7.20.7",
|
|
23
|
-
"@emotion/react": "^11.
|
|
24
|
-
"@emotion/styled": "^11.
|
|
25
|
-
"@mui/icons-material": "^
|
|
26
|
-
"@mui/material": "^
|
|
27
|
-
"@mui/x-date-pickers": "^
|
|
23
|
+
"@emotion/react": "^11.14.0",
|
|
24
|
+
"@emotion/styled": "^11.14.0",
|
|
25
|
+
"@mui/icons-material": "^9.0.0",
|
|
26
|
+
"@mui/material": "^9.0.0",
|
|
27
|
+
"@mui/x-date-pickers": "^9.0.0",
|
|
28
28
|
"@react-pdf/renderer": "^3.1.11",
|
|
29
29
|
"@sentry/react": "^8.54.0",
|
|
30
30
|
"@sentry/webpack-plugin": "^3.1.2",
|
|
31
31
|
"@stripe/react-stripe-js": "^5.4.1",
|
|
32
32
|
"@stripe/stripe-js": "^8.5.3",
|
|
33
33
|
"@testing-library/jest-dom": "5.17.0",
|
|
34
|
-
"@testing-library/react": "
|
|
34
|
+
"@testing-library/react": "^14.0.0",
|
|
35
35
|
"@testing-library/user-event": "14.5.2",
|
|
36
36
|
"awesome-bootstrap-checkbox": "^1.0.1",
|
|
37
37
|
"babel-cli": "^6.26.0",
|
|
@@ -72,13 +72,13 @@
|
|
|
72
72
|
"node-sass": "^7.0.1",
|
|
73
73
|
"path": "^0.12.7",
|
|
74
74
|
"postcss-loader": "^6.2.1",
|
|
75
|
-
"react": "^
|
|
75
|
+
"react": "^18.0.0",
|
|
76
76
|
"react-beautiful-dnd": "^13.1.1",
|
|
77
77
|
"react-bootstrap": "^0.31.5",
|
|
78
78
|
"react-datetime": "^2.16.2",
|
|
79
79
|
"react-dnd": "^16.0.0",
|
|
80
80
|
"react-dnd-html5-backend": "^16.0.0",
|
|
81
|
-
"react-dom": "^
|
|
81
|
+
"react-dom": "^18.0.0",
|
|
82
82
|
"react-dropzone": "^4.2.9",
|
|
83
83
|
"react-final-form": "^6.5.9",
|
|
84
84
|
"react-google-maps": "^9.4.5",
|
|
@@ -112,11 +112,11 @@
|
|
|
112
112
|
"cheerio": "1.0.0-rc.10"
|
|
113
113
|
},
|
|
114
114
|
"peerDependencies": {
|
|
115
|
-
"@emotion/react": "^11.
|
|
116
|
-
"@emotion/styled": "^11.
|
|
117
|
-
"@mui/icons-material": "^
|
|
118
|
-
"@mui/material": "^
|
|
119
|
-
"@mui/x-date-pickers": "^
|
|
115
|
+
"@emotion/react": "^11.0.0",
|
|
116
|
+
"@emotion/styled": "^11.0.0",
|
|
117
|
+
"@mui/icons-material": "^9.0.0",
|
|
118
|
+
"@mui/material": "^9.0.0",
|
|
119
|
+
"@mui/x-date-pickers": "^9.0.0",
|
|
120
120
|
"@react-pdf/renderer": "^3.1.11",
|
|
121
121
|
"@sentry/react": "^8.54.0",
|
|
122
122
|
"@stripe/react-stripe-js": "^5.4.1",
|
|
@@ -139,13 +139,13 @@
|
|
|
139
139
|
"moment": "^2.22.2",
|
|
140
140
|
"moment-timezone": "^0.5.21",
|
|
141
141
|
"prop-types": "^15.8.1",
|
|
142
|
-
"react": "^
|
|
142
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
143
143
|
"react-beautiful-dnd": "^13.1.1",
|
|
144
144
|
"react-bootstrap": "^0.31.5",
|
|
145
145
|
"react-datetime": "^2.16.2",
|
|
146
146
|
"react-dnd": "^16.0.0",
|
|
147
147
|
"react-dnd-html5-backend": "^16.0.0",
|
|
148
|
-
"react-dom": "^
|
|
148
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
149
149
|
"react-dropzone": "^4.2.9",
|
|
150
150
|
"react-final-form": "^6.5.9",
|
|
151
151
|
"react-google-maps": "^9.4.5",
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Component Patterns
|
|
2
|
-
|
|
3
|
-
## Upload Components (3 generations)
|
|
4
|
-
|
|
5
|
-
| Version | Location | Rendering | Use Case |
|
|
6
|
-
|---------|----------|-----------|----------|
|
|
7
|
-
| V1 | `inputs/upload-input/` | Legacy, basic file list | Simple single-file uploads |
|
|
8
|
-
| V2 | `inputs/upload-input-v2/` | Custom React UI | Multi-file with progress |
|
|
9
|
-
| V3 | `inputs/upload-input-v3/` | MUI-based UI | Chunked uploads, async processing |
|
|
10
|
-
|
|
11
|
-
**All versions wrap `inputs/dropzone/index.js`** (DropzoneJS class) or `dropzone-v3.js` (DropzoneV3 wrapper). The underlying Dropzone library is `dropzone@5.7.2`.
|
|
12
|
-
|
|
13
|
-
### Chunked Upload Architecture
|
|
14
|
-
|
|
15
|
-
- `DropzoneJS` manages a chunk queue with `maxConcurrentChunks` (default: 6)
|
|
16
|
-
- `setupChunkThrottle()` wraps Dropzone's `_uploadData` to enforce concurrency
|
|
17
|
-
- Progress tracking uses `_completedBytes` floor to prevent oscillation during parallel chunk uploads
|
|
18
|
-
- `options.uploadprogress` override in `getDjsConfig()` centralizes progress correction (guards against `NaN` bytesSent from queued chunks)
|
|
19
|
-
- HTTP 202 responses trigger async polling via `_asyncProcessing` flag
|
|
20
|
-
|
|
21
|
-
### Upload Gotchas
|
|
22
|
-
|
|
23
|
-
- **Progress oscillation:** Dropzone creates chunk entries with `progress:0` and `bytesSent:undefined` upfront. Raw progress average across chunks causes backsliding — always apply `_completedBytes` floor.
|
|
24
|
-
- **Cancel cleanup:** `xhr.abort()` fires `onabort`, not `onload`/`onerror`. Cancelled files must be filtered from `chunkQueue` and `chunksInFlight` decremented in `removedfile` handler.
|
|
25
|
-
- **NaN guard:** `Math.max(bytesSent || 0, ...)` — bytesSent can be `undefined` for queued chunks.
|
|
26
|
-
|
|
27
|
-
## MUI Components
|
|
28
|
-
|
|
29
|
-
- Located in `src/components/mui/`
|
|
30
|
-
- Follow pattern: component in `index.js`, styles in `.module.less` or `.module.scss`
|
|
31
|
-
- Formik integration components in `mui/formik-inputs/` — prefix `mui-formik-*`
|
|
32
|
-
- All MUI components use MUI v6 APIs
|
|
33
|
-
|
|
34
|
-
## Redux Pattern
|
|
35
|
-
|
|
36
|
-
```javascript
|
|
37
|
-
// Action creator factory
|
|
38
|
-
export const createAction = type => payload => ({ type, payload });
|
|
39
|
-
|
|
40
|
-
// Async thunk pattern
|
|
41
|
-
export const myAction = (params) => async (dispatch, getState) => {
|
|
42
|
-
dispatch(startLoading());
|
|
43
|
-
return getRequest(
|
|
44
|
-
createAction(REQUEST_TYPE),
|
|
45
|
-
createAction(RECEIVE_TYPE),
|
|
46
|
-
buildAPIBaseUrl('/api/v1/endpoint'),
|
|
47
|
-
authErrorHandler
|
|
48
|
-
)(params)(dispatch, getState);
|
|
49
|
-
};
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
- Actions: constants + thunks in same file
|
|
53
|
-
- Reducers: switch/case on action types
|
|
54
|
-
- State shape: `loggedUserState` for auth, domain-specific reducers in consumers
|
|
55
|
-
|
|
56
|
-
## Testing Conventions
|
|
57
|
-
|
|
58
|
-
- Test files: `__tests__/` directories adjacent to components
|
|
59
|
-
- Framework: Jest + @testing-library/react
|
|
60
|
-
- Mock pattern: `jest.mock('module')` at top of file
|
|
61
|
-
- Component tests render with `@testing-library/react`, assert on DOM
|
|
62
|
-
- Dropzone tests mock the Dropzone constructor to capture options and simulate events
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Project: openstack-uicore-foundation
|
|
2
|
-
|
|
3
|
-
**Last Updated:** 2026-04-23
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Shared React component library for OpenStack marketing sites and summit management apps. Published as an npm package — consumers import from `lib/`.
|
|
8
|
-
|
|
9
|
-
## Technology Stack
|
|
10
|
-
|
|
11
|
-
- **Language:** JavaScript (ES6+, Babel-transpiled)
|
|
12
|
-
- **UI:** React 17, MUI 6, Formik, React-Redux 5, Redux 3
|
|
13
|
-
- **HTTP:** superagent
|
|
14
|
-
- **Auth:** OAuth2 PKCE + OIDC (idtoken-verifier, browser-tabs-lock)
|
|
15
|
-
- **Build:** Webpack 5, Babel 7 (babel.config.json)
|
|
16
|
-
- **Test:** Jest 28, @testing-library/react 12, jsdom
|
|
17
|
-
- **Styles:** LESS, SCSS, CSS Modules
|
|
18
|
-
- **Node:** 18.15.0 (.nvmrc)
|
|
19
|
-
- **Indentation:** 4 spaces (all file types — .editorconfig)
|
|
20
|
-
|
|
21
|
-
## Directory Structure
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
src/
|
|
25
|
-
├── components/
|
|
26
|
-
│ ├── inputs/ # Form inputs (dropzone, upload V1/V2/V3, text, dropdown, etc.)
|
|
27
|
-
│ ├── mui/ # MUI-based components (formik-inputs/, tables, dialogs, etc.)
|
|
28
|
-
│ ├── security/ # OAuth/PKCE auth, session management, reducers
|
|
29
|
-
│ ├── forms/ # SimpleForm, RsvpForm
|
|
30
|
-
│ ├── sections/ # Panel
|
|
31
|
-
│ ├── index.js # Barrel re-exports for all components
|
|
32
|
-
│ └── ... # Individual components (clock, video-stream, etc.)
|
|
33
|
-
├── models/ # Data models (summit-event)
|
|
34
|
-
├── utils/ # Actions, reducers, methods, constants, crypto, money
|
|
35
|
-
└── i18n/ # en.json, es.json, zh.json
|
|
36
|
-
lib/ # Built output (gitignored, npm-published)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Key Files
|
|
40
|
-
|
|
41
|
-
- **Entry/Exports:** `src/components/index.js` — barrel file with all public exports
|
|
42
|
-
- **Webpack entries:** `webpack.common.js` — individual entry points per component (no single bundle)
|
|
43
|
-
- **Auth core:** `src/components/security/methods.js` — OAuth PKCE, token refresh, session management
|
|
44
|
-
- **API utils:** `src/utils/actions.js` — HTTP request helpers, error handlers, Redux action creators
|
|
45
|
-
- **Constants:** `src/utils/constants.js` — shared numeric/string constants
|
|
46
|
-
|
|
47
|
-
## Development Commands
|
|
48
|
-
|
|
49
|
-
| Task | Command |
|
|
50
|
-
|------|---------|
|
|
51
|
-
| Install | `yarn install` |
|
|
52
|
-
| Build (dev) | `yarn build-dev` |
|
|
53
|
-
| Build (prod) | `yarn build` |
|
|
54
|
-
| Test | `jest` (or `npx jest`) |
|
|
55
|
-
| Clean rebuild | `yarn clean` |
|
|
56
|
-
|
|
57
|
-
## Architecture Notes
|
|
58
|
-
|
|
59
|
-
- **Multi-entry Webpack build:** Each component is a separate webpack entry point — consumers can import individual components without pulling the full bundle.
|
|
60
|
-
- **Peer dependencies model:** React, MUI, Redux, and most libs are peer deps — consumers provide them.
|
|
61
|
-
- **Redux pattern:** `createAction(TYPE)` factory → thunk actions → `getRequest`/`putRequest`/`postRequest`/`deleteRequest` helpers in `utils/actions.js`. Error handling via `authErrorHandler` with auto-redirect on 401.
|
|
62
|
-
- **i18n:** `i18n-react` with JSON locale files. Language detected from browser, fallback to English.
|
|
63
|
-
- **No barrel imports from `lib/`:** Components are imported directly from their paths (e.g., `openstack-uicore-foundation/lib/components/inputs/upload-input-v3`).
|
|
64
|
-
- **Commented-out exports** in `src/components/index.js` are components with heavy 3rd-party deps (Stripe, react-beautiful-dnd) — imported separately by consumers.
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Security & Auth Conventions
|
|
2
|
-
|
|
3
|
-
## OAuth2 PKCE Flow
|
|
4
|
-
|
|
5
|
-
Auth lives in `src/components/security/`. The library implements OAuth2 Authorization Code + PKCE against an OpenStack IDP.
|
|
6
|
-
|
|
7
|
-
### Key Modules
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|------|---------|
|
|
11
|
-
| `methods.js` | Core auth: `doLogin`, `initLogOut`, `getAccessToken`, `storeAuthInfo`, token refresh with mutex (SuperTokensLock) |
|
|
12
|
-
| `actions.js` | Redux actions: `onUserAuth`, `getUserInfo`, `doLogout` |
|
|
13
|
-
| `reducers.js` | Auth state: `loggedUserState` with `member`, `sessionState` |
|
|
14
|
-
| `constants.js` | Error code constants (`AUTH_ERROR_*`) |
|
|
15
|
-
| `abstract-auth-callback-route.js` | Route component for OAuth callback handling (v1) |
|
|
16
|
-
| `abstract-auth-callback-route-v2.js` | OAuth callback with PKCE verifier exchange (v2) |
|
|
17
|
-
| `session-checker/op-session-checker.js` | Session iframe checker for silent re-auth |
|
|
18
|
-
|
|
19
|
-
### Token Management
|
|
20
|
-
|
|
21
|
-
- Access tokens stored via `storeAuthInfo()` in localStorage
|
|
22
|
-
- Refresh uses `SuperTokensLock` (browser-tabs-lock) for cross-tab mutex
|
|
23
|
-
- ID token validated with `idtoken-verifier`
|
|
24
|
-
- PKCE: SHA256 code challenge via `src/utils/crypto.js` (`getSHA256`, `getRandomBytes`)
|
|
25
|
-
|
|
26
|
-
### Auth Error Handling
|
|
27
|
-
|
|
28
|
-
`authErrorHandler` in `utils/actions.js` handles HTTP errors:
|
|
29
|
-
- **401:** Triggers `initLogin()` → redirects to IDP (with session-clearing guard to prevent loops)
|
|
30
|
-
- **403:** Shows "not authorized" message
|
|
31
|
-
- **412:** Shows server-provided validation errors
|
|
32
|
-
- **Other:** Generic error with optional `res.body.message`
|
|
33
|
-
|
|
34
|
-
### Conventions
|
|
35
|
-
|
|
36
|
-
- Auth methods imported from `security/methods` — never call IDP directly
|
|
37
|
-
- Access token passed as query param `access_token` (not Bearer header) in `getRequest`/`putRequest` helpers
|
|
38
|
-
- `getAllowedUserGroups()` reads from env/config to restrict access by group membership
|
|
39
|
-
- Consumer apps must provide `loggedUserState` in their Redux store
|
package/.codegraph/config.json
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 1,
|
|
3
|
-
"include": [
|
|
4
|
-
"**/*.ts",
|
|
5
|
-
"**/*.tsx",
|
|
6
|
-
"**/*.js",
|
|
7
|
-
"**/*.jsx",
|
|
8
|
-
"**/*.py",
|
|
9
|
-
"**/*.go",
|
|
10
|
-
"**/*.rs",
|
|
11
|
-
"**/*.java",
|
|
12
|
-
"**/*.c",
|
|
13
|
-
"**/*.h",
|
|
14
|
-
"**/*.cpp",
|
|
15
|
-
"**/*.hpp",
|
|
16
|
-
"**/*.cc",
|
|
17
|
-
"**/*.cxx",
|
|
18
|
-
"**/*.cs",
|
|
19
|
-
"**/*.php",
|
|
20
|
-
"**/*.rb",
|
|
21
|
-
"**/*.swift",
|
|
22
|
-
"**/*.kt",
|
|
23
|
-
"**/*.kts",
|
|
24
|
-
"**/*.dart",
|
|
25
|
-
"**/*.svelte",
|
|
26
|
-
"**/*.liquid",
|
|
27
|
-
"**/*.pas",
|
|
28
|
-
"**/*.dpr",
|
|
29
|
-
"**/*.dpk",
|
|
30
|
-
"**/*.lpr",
|
|
31
|
-
"**/*.dfm",
|
|
32
|
-
"**/*.fmx"
|
|
33
|
-
],
|
|
34
|
-
"exclude": [
|
|
35
|
-
"**/.git/**",
|
|
36
|
-
"**/node_modules/**",
|
|
37
|
-
"**/vendor/**",
|
|
38
|
-
"**/Pods/**",
|
|
39
|
-
"**/dist/**",
|
|
40
|
-
"**/build/**",
|
|
41
|
-
"**/out/**",
|
|
42
|
-
"**/bin/**",
|
|
43
|
-
"**/obj/**",
|
|
44
|
-
"**/target/**",
|
|
45
|
-
"**/*.min.js",
|
|
46
|
-
"**/*.bundle.js",
|
|
47
|
-
"**/.next/**",
|
|
48
|
-
"**/.nuxt/**",
|
|
49
|
-
"**/.svelte-kit/**",
|
|
50
|
-
"**/.output/**",
|
|
51
|
-
"**/.turbo/**",
|
|
52
|
-
"**/.cache/**",
|
|
53
|
-
"**/.parcel-cache/**",
|
|
54
|
-
"**/.vite/**",
|
|
55
|
-
"**/.astro/**",
|
|
56
|
-
"**/.docusaurus/**",
|
|
57
|
-
"**/.gatsby/**",
|
|
58
|
-
"**/.webpack/**",
|
|
59
|
-
"**/.nx/**",
|
|
60
|
-
"**/.yarn/cache/**",
|
|
61
|
-
"**/.pnpm-store/**",
|
|
62
|
-
"**/storybook-static/**",
|
|
63
|
-
"**/.expo/**",
|
|
64
|
-
"**/web-build/**",
|
|
65
|
-
"**/ios/Pods/**",
|
|
66
|
-
"**/ios/build/**",
|
|
67
|
-
"**/android/build/**",
|
|
68
|
-
"**/android/.gradle/**",
|
|
69
|
-
"**/__pycache__/**",
|
|
70
|
-
"**/.venv/**",
|
|
71
|
-
"**/venv/**",
|
|
72
|
-
"**/site-packages/**",
|
|
73
|
-
"**/dist-packages/**",
|
|
74
|
-
"**/.pytest_cache/**",
|
|
75
|
-
"**/.mypy_cache/**",
|
|
76
|
-
"**/.ruff_cache/**",
|
|
77
|
-
"**/.tox/**",
|
|
78
|
-
"**/.nox/**",
|
|
79
|
-
"**/*.egg-info/**",
|
|
80
|
-
"**/.eggs/**",
|
|
81
|
-
"**/go/pkg/mod/**",
|
|
82
|
-
"**/target/debug/**",
|
|
83
|
-
"**/target/release/**",
|
|
84
|
-
"**/.gradle/**",
|
|
85
|
-
"**/.m2/**",
|
|
86
|
-
"**/generated-sources/**",
|
|
87
|
-
"**/.kotlin/**",
|
|
88
|
-
"**/.dart_tool/**",
|
|
89
|
-
"**/.vs/**",
|
|
90
|
-
"**/.nuget/**",
|
|
91
|
-
"**/artifacts/**",
|
|
92
|
-
"**/publish/**",
|
|
93
|
-
"**/cmake-build-*/**",
|
|
94
|
-
"**/CMakeFiles/**",
|
|
95
|
-
"**/bazel-*/**",
|
|
96
|
-
"**/vcpkg_installed/**",
|
|
97
|
-
"**/.conan/**",
|
|
98
|
-
"**/Debug/**",
|
|
99
|
-
"**/Release/**",
|
|
100
|
-
"**/x64/**",
|
|
101
|
-
"**/release/**",
|
|
102
|
-
"**/*.app/**",
|
|
103
|
-
"**/*.asar",
|
|
104
|
-
"**/DerivedData/**",
|
|
105
|
-
"**/.build/**",
|
|
106
|
-
"**/.swiftpm/**",
|
|
107
|
-
"**/xcuserdata/**",
|
|
108
|
-
"**/Carthage/Build/**",
|
|
109
|
-
"**/SourcePackages/**",
|
|
110
|
-
"**/__history/**",
|
|
111
|
-
"**/__recovery/**",
|
|
112
|
-
"**/*.dcu",
|
|
113
|
-
"**/.composer/**",
|
|
114
|
-
"**/storage/framework/**",
|
|
115
|
-
"**/bootstrap/cache/**",
|
|
116
|
-
"**/.bundle/**",
|
|
117
|
-
"**/tmp/cache/**",
|
|
118
|
-
"**/public/assets/**",
|
|
119
|
-
"**/public/packs/**",
|
|
120
|
-
"**/.yardoc/**",
|
|
121
|
-
"**/coverage/**",
|
|
122
|
-
"**/htmlcov/**",
|
|
123
|
-
"**/.nyc_output/**",
|
|
124
|
-
"**/test-results/**",
|
|
125
|
-
"**/.coverage/**",
|
|
126
|
-
"**/.idea/**",
|
|
127
|
-
"**/logs/**",
|
|
128
|
-
"**/tmp/**",
|
|
129
|
-
"**/temp/**",
|
|
130
|
-
"**/_build/**",
|
|
131
|
-
"**/docs/_build/**",
|
|
132
|
-
"**/site/**"
|
|
133
|
-
],
|
|
134
|
-
"languages": [],
|
|
135
|
-
"frameworks": [],
|
|
136
|
-
"maxFileSize": 1048576,
|
|
137
|
-
"extractDocstrings": true,
|
|
138
|
-
"trackCallSites": true,
|
|
139
|
-
"enableEmbeddings": true
|
|
140
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# showConfirmDialog React 16 Compatibility Fix Plan
|
|
2
|
-
|
|
3
|
-
Created: 2026-04-09
|
|
4
|
-
Author: smarcet@gmail.com
|
|
5
|
-
Status: VERIFIED
|
|
6
|
-
Approved: Yes
|
|
7
|
-
Iterations: 0
|
|
8
|
-
Worktree: No
|
|
9
|
-
Type: Bugfix
|
|
10
|
-
|
|
11
|
-
## Summary
|
|
12
|
-
|
|
13
|
-
**Symptom:** `showConfirmDialog` causes "Module not found: Error: Can't resolve 'react-dom/client'" build error on React 16 projects, despite a `/* webpackIgnore: true */` dynamic import guard.
|
|
14
|
-
|
|
15
|
-
**Trigger:** Any consuming project on React 16 that bundles `openstack-uicore-foundation` hits the error during webpack build.
|
|
16
|
-
|
|
17
|
-
**Root Cause:** `src/components/mui/showConfirmDialog.js:27` — The `import(/* webpackIgnore: true */ "react-dom/client")` compiles into the UMD output as a bare `import("react-dom/client")` (the magic comment is stripped during this library's build). When a consuming project's webpack processes the compiled bundle, it encounters the bare dynamic import, tries to resolve `react-dom/client`, and fails because React 16 has no such module path.
|
|
18
|
-
|
|
19
|
-
## Investigation
|
|
20
|
-
|
|
21
|
-
- **Evolution:** Original code (cd39cf3) used only `ReactDOM.render()`. PR #214 (094c6b9) added `require("react-dom/client")` in try/catch for React 18+ support — caused the same build error. Commit 6c95b33 replaced `require()` with `import(/* webpackIgnore: true */ ...)` — the magic comment works for THIS library's webpack but is stripped from the compiled UMD output.
|
|
22
|
-
- **Confirmed in built output:** `lib/components/mui/show-confirm-dialog.js` contains literal `await import("react-dom/client")` with no webpack annotation — any consuming webpack resolves it at build time.
|
|
23
|
-
- **Key insight:** The `webpackIgnore` comment is a build-time directive that only affects the webpack instance that processes the source file. It does not survive into the output and cannot protect consuming projects.
|
|
24
|
-
- **Internal callers** (5 files: mui-table, mui-table-sortable, mui-table-editable, meta-field-values, additional-input-list) all use `showConfirmDialog` as a plain imperative function — `const isConfirmed = await showConfirmDialog({...})`.
|
|
25
|
-
|
|
26
|
-
## Fix Approach
|
|
27
|
-
|
|
28
|
-
**Chosen:** Bridge Pattern + Context Provider
|
|
29
|
-
|
|
30
|
-
**Why:** Completely eliminates all references to `react-dom/client` from the source and compiled output. The dialog renders inside the existing React tree (managed by whatever React version the app uses), so no version-specific rendering API is needed. Preserves the imperative `showConfirmDialog()` API unchanged.
|
|
31
|
-
|
|
32
|
-
**Alternatives considered:**
|
|
33
|
-
- *Configuration injection* (`configureConfirmDialog({ createRoot })`) — simpler but less ergonomic; consumer must handle version detection and import themselves.
|
|
34
|
-
- *Remove createRoot entirely* (pure `ReactDOM.render`) — works on 16/17/18 but breaks React 19 where `ReactDOM.render` was removed.
|
|
35
|
-
|
|
36
|
-
**How it works:**
|
|
37
|
-
1. A new `ConfirmDialogProvider` component manages dialog state (open/closed, options, resolve callback) and renders `ConfirmDialog` within the existing React tree.
|
|
38
|
-
2. On mount, the provider registers a "bridge" callback in a module-level variable inside `showConfirmDialog.js`.
|
|
39
|
-
3. When `showConfirmDialog()` is called, it delegates to the bridge if registered. If no provider is mounted, it falls back to `ReactDOM.render()` with a console warning (backward compat for React 16/17/18 consumers who haven't added the provider yet).
|
|
40
|
-
4. Zero references to `react-dom/client` remain in the codebase.
|
|
41
|
-
|
|
42
|
-
**Files:**
|
|
43
|
-
- `src/components/mui/showConfirmDialog.js` — Add bridge registration, fallback logic
|
|
44
|
-
- `src/components/mui/ConfirmDialogProvider.js` — NEW: Provider component
|
|
45
|
-
- `src/components/index.js` — Export the new provider
|
|
46
|
-
- `webpack.common.js` — Add entry point for the new provider
|
|
47
|
-
|
|
48
|
-
**Tests:**
|
|
49
|
-
- `src/components/mui/__tests__/show-confirm-dialog.test.js` — Update for bridge-based flow
|
|
50
|
-
- `src/components/mui/__tests__/confirm-dialog-provider.test.js` — NEW: Provider tests
|
|
51
|
-
|
|
52
|
-
**Defense-in-depth:** Not applicable — this is a build-time resolution error, not a data flow issue.
|
|
53
|
-
|
|
54
|
-
## Progress
|
|
55
|
-
|
|
56
|
-
- [x] Task 1: Implement bridge pattern + provider
|
|
57
|
-
- [x] Task 2: Verify
|
|
58
|
-
**Tasks:** 2 | **Done:** 2
|
|
59
|
-
|
|
60
|
-
## Tasks
|
|
61
|
-
|
|
62
|
-
### Task 1: Implement bridge pattern + provider
|
|
63
|
-
|
|
64
|
-
**Objective:** Replace the `react-dom/client` dynamic import with a bridge pattern. Create `ConfirmDialogProvider`, modify `showConfirmDialog` to use bridge with ReactDOM.render fallback, export the new provider.
|
|
65
|
-
|
|
66
|
-
**Files:**
|
|
67
|
-
- `src/components/mui/showConfirmDialog.js` — Remove `getCreateRoot()`, add bridge registration exports (`_registerBridge`, `_unregisterBridge`). When bridge is registered, delegate. When not, fall back to `ReactDOM.render()` with `console.warn` suggesting provider migration.
|
|
68
|
-
- `src/components/mui/ConfirmDialogProvider.js` — NEW: Functional component using `useState` + `useEffect`. On mount, registers bridge via `_registerBridge`. Bridge callback sets dialog state and returns a Promise. Renders `<ConfirmDialog>` when dialog state is active. On unmount, calls `_unregisterBridge`.
|
|
69
|
-
- `src/components/index.js` — Add export: `export { default as ConfirmDialogProvider } from './mui/ConfirmDialogProvider'`
|
|
70
|
-
- `webpack.common.js` — Add entry: `'components/mui/confirm-dialog-provider': './src/components/mui/ConfirmDialogProvider.js'`
|
|
71
|
-
|
|
72
|
-
**TDD:**
|
|
73
|
-
1. Write regression test: import `showConfirmDialog` without mocking `react-dom/client` — verify no reference to `react-dom/client` exists in the module
|
|
74
|
-
2. Write provider test: render `ConfirmDialogProvider`, call `showConfirmDialog`, verify dialog appears and resolves correctly
|
|
75
|
-
3. Write fallback test: call `showConfirmDialog` without provider mounted — verify `ReactDOM.render` is called with console warning
|
|
76
|
-
4. Verify all existing tests still pass (callers mock `showConfirmDialog` so they are unaffected)
|
|
77
|
-
|
|
78
|
-
**Verify:** `npx jest --no-cache`
|
|
79
|
-
|
|
80
|
-
### Task 2: Verify
|
|
81
|
-
|
|
82
|
-
**Objective:** Full test suite passes, no regressions across all components that use `showConfirmDialog`.
|
|
83
|
-
**Verify:** `npx jest --no-cache && grep -r "react-dom/client" src/ && echo "FAIL: react-dom/client still referenced" || echo "PASS: no react-dom/client references"`
|