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

89
node_modules/rungen/src/controls/async.js generated vendored Normal file
View File

@@ -0,0 +1,89 @@
import is from '../utils/is'
import {error} from '../utils/helpers'
import createDispatcher from '../utils/dispatcher'
export const promise = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.promise(value)) return false
value.then(next, raiseNext)
return true
}
const forkedTasks = new Map()
export const fork = (value, next, rungen) => {
if (!is.fork(value)) return false
const task = Symbol('fork')
const dispatcher = createDispatcher()
forkedTasks.set(task, dispatcher)
rungen(
value.iterator.apply(null, value.args),
result => dispatcher.dispatch(result),
err => dispatcher.dispatch(error(err))
)
const unsubscribe = dispatcher.subscribe(() => {
unsubscribe()
forkedTasks.delete(task)
})
next(task)
return true
}
export const join = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.join(value)) return false
const dispatcher = forkedTasks.get(value.task)
if (!dispatcher) {
raiseNext('join error : task not found')
} else {
const unsubscribe = dispatcher.subscribe(result => {
unsubscribe()
next(result)
})
}
return true
}
export const race = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.race(value)) return false
let finished = false
const success = (result, k, v) => {
if (finished) return
finished = true
result[k] = v
next(result)
}
const fail = err => {
if (finished) return
raiseNext(err)
}
if (is.array(value.competitors)) {
const result = value.competitors.map(() => false)
value.competitors.forEach((competitor, index) => {
rungen(competitor, output => success(result, index, output), fail)
})
}
else {
const result = Object.keys(value.competitors).reduce((p, c) => {
p[c] = false
return p
}, {})
Object.keys(value.competitors).forEach(index => {
rungen(value.competitors[index], output => success(result, index, output), fail)
})
}
return true
}
const subscribe = (value, next) => {
if (!is.subscribe(value)) return false
if (!is.channel(value.channel)) {
throw new Error('the first argument of "subscribe" must be a valid channel')
}
const unsubscribe = value.channel.subscribe(ret => {
unsubscribe && unsubscribe()
next(ret)
})
return true
}
export default [promise, fork, join, race, subscribe]

83
node_modules/rungen/src/controls/builtin.js generated vendored Normal file
View File

@@ -0,0 +1,83 @@
import is from '../utils/is'
export const any = (value, next, rungen, yieldNext) => {
yieldNext(value)
return true
}
export const error = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.error(value)) return false
raiseNext(value.error)
return true
}
export const object = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.all(value) || !is.obj(value.value)) return false
const result = {}
const keys = Object.keys(value.value)
let count = 0
let hasError = false
const gotResultSuccess = (key, ret) => {
if (hasError) return
result[key] = ret
count++
if (count === keys.length) {
yieldNext(result)
}
}
const gotResultError = (key, error) => {
if (hasError) return
hasError = true
raiseNext(error)
}
keys.map(key => {
rungen(
value.value[key],
ret => gotResultSuccess(key, ret),
err => gotResultError(key, err)
)
})
return true
}
export const array = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.all(value) || !is.array(value.value)) return false
const result = []
let count = 0
let hasError = false
const gotResultSuccess = (key, ret) => {
if (hasError) return
result[key] = ret
count++
if (count === value.value.length) {
yieldNext(result)
}
}
const gotResultError = (key, error) => {
if (hasError) return
hasError = true
raiseNext(error)
}
value.value.map((v, key) => {
rungen(
v,
ret => gotResultSuccess(key, ret),
err => gotResultError(key, err)
)
})
return true
}
export const iterator = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.iterator(value)) return false
rungen(value, next, raiseNext)
return true
}
export default [error, iterator, array, object, any]

22
node_modules/rungen/src/controls/wrap.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import is from '../utils/is'
export const call = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.call(value)) return false
try {
next(value.func.apply(value.context, value.args))
} catch (err) {
raiseNext(err)
}
return true
}
export const cps = (value, next, rungen, yieldNext, raiseNext) => {
if (!is.cps(value)) return false
value.func.call(null, ...value.args, (err, result) => {
if (err) raiseNext(err)
else next(result)
})
return true
}
export default [call, cps]

