fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

View File

@@ -0,0 +1,28 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _utils = require("../utils");
var _options = require("../options");
async function notToMatch(instance, matcher, options) {
options = (0, _options.defaultOptions)(options);
const {
page,
handle
} = await (0, _utils.getContext)(instance, () => document.body);
try {
await page.waitForFunction((handle, matcher) => {
if (!handle) return false;
return handle.textContent.match(new RegExp(matcher)) === null;
}, options, handle, matcher);
} catch (error) {
throw (0, _utils.enhanceError)(error, `Text found "${matcher}"`);
}
}
var _default = notToMatch;
exports.default = _default;

View File

@@ -0,0 +1,42 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _utils = require("../utils");
var _options = require("../options");
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
async function notToMatchElement(instance, selector, _ref = {}) {
let {
text
} = _ref,
options = _objectWithoutPropertiesLoose(_ref, ["text"]);
options = (0, _options.defaultOptions)(options);
const {
page,
handle
} = await (0, _utils.getContext)(instance, () => document);
try {
await page.waitForFunction((handle, selector, text) => {
const elements = handle.querySelectorAll(selector);
if (text !== undefined) {
return [...elements].every(({
textContent
}) => !textContent.match(text));
}
return elements.length === 0;
}, options, handle, selector, text);
} catch (error) {
throw (0, _utils.enhanceError)(error, `Element ${selector}${text !== undefined ? ` (text: "${text}") ` : ' '}found`);
}
}
var _default = notToMatchElement;
exports.default = _default;

View File

@@ -0,0 +1,39 @@
"use strict";
exports.__esModule = true;
exports.setupPage = void 0;
function waitForFrame(page) {
let fulfill;
const promise = new Promise(resolve => {
fulfill = resolve;
});
function checkFrame() {
const frame = page.frames().find(f => f.parentFrame() !== null);
if (frame) fulfill(frame);else page.once(`frameattached`, checkFrame);
}
checkFrame();
return promise;
}
const setupPage = (pageType, cb) => {
let currentPage = page;
beforeEach(async () => {
if (pageType === `Page`) {
cb({
currentPage
});
return;
}
await page.goto(`http://localhost:${process.env.TEST_SERVER_PORT}/frame.html`);
currentPage = await waitForFrame(page);
cb({
currentPage
});
});
};
exports.setupPage = setupPage;

