imean-service-engine-htmx-plugin 2.4.0 → 2.6.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.
- package/dist/index.d.mts +50 -106
- package/dist/index.d.ts +50 -106
- package/dist/index.js +287 -580
- package/dist/index.mjs +287 -577
- package/docs/README.md +0 -38
- package/package.json +1 -1
- package/docs/alpinejs-interactive-components.md +0 -653
- package/docs/custom-form-field-renderers.md +0 -541
- package/docs/field-editor-best-practices.md +0 -320
- package/docs/hono-html-best-practices.md +0 -509
package/dist/index.js
CHANGED
|
@@ -80,7 +80,6 @@ function renderActionButton(action, index) {
|
|
|
80
80
|
close,
|
|
81
81
|
submit,
|
|
82
82
|
formId,
|
|
83
|
-
onClick,
|
|
84
83
|
className = "",
|
|
85
84
|
target
|
|
86
85
|
} = action;
|
|
@@ -106,8 +105,7 @@ function renderActionButton(action, index) {
|
|
|
106
105
|
index
|
|
107
106
|
);
|
|
108
107
|
}
|
|
109
|
-
|
|
110
|
-
if (finalOnClick) {
|
|
108
|
+
if (close) {
|
|
111
109
|
const variantStyles = {
|
|
112
110
|
primary: "bg-blue-600 text-white hover:bg-blue-700",
|
|
113
111
|
secondary: "bg-gray-200 text-gray-800 hover:bg-gray-300",
|
|
@@ -125,7 +123,8 @@ function renderActionButton(action, index) {
|
|
|
125
123
|
"button",
|
|
126
124
|
{
|
|
127
125
|
type: "button",
|
|
128
|
-
|
|
126
|
+
"x-data": CLOSE_DIALOG_ALPINE_DATA,
|
|
127
|
+
"x-on:click": "closeDialog()",
|
|
129
128
|
className: `px-4 py-2 rounded transition-colors font-medium ${buttonStyle} ${className}`,
|
|
130
129
|
"data-testid": testId2,
|
|
131
130
|
...confirm && { "data-confirm": confirm },
|
|
@@ -169,15 +168,25 @@ function renderActionButton(action, index) {
|
|
|
169
168
|
function renderActionButtons(actions) {
|
|
170
169
|
return actions.map((action, index) => renderActionButton(action, index));
|
|
171
170
|
}
|
|
172
|
-
var
|
|
171
|
+
var CLOSE_DIALOG_ALPINE_DATA;
|
|
173
172
|
var init_action_button_renderer = __esm({
|
|
174
173
|
"src/utils/action-button-renderer.tsx"() {
|
|
175
174
|
init_button();
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
175
|
+
CLOSE_DIALOG_ALPINE_DATA = `{
|
|
176
|
+
closeDialog() {
|
|
177
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
178
|
+
if (backdrop) {
|
|
179
|
+
backdrop.classList.add('dialog-exit');
|
|
180
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
181
|
+
if (content) {
|
|
182
|
+
content.classList.add('dialog-content-exit');
|
|
183
|
+
}
|
|
184
|
+
setTimeout(() => {
|
|
185
|
+
backdrop.remove();
|
|
186
|
+
}, 200);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}`;
|
|
181
190
|
}
|
|
182
191
|
});
|
|
183
192
|
|
|
@@ -307,11 +316,6 @@ var init_cdn_cache = __esm({
|
|
|
307
316
|
url: "https://unpkg.com/htmx.org@latest",
|
|
308
317
|
mimeType: "application/javascript"
|
|
309
318
|
},
|
|
310
|
-
{
|
|
311
|
-
name: "hyperscript",
|
|
312
|
-
url: "https://unpkg.com/hyperscript.org@latest",
|
|
313
|
-
mimeType: "application/javascript"
|
|
314
|
-
},
|
|
315
319
|
{
|
|
316
320
|
name: "tailwindcss",
|
|
317
321
|
url: "https://cdn.tailwindcss.com",
|
|
@@ -321,16 +325,6 @@ var init_cdn_cache = __esm({
|
|
|
321
325
|
name: "alpinejs",
|
|
322
326
|
url: "https://unpkg.com/alpinejs@latest/dist/cdn.min.js",
|
|
323
327
|
mimeType: "application/javascript"
|
|
324
|
-
},
|
|
325
|
-
{
|
|
326
|
-
name: "idiomorph",
|
|
327
|
-
url: "https://unpkg.com/idiomorph@0.7.4/dist/idiomorph-ext.min.js",
|
|
328
|
-
mimeType: "application/javascript"
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
name: "sortablejs",
|
|
332
|
-
url: "https://unpkg.com/sortablejs@latest/Sortable.min.js",
|
|
333
|
-
mimeType: "application/javascript"
|
|
334
328
|
}
|
|
335
329
|
];
|
|
336
330
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -555,8 +549,8 @@ function renderFormField(field, initialData, formFieldRenderers) {
|
|
|
555
549
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: customRenderer({
|
|
556
550
|
field,
|
|
557
551
|
value: parsedValue,
|
|
558
|
-
initialData,
|
|
559
|
-
|
|
552
|
+
item: initialData,
|
|
553
|
+
name: field.name
|
|
560
554
|
}) }),
|
|
561
555
|
field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 mt-1", children: field.description })
|
|
562
556
|
]
|
|
@@ -631,7 +625,7 @@ function renderFormField(field, initialData, formFieldRenderers) {
|
|
|
631
625
|
name: field.name,
|
|
632
626
|
required: field.required,
|
|
633
627
|
placeholder: field.placeholder || (isJsonString(value) ? "JSON \u683C\u5F0F\u6570\u636E" : ""),
|
|
634
|
-
rows: isJsonString(value) ? 10 :
|
|
628
|
+
rows: isJsonString(value) ? Math.max(10, value.split("\n").length) : Math.max(5, Math.ceil(value.length / 100)),
|
|
635
629
|
className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 resize-y font-mono text-sm",
|
|
636
630
|
"data-testid": `input-${field.name}`,
|
|
637
631
|
children: isJsonString(value) ? formatJsonString(value) : value
|
|
@@ -2809,286 +2803,6 @@ var DefaultListFeature = class extends BaseFeature {
|
|
|
2809
2803
|
}
|
|
2810
2804
|
};
|
|
2811
2805
|
|
|
2812
|
-
// src/component-system/store.ts
|
|
2813
|
-
var STATE_EXPIRATION_TIME = 864e5;
|
|
2814
|
-
var StateStore = class _StateStore {
|
|
2815
|
-
static instance;
|
|
2816
|
-
state;
|
|
2817
|
-
constructor() {
|
|
2818
|
-
this.state = /* @__PURE__ */ new Map();
|
|
2819
|
-
setInterval(() => {
|
|
2820
|
-
this.state.forEach((state) => {
|
|
2821
|
-
if (state.lastUpdated < Date.now() - STATE_EXPIRATION_TIME) {
|
|
2822
|
-
this.state.delete(state.instanceId);
|
|
2823
|
-
}
|
|
2824
|
-
});
|
|
2825
|
-
}, 3e4);
|
|
2826
|
-
}
|
|
2827
|
-
static get() {
|
|
2828
|
-
if (!_StateStore.instance) {
|
|
2829
|
-
_StateStore.instance = new _StateStore();
|
|
2830
|
-
}
|
|
2831
|
-
return _StateStore.instance;
|
|
2832
|
-
}
|
|
2833
|
-
/** 获取实例状态 */
|
|
2834
|
-
getState(instanceId) {
|
|
2835
|
-
const state = this.state.get(instanceId);
|
|
2836
|
-
if (state) {
|
|
2837
|
-
return state;
|
|
2838
|
-
}
|
|
2839
|
-
const newState = {
|
|
2840
|
-
instanceId,
|
|
2841
|
-
data: {
|
|
2842
|
-
props: {},
|
|
2843
|
-
state: {}
|
|
2844
|
-
},
|
|
2845
|
-
lastUpdated: Date.now()
|
|
2846
|
-
};
|
|
2847
|
-
this.state.set(instanceId, newState);
|
|
2848
|
-
return newState;
|
|
2849
|
-
}
|
|
2850
|
-
/** 设置实例状态 */
|
|
2851
|
-
setState(instanceId, state) {
|
|
2852
|
-
const instanceState = this.getState(instanceId);
|
|
2853
|
-
instanceState.data = Object.assign(instanceState.data.state, state);
|
|
2854
|
-
instanceState.lastUpdated = Date.now();
|
|
2855
|
-
}
|
|
2856
|
-
};
|
|
2857
|
-
|
|
2858
|
-
// src/component-system/utils.ts
|
|
2859
|
-
var globalIdCounter = 0;
|
|
2860
|
-
function generateUniqueId() {
|
|
2861
|
-
return `htmx-cid-${globalIdCounter++}`;
|
|
2862
|
-
}
|
|
2863
|
-
var HTMX_COMPONENT_PREFIX = "/_htmx_components";
|
|
2864
|
-
|
|
2865
|
-
// src/component-system/context.tsx
|
|
2866
|
-
var RenderContext = class {
|
|
2867
|
-
constructor(prefix, instanceId, componentName) {
|
|
2868
|
-
this.prefix = prefix;
|
|
2869
|
-
this.instanceId = instanceId;
|
|
2870
|
-
this.componentName = componentName;
|
|
2871
|
-
}
|
|
2872
|
-
// 生成唯一 ID(使用全局共享计数器,避免冲突)
|
|
2873
|
-
$id() {
|
|
2874
|
-
return generateUniqueId();
|
|
2875
|
-
}
|
|
2876
|
-
setState(state) {
|
|
2877
|
-
StateStore.get().setState(this.instanceId, state);
|
|
2878
|
-
}
|
|
2879
|
-
get state() {
|
|
2880
|
-
return StateStore.get().getState(this.instanceId).data.state;
|
|
2881
|
-
}
|
|
2882
|
-
get props() {
|
|
2883
|
-
return StateStore.get().getState(this.instanceId).data.props;
|
|
2884
|
-
}
|
|
2885
|
-
// 生成方法 URL(使用当前 instanceId)
|
|
2886
|
-
url(methodName, params) {
|
|
2887
|
-
const baseUrl = `${this.prefix}/${HTMX_COMPONENT_PREFIX}/${this.componentName}/${this.instanceId}/${methodName}`;
|
|
2888
|
-
if (params && Object.keys(params).length > 0) {
|
|
2889
|
-
const queryString = new URLSearchParams(
|
|
2890
|
-
Object.entries(params).reduce(
|
|
2891
|
-
(acc, [key, value]) => {
|
|
2892
|
-
acc[key] = String(value);
|
|
2893
|
-
return acc;
|
|
2894
|
-
},
|
|
2895
|
-
{}
|
|
2896
|
-
)
|
|
2897
|
-
).toString();
|
|
2898
|
-
return `${baseUrl}?${queryString}`;
|
|
2899
|
-
}
|
|
2900
|
-
return baseUrl;
|
|
2901
|
-
}
|
|
2902
|
-
callMethod(methodName, params) {
|
|
2903
|
-
const selectors = Object.entries(params).map(([name, expression]) => `${name}:${expression}`).join(",");
|
|
2904
|
-
return {
|
|
2905
|
-
"hx-post": this.url(methodName),
|
|
2906
|
-
"hx-vals": `js:{_params_:{${selectors}}}`,
|
|
2907
|
-
"hx-params": "_state_,_params_,_this_value_"
|
|
2908
|
-
};
|
|
2909
|
-
}
|
|
2910
|
-
};
|
|
2911
|
-
var ComponentContext = class extends RenderContext {
|
|
2912
|
-
constructor(prefix, ctx, componentName) {
|
|
2913
|
-
const routeParams = ctx.req.param();
|
|
2914
|
-
const instanceId = String(routeParams.instanceId || "");
|
|
2915
|
-
super(prefix, instanceId, componentName);
|
|
2916
|
-
this.ctx = ctx;
|
|
2917
|
-
}
|
|
2918
|
-
// 获取所有参数(统一接口:聚合 query string 和 body)
|
|
2919
|
-
async params() {
|
|
2920
|
-
const params = {};
|
|
2921
|
-
const routeParams = this.ctx.req.param();
|
|
2922
|
-
Object.assign(params, routeParams);
|
|
2923
|
-
const url = new URL(this.ctx.req.url);
|
|
2924
|
-
for (const [key, value] of url.searchParams.entries()) {
|
|
2925
|
-
params[key] = value;
|
|
2926
|
-
}
|
|
2927
|
-
const contentType = this.ctx.req.header("Content-Type") || "";
|
|
2928
|
-
if (contentType.includes("application/json")) {
|
|
2929
|
-
try {
|
|
2930
|
-
const body = await this.ctx.req.json();
|
|
2931
|
-
Object.assign(params, body);
|
|
2932
|
-
} catch (e) {
|
|
2933
|
-
console.warn("[ComponentContext] Failed to parse JSON body:", e);
|
|
2934
|
-
}
|
|
2935
|
-
} else if (this.ctx.req.method === "POST" || this.ctx.req.method === "PUT" || this.ctx.req.method === "PATCH" || this.ctx.req.method === "DELETE") {
|
|
2936
|
-
try {
|
|
2937
|
-
const formData = await this.ctx.req.formData();
|
|
2938
|
-
for (const [key, value] of formData.entries()) {
|
|
2939
|
-
params[key] = value instanceof File ? value : value.toString();
|
|
2940
|
-
}
|
|
2941
|
-
} catch (e) {
|
|
2942
|
-
console.warn("[ComponentContext] Failed to parse form data:", e);
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
return params;
|
|
2946
|
-
}
|
|
2947
|
-
// 获取查询参数
|
|
2948
|
-
query() {
|
|
2949
|
-
const url = new URL(this.ctx.req.url);
|
|
2950
|
-
return Object.fromEntries(url.searchParams.entries());
|
|
2951
|
-
}
|
|
2952
|
-
// 获取请求体
|
|
2953
|
-
async body() {
|
|
2954
|
-
const contentType = this.ctx.req.header("Content-Type") || "";
|
|
2955
|
-
if (contentType.includes("application/json")) {
|
|
2956
|
-
try {
|
|
2957
|
-
return await this.ctx.req.json();
|
|
2958
|
-
} catch (e) {
|
|
2959
|
-
console.warn("[ComponentContext] Failed to parse JSON body:", e);
|
|
2960
|
-
return {};
|
|
2961
|
-
}
|
|
2962
|
-
}
|
|
2963
|
-
try {
|
|
2964
|
-
const formData = await this.ctx.req.formData();
|
|
2965
|
-
const body = {};
|
|
2966
|
-
for (const [key, value] of formData.entries()) {
|
|
2967
|
-
body[key] = value instanceof File ? value : value.toString();
|
|
2968
|
-
}
|
|
2969
|
-
return body;
|
|
2970
|
-
} catch (e) {
|
|
2971
|
-
console.warn("[ComponentContext] Failed to parse form data:", e);
|
|
2972
|
-
return {};
|
|
2973
|
-
}
|
|
2974
|
-
}
|
|
2975
|
-
};
|
|
2976
|
-
|
|
2977
|
-
// src/component-system/component.tsx
|
|
2978
|
-
var METHOD_METADATA_KEY = /* @__PURE__ */ Symbol("htmx:method");
|
|
2979
|
-
function Method(config) {
|
|
2980
|
-
return function(target, propertyKey, _descriptor) {
|
|
2981
|
-
if (!target[METHOD_METADATA_KEY]) {
|
|
2982
|
-
target[METHOD_METADATA_KEY] = /* @__PURE__ */ new Map();
|
|
2983
|
-
}
|
|
2984
|
-
target[METHOD_METADATA_KEY].set(propertyKey, {
|
|
2985
|
-
method: config?.method || "get",
|
|
2986
|
-
path: config?.path
|
|
2987
|
-
});
|
|
2988
|
-
};
|
|
2989
|
-
}
|
|
2990
|
-
var HtmxComponent = class {
|
|
2991
|
-
constructor(name) {
|
|
2992
|
-
this.name = name;
|
|
2993
|
-
}
|
|
2994
|
-
prefix;
|
|
2995
|
-
// 组件函数
|
|
2996
|
-
Component = (props) => {
|
|
2997
|
-
const instanceId = generateUniqueId();
|
|
2998
|
-
const state = StateStore.get().getState(instanceId).data;
|
|
2999
|
-
state.props = props;
|
|
3000
|
-
state.state = {};
|
|
3001
|
-
const renderCtx = new RenderContext(
|
|
3002
|
-
this.prefix,
|
|
3003
|
-
instanceId,
|
|
3004
|
-
this.name
|
|
3005
|
-
);
|
|
3006
|
-
return this.render(renderCtx, props);
|
|
3007
|
-
};
|
|
3008
|
-
// 返回 JSX script 元素
|
|
3009
|
-
// 获取所有标记为 @Method() 的方法
|
|
3010
|
-
// 注意:handler 不再绑定 this,因为方法会接收 ComponentContext 作为第一个参数
|
|
3011
|
-
static getMethods(component) {
|
|
3012
|
-
const methods = /* @__PURE__ */ new Map();
|
|
3013
|
-
const metadata = component[METHOD_METADATA_KEY];
|
|
3014
|
-
if (!metadata) return methods;
|
|
3015
|
-
for (const [methodName, config] of metadata.entries()) {
|
|
3016
|
-
const handler = component[methodName];
|
|
3017
|
-
methods.set(methodName, {
|
|
3018
|
-
method: config.method,
|
|
3019
|
-
path: config.path,
|
|
3020
|
-
handler
|
|
3021
|
-
});
|
|
3022
|
-
}
|
|
3023
|
-
return methods;
|
|
3024
|
-
}
|
|
3025
|
-
};
|
|
3026
|
-
var HtmxComponentHandler = class {
|
|
3027
|
-
constructor(hono, prefix, components) {
|
|
3028
|
-
this.hono = hono;
|
|
3029
|
-
this.prefix = prefix;
|
|
3030
|
-
this.components = components;
|
|
3031
|
-
for (const component of this.components) {
|
|
3032
|
-
component.prefix = this.prefix;
|
|
3033
|
-
this.registerHandler(component);
|
|
3034
|
-
}
|
|
3035
|
-
}
|
|
3036
|
-
registerHandler(component) {
|
|
3037
|
-
const methods = HtmxComponent.getMethods(component);
|
|
3038
|
-
for (const [methodName, methodConfig] of methods) {
|
|
3039
|
-
const routePath = `${this.prefix}/${HTMX_COMPONENT_PREFIX}/${component.name}/:instanceId/${methodName}`;
|
|
3040
|
-
imeanServiceEngine.logger.info(
|
|
3041
|
-
`[HtmxComponent] Registering handler ${methodConfig.method} ${routePath}`
|
|
3042
|
-
);
|
|
3043
|
-
this.hono[methodConfig.method](routePath, async (ctx) => {
|
|
3044
|
-
return this.handleComponentMethod(
|
|
3045
|
-
ctx,
|
|
3046
|
-
component,
|
|
3047
|
-
methodConfig.handler.bind(component)
|
|
3048
|
-
);
|
|
3049
|
-
});
|
|
3050
|
-
}
|
|
3051
|
-
}
|
|
3052
|
-
async handleComponentMethod(ctx, component, handler) {
|
|
3053
|
-
const componentContext = new ComponentContext(
|
|
3054
|
-
this.prefix,
|
|
3055
|
-
ctx,
|
|
3056
|
-
component.name
|
|
3057
|
-
);
|
|
3058
|
-
const result = await handler(componentContext);
|
|
3059
|
-
if (result instanceof Object && ("target" in result || "swap" in result || "body" in result || "oobs" in result)) {
|
|
3060
|
-
const { target, swap, body, oobs, trigger } = result;
|
|
3061
|
-
const headers = {};
|
|
3062
|
-
let bodyContent = body;
|
|
3063
|
-
if (target) headers["HX-Retarget"] = target;
|
|
3064
|
-
if (swap) headers["HX-Reswap"] = swap;
|
|
3065
|
-
if (trigger) headers["HX-Trigger"] = trigger;
|
|
3066
|
-
if (oobs) {
|
|
3067
|
-
oobs.forEach((oob) => {
|
|
3068
|
-
oob.props["hx-swap-oob"] = "true";
|
|
3069
|
-
});
|
|
3070
|
-
if (!body) {
|
|
3071
|
-
headers["HX-Reswap"] = "delete";
|
|
3072
|
-
}
|
|
3073
|
-
bodyContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3074
|
-
body,
|
|
3075
|
-
oobs
|
|
3076
|
-
] });
|
|
3077
|
-
}
|
|
3078
|
-
return ctx.html(bodyContent, 200, headers);
|
|
3079
|
-
}
|
|
3080
|
-
if (result === null) {
|
|
3081
|
-
return ctx.html(/* @__PURE__ */ jsxRuntime.jsx("div", {}), 200, {
|
|
3082
|
-
"HX-Reswap": "none"
|
|
3083
|
-
});
|
|
3084
|
-
}
|
|
3085
|
-
if (result instanceof Response) {
|
|
3086
|
-
return result;
|
|
3087
|
-
}
|
|
3088
|
-
return ctx.html(result, 200);
|
|
3089
|
-
}
|
|
3090
|
-
};
|
|
3091
|
-
|
|
3092
2806
|
// src/utils/path.ts
|
|
3093
2807
|
function modelNameToPath(modelName) {
|
|
3094
2808
|
return `/${modelName.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
|
|
@@ -3100,8 +2814,9 @@ function ErrorAlert(props) {
|
|
|
3100
2814
|
type = "error",
|
|
3101
2815
|
showClose = true,
|
|
3102
2816
|
className = "",
|
|
3103
|
-
autoClose = 5e3
|
|
2817
|
+
autoClose = 5e3,
|
|
3104
2818
|
// 默认 5 秒自动关闭
|
|
2819
|
+
"hx-swap-oob": hxSwapOob
|
|
3105
2820
|
} = props;
|
|
3106
2821
|
const typeClasses = {
|
|
3107
2822
|
error: "bg-red-50 border-red-200 text-red-800",
|
|
@@ -3190,12 +2905,20 @@ function ErrorAlert(props) {
|
|
|
3190
2905
|
const now = Date.now();
|
|
3191
2906
|
this.elapsedTime = now - this.startTime;
|
|
3192
2907
|
this.progress = Math.max(0, 100 - (this.elapsedTime / this.autoCloseDelay) * 100);
|
|
2908
|
+
// \u66F4\u65B0\u8FDB\u5EA6\u6761\u6837\u5F0F
|
|
2909
|
+
const progressBar = this.$el.querySelector('.progress-bar');
|
|
2910
|
+
if (progressBar) {
|
|
2911
|
+
progressBar.style.width = this.progress + '%';
|
|
2912
|
+
}
|
|
3193
2913
|
if (this.progress > 0 && this.visible) {
|
|
3194
2914
|
this.progressTimer = requestAnimationFrame(updateProgress);
|
|
3195
2915
|
}
|
|
3196
2916
|
};
|
|
3197
2917
|
this.progressTimer = requestAnimationFrame(updateProgress);
|
|
3198
2918
|
},
|
|
2919
|
+
getProgressStyle() {
|
|
2920
|
+
return { width: this.progress + '%' };
|
|
2921
|
+
},
|
|
3199
2922
|
pauseAutoClose() {
|
|
3200
2923
|
if (this.autoCloseTimer) {
|
|
3201
2924
|
clearTimeout(this.autoCloseTimer);
|
|
@@ -3224,6 +2947,9 @@ function ErrorAlert(props) {
|
|
|
3224
2947
|
cancelAnimationFrame(this.progressTimer);
|
|
3225
2948
|
this.progressTimer = null;
|
|
3226
2949
|
}
|
|
2950
|
+
// \u6DFB\u52A0\u6DE1\u51FA\u52A8\u753B
|
|
2951
|
+
this.$el.classList.add('error-alert-exit');
|
|
2952
|
+
// \u52A8\u753B\u7ED3\u675F\u540E\u5B8C\u5168\u79FB\u9664\u5143\u7D20\uFF0C\u4E0D\u7559\u7A7A div
|
|
3227
2953
|
setTimeout(() => {
|
|
3228
2954
|
if (this.$el && this.$el.parentNode) {
|
|
3229
2955
|
this.$el.parentNode.removeChild(this.$el);
|
|
@@ -3234,6 +2960,9 @@ function ErrorAlert(props) {
|
|
|
3234
2960
|
visible: true,
|
|
3235
2961
|
close() {
|
|
3236
2962
|
this.visible = false;
|
|
2963
|
+
// \u6DFB\u52A0\u6DE1\u51FA\u52A8\u753B
|
|
2964
|
+
this.$el.classList.add('error-alert-exit');
|
|
2965
|
+
// \u52A8\u753B\u7ED3\u675F\u540E\u5B8C\u5168\u79FB\u9664\u5143\u7D20\uFF0C\u4E0D\u7559\u7A7A div
|
|
3237
2966
|
setTimeout(() => {
|
|
3238
2967
|
if (this.$el && this.$el.parentNode) {
|
|
3239
2968
|
this.$el.parentNode.removeChild(this.$el);
|
|
@@ -3255,18 +2984,26 @@ function ErrorAlert(props) {
|
|
|
3255
2984
|
alpineProps["@mouseenter"] = "pauseAutoClose()";
|
|
3256
2985
|
alpineProps["@mouseleave"] = "resumeAutoClose()";
|
|
3257
2986
|
}
|
|
2987
|
+
const htmxProps = {};
|
|
2988
|
+
if (hxSwapOob) {
|
|
2989
|
+
htmxProps["hx-swap-oob"] = hxSwapOob;
|
|
2990
|
+
}
|
|
3258
2991
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3259
2992
|
"div",
|
|
3260
2993
|
{
|
|
3261
2994
|
...alpineProps,
|
|
3262
|
-
|
|
2995
|
+
...htmxProps,
|
|
2996
|
+
className: `w-full border rounded-lg p-4 shadow-lg ${typeClasses[type]} ${className} relative overflow-hidden pointer-events-auto`,
|
|
3263
2997
|
role: "alert",
|
|
2998
|
+
style: {
|
|
2999
|
+
animation: "slideInRight 0.3s ease-out"
|
|
3000
|
+
},
|
|
3264
3001
|
children: [
|
|
3265
3002
|
autoClose > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 h-1 bg-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3266
3003
|
"div",
|
|
3267
3004
|
{
|
|
3268
|
-
className: `h-full ${progressBarColors[type]}`,
|
|
3269
|
-
...{ ":style": "
|
|
3005
|
+
className: `h-full ${progressBarColors[type]} progress-bar`,
|
|
3006
|
+
...{ "x-bind:style": "getProgressStyle()" }
|
|
3270
3007
|
}
|
|
3271
3008
|
) }),
|
|
3272
3009
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start", children: [
|
|
@@ -3385,6 +3122,9 @@ async function createFeatureContext(ctx, page, feature, user, options) {
|
|
|
3385
3122
|
};
|
|
3386
3123
|
return featureContext;
|
|
3387
3124
|
}
|
|
3125
|
+
function generateDialogId() {
|
|
3126
|
+
return `dialog-${Date.now()}}`;
|
|
3127
|
+
}
|
|
3388
3128
|
function Dialog(props) {
|
|
3389
3129
|
const {
|
|
3390
3130
|
title,
|
|
@@ -3396,6 +3136,7 @@ function Dialog(props) {
|
|
|
3396
3136
|
actions = [],
|
|
3397
3137
|
fixedContentHeight = false
|
|
3398
3138
|
} = props;
|
|
3139
|
+
const dialogId = generateDialogId();
|
|
3399
3140
|
const sizeClasses = {
|
|
3400
3141
|
sm: "max-w-md",
|
|
3401
3142
|
md: "max-w-lg",
|
|
@@ -3403,19 +3144,33 @@ function Dialog(props) {
|
|
|
3403
3144
|
xl: "max-w-4xl",
|
|
3404
3145
|
full: "max-w-7xl"
|
|
3405
3146
|
};
|
|
3406
|
-
const
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3147
|
+
const alpineData = `{
|
|
3148
|
+
closeDialog() {
|
|
3149
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
3150
|
+
if (backdrop) {
|
|
3151
|
+
backdrop.classList.add('dialog-exit');
|
|
3152
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
3153
|
+
if (content) {
|
|
3154
|
+
content.classList.add('dialog-content-exit');
|
|
3155
|
+
}
|
|
3156
|
+
setTimeout(() => {
|
|
3157
|
+
backdrop.remove();
|
|
3158
|
+
}, 200);
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
}`;
|
|
3411
3162
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3412
3163
|
"div",
|
|
3413
3164
|
{
|
|
3165
|
+
id: dialogId,
|
|
3414
3166
|
className: "fixed inset-0 bg-black bg-opacity-50 z-[100] flex items-center justify-center p-4 dialog-backdrop",
|
|
3415
3167
|
style: {
|
|
3416
3168
|
animation: "fadeIn 0.2s ease-out"
|
|
3417
3169
|
},
|
|
3418
|
-
|
|
3170
|
+
"x-data": alpineData,
|
|
3171
|
+
...closeOnBackdropClick && {
|
|
3172
|
+
"x-on:click": "if ($event.target === $el) closeDialog()"
|
|
3173
|
+
},
|
|
3419
3174
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3420
3175
|
"div",
|
|
3421
3176
|
{
|
|
@@ -3423,7 +3178,7 @@ function Dialog(props) {
|
|
|
3423
3178
|
style: {
|
|
3424
3179
|
animation: "slideIn 0.3s ease-out"
|
|
3425
3180
|
},
|
|
3426
|
-
|
|
3181
|
+
...{ "x-on:click.stop": "" },
|
|
3427
3182
|
children: [
|
|
3428
3183
|
(title || showClose) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4 border-b border-gray-200 bg-white flex items-center justify-between", children: [
|
|
3429
3184
|
title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: title }),
|
|
@@ -3431,7 +3186,7 @@ function Dialog(props) {
|
|
|
3431
3186
|
"button",
|
|
3432
3187
|
{
|
|
3433
3188
|
className: "text-gray-400 hover:text-gray-600 transition-colors",
|
|
3434
|
-
|
|
3189
|
+
"x-on:click": "closeDialog()",
|
|
3435
3190
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3436
3191
|
"svg",
|
|
3437
3192
|
{
|
|
@@ -3528,11 +3283,26 @@ function PermissionDeniedContent(props) {
|
|
|
3528
3283
|
Button,
|
|
3529
3284
|
{
|
|
3530
3285
|
variant: "secondary",
|
|
3531
|
-
|
|
3286
|
+
"x-data": `{
|
|
3287
|
+
closeDialog() {
|
|
3288
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
3289
|
+
if (backdrop) {
|
|
3290
|
+
backdrop.classList.add('dialog-exit');
|
|
3291
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
3292
|
+
if (content) {
|
|
3293
|
+
content.classList.add('dialog-content-exit');
|
|
3294
|
+
}
|
|
3295
|
+
setTimeout(() => {
|
|
3296
|
+
backdrop.remove();
|
|
3297
|
+
}, 200);
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
}`,
|
|
3301
|
+
"x-on:click": "closeDialog()",
|
|
3532
3302
|
children: "\u5173\u95ED"
|
|
3533
3303
|
}
|
|
3534
3304
|
),
|
|
3535
|
-
!isDialog && userInfo && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary",
|
|
3305
|
+
!isDialog && userInfo && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary", onclick: "window.history.back()", children: "\u8FD4\u56DE" })
|
|
3536
3306
|
] })
|
|
3537
3307
|
] });
|
|
3538
3308
|
}
|
|
@@ -3553,13 +3323,8 @@ var getResourceUrl = (prefix, name) => {
|
|
|
3553
3323
|
function globalScripts(prefix) {
|
|
3554
3324
|
return html.html`
|
|
3555
3325
|
<script src=${getResourceUrl(prefix, "htmx")}></script>
|
|
3556
|
-
<script src=${getResourceUrl(prefix, "htmx-ext-form-json")}></script>
|
|
3557
|
-
<script src=${getResourceUrl(prefix, "hyperscript")}></script>
|
|
3558
3326
|
<script src=${getResourceUrl(prefix, "tailwindcss")}></script>
|
|
3559
3327
|
<script src=${getResourceUrl(prefix, "alpinejs")} defer></script>
|
|
3560
|
-
<script src=${getResourceUrl(prefix, "sortablejs")}></script>
|
|
3561
|
-
<script src=${getResourceUrl(prefix, "idiomorph")}></script>
|
|
3562
|
-
<script type="module" src=${getResourceUrl(prefix, "datastar")}></script>
|
|
3563
3328
|
`;
|
|
3564
3329
|
}
|
|
3565
3330
|
function globalStyles() {
|
|
@@ -3689,36 +3454,6 @@ function globalStyles() {
|
|
|
3689
3454
|
}
|
|
3690
3455
|
</style>`;
|
|
3691
3456
|
}
|
|
3692
|
-
function sortableScript() {
|
|
3693
|
-
html.html`<script>
|
|
3694
|
-
if (typeof htmx !== "undefined" && typeof Sortable !== "undefined") {
|
|
3695
|
-
htmx.onLoad(function (content) {
|
|
3696
|
-
var sortables = content.querySelectorAll(".sortable");
|
|
3697
|
-
for (var i = 0; i < sortables.length; i++) {
|
|
3698
|
-
var sortable = sortables[i];
|
|
3699
|
-
// 检查是否已经初始化
|
|
3700
|
-
if (sortable.sortableInstance) {
|
|
3701
|
-
continue;
|
|
3702
|
-
}
|
|
3703
|
-
var sortableInstance = new Sortable(sortable, {
|
|
3704
|
-
animation: 150,
|
|
3705
|
-
ghostClass: "sortable-ghost",
|
|
3706
|
-
filter: ".htmx-indicator",
|
|
3707
|
-
onMove: function (evt) {
|
|
3708
|
-
return evt.related.className.indexOf("htmx-indicator") === -1;
|
|
3709
|
-
},
|
|
3710
|
-
});
|
|
3711
|
-
sortable.sortableInstance = sortableInstance;
|
|
3712
|
-
sortable.addEventListener("htmx:afterSwap", function () {
|
|
3713
|
-
if (sortable.sortableInstance) {
|
|
3714
|
-
sortable.sortableInstance.option("disabled", false);
|
|
3715
|
-
}
|
|
3716
|
-
});
|
|
3717
|
-
}
|
|
3718
|
-
});
|
|
3719
|
-
}
|
|
3720
|
-
</script>`;
|
|
3721
|
-
}
|
|
3722
3457
|
function Breadcrumb(props) {
|
|
3723
3458
|
const { items } = props;
|
|
3724
3459
|
if (items.length === 0) {
|
|
@@ -4074,7 +3809,7 @@ function SortableList(props) {
|
|
|
4074
3809
|
function StringArrayEditor(props) {
|
|
4075
3810
|
const {
|
|
4076
3811
|
value,
|
|
4077
|
-
|
|
3812
|
+
name,
|
|
4078
3813
|
placeholder = "\u8BF7\u8F93\u5165\u5185\u5BB9",
|
|
4079
3814
|
allowEmpty = false,
|
|
4080
3815
|
rows = 1
|
|
@@ -4082,185 +3817,174 @@ function StringArrayEditor(props) {
|
|
|
4082
3817
|
const initialItems = value || [];
|
|
4083
3818
|
const initialDataJson = JSON.stringify({
|
|
4084
3819
|
items: initialItems.map((item) => item || ""),
|
|
4085
|
-
fieldName,
|
|
3820
|
+
fieldName: name,
|
|
4086
3821
|
placeholder,
|
|
4087
3822
|
allowEmpty,
|
|
4088
3823
|
rows
|
|
4089
3824
|
});
|
|
4090
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4091
|
-
"div",
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
"button",
|
|
4098
|
-
{
|
|
4099
|
-
type: "button",
|
|
4100
|
-
...{
|
|
4101
|
-
"x-on:click": `
|
|
3825
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", "x-data": initialDataJson, children: [
|
|
3826
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3827
|
+
"button",
|
|
3828
|
+
{
|
|
3829
|
+
type: "button",
|
|
3830
|
+
...{
|
|
3831
|
+
"x-on:click": `
|
|
4102
3832
|
items.push('');
|
|
4103
3833
|
`
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
3834
|
+
},
|
|
3835
|
+
className: "px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium flex items-center gap-2",
|
|
3836
|
+
"data-testid": `${name}-add-button`,
|
|
3837
|
+
children: [
|
|
3838
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3839
|
+
"svg",
|
|
3840
|
+
{
|
|
3841
|
+
className: "w-4 h-4",
|
|
3842
|
+
fill: "none",
|
|
3843
|
+
stroke: "currentColor",
|
|
3844
|
+
viewBox: "0 0 24 24",
|
|
3845
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3846
|
+
"path",
|
|
4110
3847
|
{
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4116
|
-
"path",
|
|
4117
|
-
{
|
|
4118
|
-
strokeLinecap: "round",
|
|
4119
|
-
strokeLinejoin: "round",
|
|
4120
|
-
strokeWidth: "2",
|
|
4121
|
-
d: "M12 4v16m8-8H4"
|
|
4122
|
-
}
|
|
4123
|
-
)
|
|
3848
|
+
strokeLinecap: "round",
|
|
3849
|
+
strokeLinejoin: "round",
|
|
3850
|
+
strokeWidth: "2",
|
|
3851
|
+
d: "M12 4v16m8-8H4"
|
|
4124
3852
|
}
|
|
4125
|
-
)
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
3853
|
+
)
|
|
3854
|
+
}
|
|
3855
|
+
),
|
|
3856
|
+
"\u6DFB\u52A0\u9879"
|
|
3857
|
+
]
|
|
3858
|
+
}
|
|
3859
|
+
) }),
|
|
3860
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3861
|
+
"div",
|
|
3862
|
+
{
|
|
3863
|
+
"x-show": "items.length > 0",
|
|
3864
|
+
"data-testid": `${name}-list-container`,
|
|
3865
|
+
...{
|
|
3866
|
+
"@sortable:change.stop": `
|
|
4137
3867
|
(function() {
|
|
4138
3868
|
const { oldIndex, newIndex } = $event.detail;
|
|
4139
3869
|
[items[oldIndex], items[newIndex]] = [items[newIndex], items[oldIndex]];
|
|
4140
3870
|
})();
|
|
4141
3871
|
`
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
}
|
|
4157
|
-
);
|
|
3872
|
+
},
|
|
3873
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SortableList, { className: "space-y-2", handle: "[data-drag-handle]", children: /* @__PURE__ */ jsxRuntime.jsx("template", { "x-for": "(item, index) in items", "x-bind:key": "index", children: /* @__PURE__ */ jsxRuntime.jsx(ArrayItem, { fieldName: name, rows }) }) })
|
|
3874
|
+
}
|
|
3875
|
+
),
|
|
3876
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3877
|
+
"div",
|
|
3878
|
+
{
|
|
3879
|
+
className: "empty-state text-center py-8 text-gray-400 text-sm border border-dashed border-gray-300 rounded-lg",
|
|
3880
|
+
"x-show": "items.length === 0",
|
|
3881
|
+
"data-testid": `${name}-empty-state`,
|
|
3882
|
+
children: '\u6682\u65E0\u9879\uFF0C\u70B9\u51FB"\u6DFB\u52A0\u9879"\u6309\u94AE\u6DFB\u52A0'
|
|
3883
|
+
}
|
|
3884
|
+
)
|
|
3885
|
+
] });
|
|
4158
3886
|
}
|
|
4159
|
-
function ArrayItem({
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
3887
|
+
function ArrayItem({
|
|
3888
|
+
fieldName,
|
|
3889
|
+
rows = 1
|
|
3890
|
+
}) {
|
|
3891
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-array-item": true, className: "flex items-center gap-2 group", children: [
|
|
3892
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3893
|
+
"div",
|
|
3894
|
+
{
|
|
3895
|
+
className: "flex-shrink-0 cursor-move text-gray-400 hover:text-gray-600 transition-colors p-1",
|
|
3896
|
+
"data-drag-handle": true,
|
|
3897
|
+
"data-testid": `${fieldName}-drag-handle`,
|
|
3898
|
+
title: "\u62D6\u62FD\u6392\u5E8F",
|
|
3899
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3900
|
+
"svg",
|
|
4168
3901
|
{
|
|
4169
|
-
className: "
|
|
4170
|
-
"
|
|
4171
|
-
"
|
|
4172
|
-
|
|
3902
|
+
className: "w-5 h-5",
|
|
3903
|
+
fill: "none",
|
|
3904
|
+
stroke: "currentColor",
|
|
3905
|
+
viewBox: "0 0 24 24",
|
|
4173
3906
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4174
|
-
"
|
|
3907
|
+
"path",
|
|
4175
3908
|
{
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4181
|
-
"path",
|
|
4182
|
-
{
|
|
4183
|
-
strokeLinecap: "round",
|
|
4184
|
-
strokeLinejoin: "round",
|
|
4185
|
-
strokeWidth: "2",
|
|
4186
|
-
d: "M4 8h16M4 16h16"
|
|
4187
|
-
}
|
|
4188
|
-
)
|
|
3909
|
+
strokeLinecap: "round",
|
|
3910
|
+
strokeLinejoin: "round",
|
|
3911
|
+
strokeWidth: "2",
|
|
3912
|
+
d: "M4 8h16M4 16h16"
|
|
4189
3913
|
}
|
|
4190
3914
|
)
|
|
4191
3915
|
}
|
|
4192
|
-
)
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
3916
|
+
)
|
|
3917
|
+
}
|
|
3918
|
+
),
|
|
3919
|
+
rows === 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3920
|
+
"input",
|
|
3921
|
+
{
|
|
3922
|
+
type: "text",
|
|
3923
|
+
"x-model": "items[index]",
|
|
3924
|
+
"x-bind:placeholder": "placeholder + ' ' + (index + 1)",
|
|
3925
|
+
className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",
|
|
3926
|
+
"data-testid": `${fieldName}-input`,
|
|
3927
|
+
"x-bind:required": "!allowEmpty"
|
|
3928
|
+
}
|
|
3929
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3930
|
+
"textarea",
|
|
3931
|
+
{
|
|
3932
|
+
"x-model": "items[index]",
|
|
3933
|
+
"x-bind:placeholder": "placeholder + ' ' + (index + 1)",
|
|
3934
|
+
rows,
|
|
3935
|
+
className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-y",
|
|
3936
|
+
"data-testid": `${fieldName}-input`,
|
|
3937
|
+
"x-bind:required": "!allowEmpty"
|
|
3938
|
+
}
|
|
3939
|
+
),
|
|
3940
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3941
|
+
"input",
|
|
3942
|
+
{
|
|
3943
|
+
type: "hidden",
|
|
3944
|
+
"x-bind:name": "fieldName + '[' + index + ']'",
|
|
3945
|
+
"x-bind:value": "item"
|
|
3946
|
+
}
|
|
3947
|
+
),
|
|
3948
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3949
|
+
"button",
|
|
3950
|
+
{
|
|
3951
|
+
type: "button",
|
|
3952
|
+
...{
|
|
3953
|
+
"x-on:click": `
|
|
4228
3954
|
items.splice(index, 1);
|
|
4229
3955
|
`
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
3956
|
+
},
|
|
3957
|
+
className: "flex-shrink-0 px-3 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors",
|
|
3958
|
+
"data-testid": `${fieldName}-remove-button`,
|
|
3959
|
+
title: "\u5220\u9664\u6B64\u9879",
|
|
3960
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3961
|
+
"svg",
|
|
3962
|
+
{
|
|
3963
|
+
className: "w-5 h-5",
|
|
3964
|
+
fill: "none",
|
|
3965
|
+
stroke: "currentColor",
|
|
3966
|
+
viewBox: "0 0 24 24",
|
|
4234
3967
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4235
|
-
"
|
|
3968
|
+
"path",
|
|
4236
3969
|
{
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4242
|
-
"path",
|
|
4243
|
-
{
|
|
4244
|
-
strokeLinecap: "round",
|
|
4245
|
-
strokeLinejoin: "round",
|
|
4246
|
-
strokeWidth: "2",
|
|
4247
|
-
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
4248
|
-
}
|
|
4249
|
-
)
|
|
3970
|
+
strokeLinecap: "round",
|
|
3971
|
+
strokeLinejoin: "round",
|
|
3972
|
+
strokeWidth: "2",
|
|
3973
|
+
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
4250
3974
|
}
|
|
4251
3975
|
)
|
|
4252
3976
|
}
|
|
4253
3977
|
)
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
);
|
|
3978
|
+
}
|
|
3979
|
+
)
|
|
3980
|
+
] });
|
|
4257
3981
|
}
|
|
4258
3982
|
function TagsEditor(props) {
|
|
4259
|
-
const { value,
|
|
3983
|
+
const { value, name, placeholder = "\u8F93\u5165\u6807\u7B7E\u540E\u6309\u56DE\u8F66\u6DFB\u52A0" } = props;
|
|
4260
3984
|
const initialTags = value || [];
|
|
4261
3985
|
const initialDataJson = JSON.stringify({
|
|
4262
3986
|
tags: initialTags.map((tag) => tag || ""),
|
|
4263
|
-
fieldName,
|
|
3987
|
+
fieldName: name,
|
|
4264
3988
|
newTag: "",
|
|
4265
3989
|
editingIndex: null,
|
|
4266
3990
|
editingValue: "",
|
|
@@ -4287,7 +4011,7 @@ function TagsEditor(props) {
|
|
|
4287
4011
|
placeholder,
|
|
4288
4012
|
autocomplete: "off",
|
|
4289
4013
|
className: "w-full px-3 py-1.5 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",
|
|
4290
|
-
"data-testid": `${
|
|
4014
|
+
"data-testid": `${name}-input`
|
|
4291
4015
|
}
|
|
4292
4016
|
),
|
|
4293
4017
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4296,7 +4020,7 @@ function TagsEditor(props) {
|
|
|
4296
4020
|
"x-show": "error && editingIndex === null",
|
|
4297
4021
|
"x-text": "error",
|
|
4298
4022
|
className: "text-red-600 text-sm p-2",
|
|
4299
|
-
id: `${
|
|
4023
|
+
id: `${name}-error`
|
|
4300
4024
|
}
|
|
4301
4025
|
)
|
|
4302
4026
|
] }),
|
|
@@ -4304,7 +4028,7 @@ function TagsEditor(props) {
|
|
|
4304
4028
|
"div",
|
|
4305
4029
|
{
|
|
4306
4030
|
"x-show": "tags.length > 0",
|
|
4307
|
-
"data-testid": `${
|
|
4031
|
+
"data-testid": `${name}-tags-container`,
|
|
4308
4032
|
...{
|
|
4309
4033
|
"@sortable:change.stop": `
|
|
4310
4034
|
(function() {
|
|
@@ -4327,8 +4051,8 @@ function TagsEditor(props) {
|
|
|
4327
4051
|
"x-bind:value": "editingIndex === index ? editingValue : tag"
|
|
4328
4052
|
}
|
|
4329
4053
|
),
|
|
4330
|
-
/* @__PURE__ */ jsxRuntime.jsx(TagItem, { fieldName }),
|
|
4331
|
-
/* @__PURE__ */ jsxRuntime.jsx(TagItemEdit, { fieldName })
|
|
4054
|
+
/* @__PURE__ */ jsxRuntime.jsx(TagItem, { fieldName: name }),
|
|
4055
|
+
/* @__PURE__ */ jsxRuntime.jsx(TagItemEdit, { fieldName: name })
|
|
4332
4056
|
] }) })
|
|
4333
4057
|
}
|
|
4334
4058
|
)
|
|
@@ -4339,7 +4063,7 @@ function TagsEditor(props) {
|
|
|
4339
4063
|
{
|
|
4340
4064
|
className: "empty-state text-center py-4 text-gray-400 text-sm border border-dashed border-gray-300 rounded-md",
|
|
4341
4065
|
"x-show": "tags.length === 0",
|
|
4342
|
-
"data-testid": `${
|
|
4066
|
+
"data-testid": `${name}-empty-state`,
|
|
4343
4067
|
children: "\u6682\u65E0\u6807\u7B7E\uFF0C\u5728\u4E0A\u65B9\u8F93\u5165\u6846\u4E2D\u8F93\u5165\u6807\u7B7E\u540E\u6309\u56DE\u8F66\u6DFB\u52A0"
|
|
4344
4068
|
}
|
|
4345
4069
|
)
|
|
@@ -4520,7 +4244,7 @@ function TagItemEdit({ fieldName }) {
|
|
|
4520
4244
|
);
|
|
4521
4245
|
}
|
|
4522
4246
|
function ObjectEditor(props) {
|
|
4523
|
-
const { value,
|
|
4247
|
+
const { value, name, objectSchema } = props;
|
|
4524
4248
|
if (!objectSchema) {
|
|
4525
4249
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border border-yellow-300 rounded-lg bg-yellow-50 text-yellow-800 text-sm", children: "\u8BF7\u63D0\u4F9B objectSchema \u53C2\u6570\u4EE5\u4F7F\u7528\u5BF9\u8C61\u7F16\u8F91\u5668" });
|
|
4526
4250
|
}
|
|
@@ -4540,7 +4264,7 @@ function ObjectEditor(props) {
|
|
|
4540
4264
|
const initialValueJson = JSON.stringify(initialObject);
|
|
4541
4265
|
JSON.stringify(fields.map((f) => f.name));
|
|
4542
4266
|
const generateField = (field) => {
|
|
4543
|
-
const fieldId = `${
|
|
4267
|
+
const fieldId = `${name}-${field.name}`;
|
|
4544
4268
|
const fieldValue = initialObject[field.name];
|
|
4545
4269
|
const fieldValueStr = fieldValue === void 0 || fieldValue === null ? "" : typeof fieldValue === "object" ? JSON.stringify(fieldValue) : String(fieldValue);
|
|
4546
4270
|
const requiredAttr = field.required ? "required" : "";
|
|
@@ -4550,11 +4274,11 @@ function ObjectEditor(props) {
|
|
|
4550
4274
|
<input
|
|
4551
4275
|
type="text"
|
|
4552
4276
|
id="${fieldId}"
|
|
4553
|
-
name="${
|
|
4277
|
+
name="${name}.${field.name}"
|
|
4554
4278
|
value="${fieldValueStr}"
|
|
4555
4279
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4556
|
-
data-testid="${
|
|
4557
|
-
oninput="updateObjectField('${
|
|
4280
|
+
data-testid="${name}-input-${field.name}"
|
|
4281
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4558
4282
|
${requiredAttr}
|
|
4559
4283
|
/>
|
|
4560
4284
|
`;
|
|
@@ -4562,11 +4286,11 @@ function ObjectEditor(props) {
|
|
|
4562
4286
|
inputElement = html.html`
|
|
4563
4287
|
<textarea
|
|
4564
4288
|
id="${fieldId}"
|
|
4565
|
-
name="${
|
|
4289
|
+
name="${name}.${field.name}"
|
|
4566
4290
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-y"
|
|
4567
4291
|
rows="4"
|
|
4568
|
-
data-testid="${
|
|
4569
|
-
oninput="updateObjectField('${
|
|
4292
|
+
data-testid="${name}-input-${field.name}"
|
|
4293
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4570
4294
|
${requiredAttr}
|
|
4571
4295
|
>${fieldValueStr}</textarea>
|
|
4572
4296
|
`;
|
|
@@ -4576,12 +4300,12 @@ function ObjectEditor(props) {
|
|
|
4576
4300
|
<input
|
|
4577
4301
|
type="number"
|
|
4578
4302
|
id="${fieldId}"
|
|
4579
|
-
name="${
|
|
4303
|
+
name="${name}.${field.name}"
|
|
4580
4304
|
value="${fieldValueStr}"
|
|
4581
4305
|
step="${step}"
|
|
4582
4306
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4583
|
-
data-testid="${
|
|
4584
|
-
oninput="updateObjectField('${
|
|
4307
|
+
data-testid="${name}-input-${field.name}"
|
|
4308
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'number', ${field.required})"
|
|
4585
4309
|
${requiredAttr}
|
|
4586
4310
|
/>
|
|
4587
4311
|
`;
|
|
@@ -4590,11 +4314,11 @@ function ObjectEditor(props) {
|
|
|
4590
4314
|
<input
|
|
4591
4315
|
type="date"
|
|
4592
4316
|
id="${fieldId}"
|
|
4593
|
-
name="${
|
|
4317
|
+
name="${name}.${field.name}"
|
|
4594
4318
|
value="${fieldValueStr}"
|
|
4595
4319
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4596
|
-
data-testid="${
|
|
4597
|
-
oninput="updateObjectField('${
|
|
4320
|
+
data-testid="${name}-input-${field.name}"
|
|
4321
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'date', ${field.required})"
|
|
4598
4322
|
${requiredAttr}
|
|
4599
4323
|
/>
|
|
4600
4324
|
`;
|
|
@@ -4603,11 +4327,11 @@ function ObjectEditor(props) {
|
|
|
4603
4327
|
<input
|
|
4604
4328
|
type="email"
|
|
4605
4329
|
id="${fieldId}"
|
|
4606
|
-
name="${
|
|
4330
|
+
name="${name}.${field.name}"
|
|
4607
4331
|
value="${fieldValueStr}"
|
|
4608
4332
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
4609
|
-
data-testid="${
|
|
4610
|
-
oninput="updateObjectField('${
|
|
4333
|
+
data-testid="${name}-input-${field.name}"
|
|
4334
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4611
4335
|
${requiredAttr}
|
|
4612
4336
|
/>
|
|
4613
4337
|
`;
|
|
@@ -4615,10 +4339,10 @@ function ObjectEditor(props) {
|
|
|
4615
4339
|
inputElement = html.html`
|
|
4616
4340
|
<select
|
|
4617
4341
|
id="${fieldId}"
|
|
4618
|
-
name="${
|
|
4342
|
+
name="${name}.${field.name}"
|
|
4619
4343
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white"
|
|
4620
|
-
data-testid="${
|
|
4621
|
-
onchange="updateObjectField('${
|
|
4344
|
+
data-testid="${name}-select-${field.name}"
|
|
4345
|
+
onchange="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4622
4346
|
${requiredAttr}
|
|
4623
4347
|
>
|
|
4624
4348
|
${!field.required ? html.html`<option value="">请选择</option>` : ""}
|
|
@@ -4641,11 +4365,11 @@ function ObjectEditor(props) {
|
|
|
4641
4365
|
<input
|
|
4642
4366
|
type="checkbox"
|
|
4643
4367
|
id="${fieldId}"
|
|
4644
|
-
name="${
|
|
4368
|
+
name="${name}.${field.name}"
|
|
4645
4369
|
${checked ? "checked" : ""}
|
|
4646
4370
|
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
|
|
4647
|
-
data-testid="${
|
|
4648
|
-
onchange="updateObjectField('${
|
|
4371
|
+
data-testid="${name}-checkbox-${field.name}"
|
|
4372
|
+
onchange="updateObjectField('${name}', '${field.name}', this.checked, 'checkbox', ${field.required}')"
|
|
4649
4373
|
/>
|
|
4650
4374
|
<label for="${fieldId}" class="ml-2 text-sm text-gray-700">
|
|
4651
4375
|
${field.label}
|
|
@@ -4654,12 +4378,12 @@ function ObjectEditor(props) {
|
|
|
4654
4378
|
`;
|
|
4655
4379
|
}
|
|
4656
4380
|
return html.html`
|
|
4657
|
-
<div class="space-y-2" data-testid="${
|
|
4381
|
+
<div class="space-y-2" data-testid="${name}-field-${field.name}">
|
|
4658
4382
|
${field.type !== "checkbox" ? html.html`
|
|
4659
4383
|
<label
|
|
4660
4384
|
for="${fieldId}"
|
|
4661
4385
|
class="block text-sm font-semibold text-gray-700"
|
|
4662
|
-
data-testid="${
|
|
4386
|
+
data-testid="${name}-label-${field.name}"
|
|
4663
4387
|
>
|
|
4664
4388
|
${field.label}
|
|
4665
4389
|
${field.required ? html.html`<span class="text-red-500 ml-1">*</span>` : ""}
|
|
@@ -4671,15 +4395,15 @@ function ObjectEditor(props) {
|
|
|
4671
4395
|
};
|
|
4672
4396
|
return html.html`
|
|
4673
4397
|
<div
|
|
4674
|
-
id="object-editor-${
|
|
4398
|
+
id="object-editor-${name}"
|
|
4675
4399
|
class="space-y-4"
|
|
4676
4400
|
data-initial-value="${initialValueJson}"
|
|
4677
4401
|
>
|
|
4678
4402
|
<input
|
|
4679
4403
|
type="hidden"
|
|
4680
|
-
name="${
|
|
4404
|
+
name="${name}"
|
|
4681
4405
|
value="${initialValueJson}"
|
|
4682
|
-
data-testid="hidden-${
|
|
4406
|
+
data-testid="hidden-${name}"
|
|
4683
4407
|
/>
|
|
4684
4408
|
<div class="space-y-4">
|
|
4685
4409
|
${fields.map((field) => generateField(field))}
|
|
@@ -4741,14 +4465,13 @@ function BaseLayout(props) {
|
|
|
4741
4465
|
<meta name="description" content="${props.description || ""}" />
|
|
4742
4466
|
${globalScripts(props.prefix)} ${globalStyles()}
|
|
4743
4467
|
</head>
|
|
4744
|
-
<body
|
|
4468
|
+
<body className="bg-gray-50" hx-indicator="#loading-bar">
|
|
4745
4469
|
${LoadingBar()} ${props.children}
|
|
4746
4470
|
<div
|
|
4747
|
-
id="
|
|
4748
|
-
|
|
4471
|
+
id="notification-container"
|
|
4472
|
+
style="position: fixed; top: 1rem; right: 1rem; z-index: 200; display: flex; flex-direction: column; gap: 0.5rem; pointer-events: none; width: 100%; max-width: 28rem; padding-left: 1rem; padding-right: 1rem;"
|
|
4749
4473
|
></div>
|
|
4750
4474
|
<div id="dialog-container"></div>
|
|
4751
|
-
${sortableScript()}
|
|
4752
4475
|
</body>
|
|
4753
4476
|
</html>
|
|
4754
4477
|
`;
|
|
@@ -5000,7 +4723,7 @@ async function handlePermissionDenied(ctx, result, options) {
|
|
|
5000
4723
|
if (isHtmxRequest) {
|
|
5001
4724
|
const headers = {
|
|
5002
4725
|
"HX-Retarget": "#dialog-container",
|
|
5003
|
-
"HX-Reswap": "
|
|
4726
|
+
"HX-Reswap": "beforeend",
|
|
5004
4727
|
"X-Permission-Denied": "true"
|
|
5005
4728
|
};
|
|
5006
4729
|
return ctx.html(
|
|
@@ -5045,22 +4768,15 @@ function buildNotificationFragments(notifications) {
|
|
|
5045
4768
|
if (notifications.length === 0) {
|
|
5046
4769
|
return null;
|
|
5047
4770
|
}
|
|
5048
|
-
return notifications.map((notification, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5049
|
-
|
|
4771
|
+
return notifications.map((notification, index) => /* @__PURE__ */ jsxRuntime.jsx("div", { id: "notification-container", "hx-swap-oob": "beforeend", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4772
|
+
ErrorAlert,
|
|
5050
4773
|
{
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
ErrorAlert,
|
|
5055
|
-
{
|
|
5056
|
-
type: notification.type,
|
|
5057
|
-
title: notification.title,
|
|
5058
|
-
message: notification.message
|
|
5059
|
-
}
|
|
5060
|
-
)
|
|
4774
|
+
type: notification.type,
|
|
4775
|
+
title: notification.title,
|
|
4776
|
+
message: notification.message
|
|
5061
4777
|
},
|
|
5062
4778
|
`notification-${index}`
|
|
5063
|
-
));
|
|
4779
|
+
) }));
|
|
5064
4780
|
}
|
|
5065
4781
|
function isEmptyContent(result) {
|
|
5066
4782
|
if (result === null || result === void 0) return true;
|
|
@@ -5154,7 +4870,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5154
4870
|
if (context.isDialog) {
|
|
5155
4871
|
return ctx.html(
|
|
5156
4872
|
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5157
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { id: "dialog-container", "hx-swap-oob": "innerHTML" }),
|
|
5158
4873
|
notificationFragments,
|
|
5159
4874
|
/* @__PURE__ */ jsxRuntime.jsx("title", { children: metadata.title })
|
|
5160
4875
|
] }),
|
|
@@ -5210,7 +4925,7 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5210
4925
|
);
|
|
5211
4926
|
}
|
|
5212
4927
|
const target = context.isDialog ? "#dialog-container" : "#main-content";
|
|
5213
|
-
const swap = context.isDialog ? "
|
|
4928
|
+
const swap = context.isDialog ? "beforeend" : "outerHTML";
|
|
5214
4929
|
const headers = {
|
|
5215
4930
|
"HX-Retarget": target,
|
|
5216
4931
|
"HX-Reswap": swap
|
|
@@ -5273,7 +4988,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5273
4988
|
useAdminLayout,
|
|
5274
4989
|
currentPath,
|
|
5275
4990
|
userInfo: user,
|
|
5276
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5277
4991
|
breadcrumbs,
|
|
5278
4992
|
actions,
|
|
5279
4993
|
children: result
|
|
@@ -5309,7 +5023,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5309
5023
|
prefix: options.prefix,
|
|
5310
5024
|
title: dynamicMetadata.title,
|
|
5311
5025
|
description: dynamicMetadata.description,
|
|
5312
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5313
5026
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5314
5027
|
AdminLayout,
|
|
5315
5028
|
{
|
|
@@ -5321,7 +5034,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5321
5034
|
userInfo: user,
|
|
5322
5035
|
breadcrumbs,
|
|
5323
5036
|
actions,
|
|
5324
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5325
5037
|
children: result
|
|
5326
5038
|
}
|
|
5327
5039
|
)
|
|
@@ -5336,7 +5048,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5336
5048
|
prefix: options.prefix,
|
|
5337
5049
|
title: dynamicMetadata.title,
|
|
5338
5050
|
description: dynamicMetadata.description,
|
|
5339
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5340
5051
|
children: /* @__PURE__ */ jsxRuntime.jsx(NoLayout, { children: result })
|
|
5341
5052
|
}
|
|
5342
5053
|
)
|
|
@@ -5425,14 +5136,15 @@ async function handleRequest(ctx, page, feature, handlerOptions) {
|
|
|
5425
5136
|
if (isHtmxRequest) {
|
|
5426
5137
|
return ctx.html(
|
|
5427
5138
|
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5428
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5139
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5429
5140
|
ErrorAlert,
|
|
5430
5141
|
{
|
|
5142
|
+
"hx-swap-oob": "beforeend:#notification-container",
|
|
5431
5143
|
type: "error",
|
|
5432
5144
|
title: "\u8BF7\u6C42\u5931\u8D25",
|
|
5433
5145
|
message: "Feature has no handler or render method"
|
|
5434
5146
|
}
|
|
5435
|
-
)
|
|
5147
|
+
),
|
|
5436
5148
|
/* @__PURE__ */ jsxRuntime.jsx("title", { children: "\u9519\u8BEF" })
|
|
5437
5149
|
] }),
|
|
5438
5150
|
500,
|
|
@@ -5449,10 +5161,15 @@ async function handleRequest(ctx, page, feature, handlerOptions) {
|
|
|
5449
5161
|
if (isHtmxRequest) {
|
|
5450
5162
|
const errorMessage = error instanceof Error ? error.message : "Internal server error";
|
|
5451
5163
|
return ctx.html(
|
|
5452
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5164
|
+
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5165
|
+
ErrorAlert,
|
|
5166
|
+
{
|
|
5167
|
+
"hx-swap-oob": "beforeend:#notification-container",
|
|
5168
|
+
type: "error",
|
|
5169
|
+
title: "\u8BF7\u6C42\u5931\u8D25",
|
|
5170
|
+
message: errorMessage
|
|
5171
|
+
}
|
|
5172
|
+
) }),
|
|
5456
5173
|
500,
|
|
5457
5174
|
{
|
|
5458
5175
|
"HX-Reswap": "none"
|
|
@@ -5555,7 +5272,6 @@ var HtmxAdminPlugin = class {
|
|
|
5555
5272
|
options;
|
|
5556
5273
|
serviceName = "";
|
|
5557
5274
|
pages = /* @__PURE__ */ new Map();
|
|
5558
|
-
componentHandler;
|
|
5559
5275
|
constructor(options) {
|
|
5560
5276
|
this.options = {
|
|
5561
5277
|
title: options?.title || "\u7BA1\u7406\u540E\u53F0",
|
|
@@ -5564,8 +5280,7 @@ var HtmxAdminPlugin = class {
|
|
|
5564
5280
|
homePath: options?.homePath || "",
|
|
5565
5281
|
navigation: options?.navigation ?? [],
|
|
5566
5282
|
authProvider: options?.authProvider,
|
|
5567
|
-
pages: options?.pages ?? []
|
|
5568
|
-
components: options?.components ?? []
|
|
5283
|
+
pages: options?.pages ?? []
|
|
5569
5284
|
};
|
|
5570
5285
|
this.initPages();
|
|
5571
5286
|
}
|
|
@@ -5597,11 +5312,6 @@ var HtmxAdminPlugin = class {
|
|
|
5597
5312
|
imeanServiceEngine.logger.info(
|
|
5598
5313
|
`HtmxAdminPlugin initialized${this.serviceName ? ` (service: ${this.serviceName})` : ""}`
|
|
5599
5314
|
);
|
|
5600
|
-
this.componentHandler = new HtmxComponentHandler(
|
|
5601
|
-
this.hono,
|
|
5602
|
-
this.options.prefix,
|
|
5603
|
-
this.options.components
|
|
5604
|
-
);
|
|
5605
5315
|
initializeCdnCache().catch((error) => {
|
|
5606
5316
|
imeanServiceEngine.logger.error("[HtmxAdminPlugin] CDN \u7F13\u5B58\u521D\u59CB\u5316\u5931\u8D25", error);
|
|
5607
5317
|
});
|
|
@@ -5624,7 +5334,6 @@ var HtmxAdminPlugin = class {
|
|
|
5624
5334
|
};
|
|
5625
5335
|
|
|
5626
5336
|
exports.BaseFeature = BaseFeature;
|
|
5627
|
-
exports.ComponentContext = ComponentContext;
|
|
5628
5337
|
exports.CustomFeature = CustomFeature;
|
|
5629
5338
|
exports.DefaultCreateFeature = DefaultCreateFeature;
|
|
5630
5339
|
exports.DefaultDeleteFeature = DefaultDeleteFeature;
|
|
@@ -5634,12 +5343,10 @@ exports.DefaultListFeature = DefaultListFeature;
|
|
|
5634
5343
|
exports.Dialog = Dialog;
|
|
5635
5344
|
exports.ErrorAlert = ErrorAlert;
|
|
5636
5345
|
exports.HtmxAdminPlugin = HtmxAdminPlugin;
|
|
5637
|
-
exports.HtmxComponent = HtmxComponent;
|
|
5638
5346
|
exports.LoadingBar = LoadingBar;
|
|
5639
|
-
exports.Method = Method;
|
|
5640
5347
|
exports.ObjectEditor = ObjectEditor;
|
|
5641
5348
|
exports.PageModel = PageModel;
|
|
5642
|
-
exports.
|
|
5349
|
+
exports.SortableList = SortableList;
|
|
5643
5350
|
exports.StringArrayEditor = StringArrayEditor;
|
|
5644
5351
|
exports.TagsEditor = TagsEditor;
|
|
5645
5352
|
exports.checkUserPermission = checkUserPermission;
|