38
node_modules/rungen/src/create.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
import builtinControls from './controls/builtin'
import is from './utils/is'
const create = (userControls = []) => {
const controls = [...userControls, ...builtinControls]
const runtime = (input, success = () => {}, error = () => {}) => {
const iterate = gen => {
const yieldValue = isError => ret => {
try {
const { value, done } = isError ? gen.throw(ret) : gen.next(ret)
if (done) return success(value)
next(value)
} catch (e) {
return error(e)
}
}
const next = ret => {
controls.some(control => control(ret, next, runtime, yieldValue(false), yieldValue(true)))
}
yieldValue(false)()
}
const iterator = is.iterator(input)
? input
: function* () {
return yield input
}()
iterate(iterator, success, error)
}
return runtime
}
export default create;

10
node_modules/rungen/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import create from './create'
export {create}
import asyncControls from './controls/async'
export {asyncControls}
import wrapControls from './controls/wrap'
export {wrapControls}
export * from './utils/helpers'

17
node_modules/rungen/src/utils/dispatcher.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
const createDispatcher = () => {
let listeners = []
return {
subscribe: (listener) => {
listeners.push(listener)
return () => {
listeners = listeners.filter(l => l !== listener)
}
},
dispatch: (action) => {
listeners.slice().forEach(listener => listener(action))
}
}
}
export default createDispatcher

77
node_modules/rungen/src/utils/helpers.js generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import keys from './keys'
export const all = value => ({
type: keys.all,
value
})
export const error = err => ({
type: keys.error,
error: err
})
export const fork = (iterator, ...args) => ({
type: keys.fork,
iterator,
args
})
export const join = task => ({
type: keys.join,
task
})
export const race = competitors => ({
type: keys.race,
competitors
})
export const delay = timeout => new Promise(resolve => {
setTimeout(() => resolve(true), timeout)
})
export const invoke = (func, ...args) => ({
type: keys.call,
func,
context: null,
args
})
export const call = (func, context, ...args) => ({
type: keys.call,
func,
context,
args
})
export const apply = (func, context, args) => ({
type: keys.call,
func,
context,
args
})
export const cps = (func, ...args) => ({
type: keys.cps,
func,
args
})
export const subscribe = channel => ({
type: keys.subscribe,
channel
})
export const createChannel = callback => {
const listeners = []
const subscribe = l => {
listeners.push(l)
return () => listeners.splice(listeners.indexOf(l), 1)
}
const next = val => listeners.forEach(l => l(val))
callback(next)
return {
subscribe
}
}

20
node_modules/rungen/src/utils/is.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import keys from './keys'
const is = {
obj : value => typeof value === 'object' && !! value,
all : value => is.obj(value) && value.type === keys.all,
error : value => is.obj(value) && value.type === keys.error,
array : Array.isArray,
func : value => typeof value === 'function',
promise : value => value && is.func(value.then),
iterator : value => value && is.func(value.next) && is.func(value.throw),
fork : value => is.obj(value) && value.type === keys.fork,
join : value => is.obj(value) && value.type === keys.join,
race : value => is.obj(value) && value.type === keys.race,
call : value => is.obj(value) && value.type === keys.call,
cps : value => is.obj(value) && value.type === keys.cps,
subscribe : value => is.obj(value) && value.type === keys.subscribe,
channel : value => is.obj(value) && is.func(value.subscribe)
}
export default is

12
node_modules/rungen/src/utils/keys.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
const keys = {
all : Symbol('all'),
error : Symbol('error'),
fork : Symbol('fork'),
join : Symbol('join'),
race : Symbol('race'),
call : Symbol('call'),
cps : Symbol('cps'),
subscribe : Symbol('subscribe')
}
export default keys