16
node_modules/expect-puppeteer/lib/matchers/toClick.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _toMatchElement = _interopRequireDefault(require("./toMatchElement"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function toClick(instance, selector, options) {
const element = await (0, _toMatchElement.default)(instance, selector, options);
await element.click(options);
}
var _default = toClick;
exports.default = _default;

View File

@@ -0,0 +1,19 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
async function toDisplayDialog(page, block) {
return new Promise((resolve, reject) => {
const handleDialog = dialog => {
page.removeListener('dialog', handleDialog);
resolve(dialog);
};
page.on('dialog', handleDialog);
block().catch(reject);
});
}
var _default = toDisplayDialog;
exports.default = _default;

29
node_modules/expect-puppeteer/lib/matchers/toFill.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _toMatchElement = _interopRequireDefault(require("./toMatchElement"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
async function toFill(instance, selector, value, options) {
const _ref = options || {},
{
delay
} = _ref,
toMatchElementOptions = _objectWithoutPropertiesLoose(_ref, ["delay"]);
const element = await (0, _toMatchElement.default)(instance, selector, toMatchElementOptions);
await element.click({
clickCount: 3
});
await element.type(value, {
delay
});
}
var _default = toFill;
exports.default = _default;

View File

@@ -0,0 +1,25 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _options = require("../options");
var _toFill = _interopRequireDefault(require("./toFill"));
var _toMatchElement = _interopRequireDefault(require("./toMatchElement"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-restricted-syntax, no-await-in-loop */
async function toFillForm(instance, selector, values, options) {
options = (0, _options.defaultOptions)(options);
const form = await (0, _toMatchElement.default)(instance, selector, options);
for (const name of Object.keys(values)) {
await (0, _toFill.default)(form, `[name="${name}"]`, values[name], options);
}
}
var _default = toFillForm;
exports.default = _default;

42
node_modules/expect-puppeteer/lib/matchers/toMatch.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _utils = require("../utils");
var _options = require("../options");
async function toMatch(instance, matcher, options) {
options = (0, _options.defaultOptions)(options);
const {
page,
handle
} = await (0, _utils.getContext)(instance, () => document.body);
const {
text,
regexp
} = (0, _utils.expandSearchExpr)(matcher);
try {
await page.waitForFunction((handle, text, regexp) => {
if (!handle) return false;
if (regexp !== null) {
const [, pattern, flags] = regexp.match(/\/(.*)\/(.*)?/);
return handle.textContent.replace(/\s+/g, ' ').trim().match(new RegExp(pattern, flags)) !== null;
}
if (text !== null) {
return handle.textContent.replace(/\s+/g, ' ').trim().includes(text);
}
return false;
}, options, handle, text, regexp);
} catch (error) {
throw (0, _utils.enhanceError)(error, `Text not found "${matcher}"`);
}
}
var _default = toMatch;
exports.default = _default;

View File

@@ -0,0 +1,73 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _utils = require("../utils");
var _options = require("../options");
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
async function toMatchElement(instance, selector, _ref = {}) {
let {
text: searchExpr,
visible = false
} = _ref,
options = _objectWithoutPropertiesLoose(_ref, ["text", "visible"]);
options = (0, _options.defaultOptions)(options);
const {
page,
handle
} = await (0, _utils.getContext)(instance, () => document);
const {
text,
regexp
} = (0, _utils.expandSearchExpr)(searchExpr);
const getElement = (handle, selector, text, regexp, visible) => {
function hasVisibleBoundingBox(element) {
const rect = element.getBoundingClientRect();
return !!(rect.top || rect.bottom || rect.width || rect.height);
}
const isVisible = element => {
if (visible) {
const style = window.getComputedStyle(element);
return style && style.visibility !== 'hidden' && hasVisibleBoundingBox(element);
}
return true;
};
const elements = [...handle.querySelectorAll(selector)].filter(isVisible);
if (regexp !== null) {
const [, pattern, flags] = regexp.match(/\/(.*)\/(.*)?/);
return elements.find(({
textContent
}) => textContent.replace(/\s+/g, ' ').trim().match(new RegExp(pattern, flags)));
}
if (text !== null) {
return elements.find(({
textContent
}) => textContent.replace(/\s+/g, ' ').trim().includes(text));
}
return elements[0];
};
try {
await page.waitForFunction(getElement, options, handle, selector, text, regexp, visible);
} catch (error) {
throw (0, _utils.enhanceError)(error, `Element ${selector}${text !== null || regexp !== null ? ` (text: "${text || regexp}") ` : ' '}not found`);
}
const jsHandle = await page.evaluateHandle(getElement, handle, selector, text, regexp, visible);
return jsHandle.asElement();
}
var _default = toMatchElement;
exports.default = _default;

80
node_modules/expect-puppeteer/lib/matchers/toSelect.js generated vendored Normal file
View File

@@ -0,0 +1,80 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _toMatchElement = _interopRequireDefault(require("./toMatchElement"));
var _utils = require("../utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-restricted-syntax */
function select(page, element, value) {
return page.evaluate((element, value) => {
if (element.nodeName.toLowerCase() !== 'select') throw new Error('Element is not a <select> element.');
const options = Array.from(element.options);
element.value = undefined;
for (const option of options) {
option.selected = value === option.value;
if (option.selected && !element.multiple) break;
}
element.dispatchEvent(new Event('input', {
bubbles: true
}));
element.dispatchEvent(new Event('change', {
bubbles: true
}));
return options.filter(option => option.selected).map(option => option.value);
}, element, value);
}
async function toSelect(instance, selector, valueOrText, options) {
const element = await (0, _toMatchElement.default)(instance, selector, options);
const optionElements = await element.$$('option');
const optionsAttributes = await Promise.all(optionElements.map(async option => {
const textContentProperty = await option.getProperty('textContent');
const valueProperty = await option.getProperty('value');
return {
value: await valueProperty.jsonValue(),
textContent: await textContentProperty.jsonValue()
};
}));
const option = optionsAttributes.find(({
value,
textContent
}) => value === valueOrText || textContent === valueOrText);
if (!option) {
throw new Error(`Option not found "${selector}" ("${valueOrText}")`);
}
const {
page
} = await (0, _utils.getContext)(instance, () => document);
await select(page, element, option.value); // await page.select(selector, foundValue)
// console.log(select.select)
// select.select()
// const foundValue = await select.$$eval(
// `${selector} option`,
// (options, valueOrText, selector) => {
// const option = options.find(
// option =>
// option.value === valueOrText || option.textContent === valueOrText,
// )
// if (!option) {
// throw new Error(`Option not found "${selector}" ("${valueOrText}")`)
// }
// return option.value
// },
// valueOrText,
// selector,
// )
//
// await page.select(selector, foundValue)
}
var _default = toSelect;
exports.default = _default;

View File

@@ -0,0 +1,17 @@
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _toMatchElement = _interopRequireDefault(require("./toMatchElement"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function toUploadFile(instance, selector, file, options) {
const input = await (0, _toMatchElement.default)(instance, selector, options);
const files = Array.isArray(file) ? file : [file];
await input.uploadFile(...files);
}
var _default = toUploadFile;
exports.default = _default;