imean-service-engine-htmx-plugin 2.5.0 → 2.7.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 +357 -116
- package/dist/index.d.ts +357 -116
- package/dist/index.js +322 -591
- package/dist/index.mjs +312 -588
- 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,9 @@ 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,
|
|
554
|
+
label: field.label
|
|
560
555
|
}) }),
|
|
561
556
|
field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 mt-1", children: field.description })
|
|
562
557
|
]
|
|
@@ -1853,7 +1848,12 @@ function renderDefaultValue(value) {
|
|
|
1853
1848
|
function renderField(field, value, item) {
|
|
1854
1849
|
let content;
|
|
1855
1850
|
if (field.render) {
|
|
1856
|
-
const rendered = field.render(
|
|
1851
|
+
const rendered = field.render({
|
|
1852
|
+
value,
|
|
1853
|
+
item,
|
|
1854
|
+
name: field.key,
|
|
1855
|
+
label: field.label
|
|
1856
|
+
});
|
|
1857
1857
|
if (rendered === null || rendered === void 0) {
|
|
1858
1858
|
content = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400", children: "-" });
|
|
1859
1859
|
} else if (typeof rendered === "string" || typeof rendered === "number" || typeof rendered === "boolean") {
|
|
@@ -1989,11 +1989,14 @@ var DefaultDetailFeature = class extends BaseFeature {
|
|
|
1989
1989
|
const groupFields = groupSchemas.map(
|
|
1990
1990
|
({ label, schema: schema2, fields: fieldNames }) => {
|
|
1991
1991
|
const groupFields2 = parseSchemaToFields(schema2);
|
|
1992
|
-
const detailFields2 = groupFields2.map((field) =>
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1992
|
+
const detailFields2 = groupFields2.map((field) => {
|
|
1993
|
+
const renderer = this.fieldRenderers?.[field.name];
|
|
1994
|
+
return {
|
|
1995
|
+
key: field.name,
|
|
1996
|
+
label: field.label,
|
|
1997
|
+
render: renderer
|
|
1998
|
+
};
|
|
1999
|
+
});
|
|
1997
2000
|
return {
|
|
1998
2001
|
label,
|
|
1999
2002
|
fields: detailFields2,
|
|
@@ -2025,12 +2028,16 @@ var DefaultDetailFeature = class extends BaseFeature {
|
|
|
2025
2028
|
}
|
|
2026
2029
|
}
|
|
2027
2030
|
const detailFieldNames = getFieldNamesFromFields(detailFields);
|
|
2028
|
-
const fields = detailFieldNames.map((fieldName) =>
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2031
|
+
const fields = detailFieldNames.map((fieldName) => {
|
|
2032
|
+
const label = getFieldLabelFromFields(this.fields || [], fieldName) || fieldName;
|
|
2033
|
+
const renderer = this.fieldRenderers?.[fieldName];
|
|
2034
|
+
return {
|
|
2035
|
+
key: fieldName,
|
|
2036
|
+
label,
|
|
2037
|
+
// 直接使用统一的渲染器类型
|
|
2038
|
+
render: renderer
|
|
2039
|
+
};
|
|
2040
|
+
});
|
|
2034
2041
|
return /* @__PURE__ */ jsxRuntime.jsx(DetailPage, { item, fields });
|
|
2035
2042
|
}
|
|
2036
2043
|
async getActions(context) {
|
|
@@ -2809,286 +2816,6 @@ var DefaultListFeature = class extends BaseFeature {
|
|
|
2809
2816
|
}
|
|
2810
2817
|
};
|
|
2811
2818
|
|
|
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
2819
|
// src/utils/path.ts
|
|
3093
2820
|
function modelNameToPath(modelName) {
|
|
3094
2821
|
return `/${modelName.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
|
|
@@ -3100,8 +2827,9 @@ function ErrorAlert(props) {
|
|
|
3100
2827
|
type = "error",
|
|
3101
2828
|
showClose = true,
|
|
3102
2829
|
className = "",
|
|
3103
|
-
autoClose = 5e3
|
|
2830
|
+
autoClose = 5e3,
|
|
3104
2831
|
// 默认 5 秒自动关闭
|
|
2832
|
+
"hx-swap-oob": hxSwapOob
|
|
3105
2833
|
} = props;
|
|
3106
2834
|
const typeClasses = {
|
|
3107
2835
|
error: "bg-red-50 border-red-200 text-red-800",
|
|
@@ -3190,12 +2918,20 @@ function ErrorAlert(props) {
|
|
|
3190
2918
|
const now = Date.now();
|
|
3191
2919
|
this.elapsedTime = now - this.startTime;
|
|
3192
2920
|
this.progress = Math.max(0, 100 - (this.elapsedTime / this.autoCloseDelay) * 100);
|
|
2921
|
+
// \u66F4\u65B0\u8FDB\u5EA6\u6761\u6837\u5F0F
|
|
2922
|
+
const progressBar = this.$el.querySelector('.progress-bar');
|
|
2923
|
+
if (progressBar) {
|
|
2924
|
+
progressBar.style.width = this.progress + '%';
|
|
2925
|
+
}
|
|
3193
2926
|
if (this.progress > 0 && this.visible) {
|
|
3194
2927
|
this.progressTimer = requestAnimationFrame(updateProgress);
|
|
3195
2928
|
}
|
|
3196
2929
|
};
|
|
3197
2930
|
this.progressTimer = requestAnimationFrame(updateProgress);
|
|
3198
2931
|
},
|
|
2932
|
+
getProgressStyle() {
|
|
2933
|
+
return { width: this.progress + '%' };
|
|
2934
|
+
},
|
|
3199
2935
|
pauseAutoClose() {
|
|
3200
2936
|
if (this.autoCloseTimer) {
|
|
3201
2937
|
clearTimeout(this.autoCloseTimer);
|
|
@@ -3224,6 +2960,9 @@ function ErrorAlert(props) {
|
|
|
3224
2960
|
cancelAnimationFrame(this.progressTimer);
|
|
3225
2961
|
this.progressTimer = null;
|
|
3226
2962
|
}
|
|
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
|
|
3227
2966
|
setTimeout(() => {
|
|
3228
2967
|
if (this.$el && this.$el.parentNode) {
|
|
3229
2968
|
this.$el.parentNode.removeChild(this.$el);
|
|
@@ -3234,6 +2973,9 @@ function ErrorAlert(props) {
|
|
|
3234
2973
|
visible: true,
|
|
3235
2974
|
close() {
|
|
3236
2975
|
this.visible = false;
|
|
2976
|
+
// \u6DFB\u52A0\u6DE1\u51FA\u52A8\u753B
|
|
2977
|
+
this.$el.classList.add('error-alert-exit');
|
|
2978
|
+
// \u52A8\u753B\u7ED3\u675F\u540E\u5B8C\u5168\u79FB\u9664\u5143\u7D20\uFF0C\u4E0D\u7559\u7A7A div
|
|
3237
2979
|
setTimeout(() => {
|
|
3238
2980
|
if (this.$el && this.$el.parentNode) {
|
|
3239
2981
|
this.$el.parentNode.removeChild(this.$el);
|
|
@@ -3255,18 +2997,26 @@ function ErrorAlert(props) {
|
|
|
3255
2997
|
alpineProps["@mouseenter"] = "pauseAutoClose()";
|
|
3256
2998
|
alpineProps["@mouseleave"] = "resumeAutoClose()";
|
|
3257
2999
|
}
|
|
3000
|
+
const htmxProps = {};
|
|
3001
|
+
if (hxSwapOob) {
|
|
3002
|
+
htmxProps["hx-swap-oob"] = hxSwapOob;
|
|
3003
|
+
}
|
|
3258
3004
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3259
3005
|
"div",
|
|
3260
3006
|
{
|
|
3261
3007
|
...alpineProps,
|
|
3262
|
-
|
|
3008
|
+
...htmxProps,
|
|
3009
|
+
className: `w-full border rounded-lg p-4 shadow-lg ${typeClasses[type]} ${className} relative overflow-hidden pointer-events-auto`,
|
|
3263
3010
|
role: "alert",
|
|
3011
|
+
style: {
|
|
3012
|
+
animation: "slideInRight 0.3s ease-out"
|
|
3013
|
+
},
|
|
3264
3014
|
children: [
|
|
3265
3015
|
autoClose > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 h-1 bg-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3266
3016
|
"div",
|
|
3267
3017
|
{
|
|
3268
|
-
className: `h-full ${progressBarColors[type]}`,
|
|
3269
|
-
...{ ":style": "
|
|
3018
|
+
className: `h-full ${progressBarColors[type]} progress-bar`,
|
|
3019
|
+
...{ "x-bind:style": "getProgressStyle()" }
|
|
3270
3020
|
}
|
|
3271
3021
|
) }),
|
|
3272
3022
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start", children: [
|
|
@@ -3385,6 +3135,9 @@ async function createFeatureContext(ctx, page, feature, user, options) {
|
|
|
3385
3135
|
};
|
|
3386
3136
|
return featureContext;
|
|
3387
3137
|
}
|
|
3138
|
+
function generateDialogId() {
|
|
3139
|
+
return `dialog-${Date.now()}}`;
|
|
3140
|
+
}
|
|
3388
3141
|
function Dialog(props) {
|
|
3389
3142
|
const {
|
|
3390
3143
|
title,
|
|
@@ -3396,6 +3149,7 @@ function Dialog(props) {
|
|
|
3396
3149
|
actions = [],
|
|
3397
3150
|
fixedContentHeight = false
|
|
3398
3151
|
} = props;
|
|
3152
|
+
const dialogId = generateDialogId();
|
|
3399
3153
|
const sizeClasses = {
|
|
3400
3154
|
sm: "max-w-md",
|
|
3401
3155
|
md: "max-w-lg",
|
|
@@ -3403,19 +3157,33 @@ function Dialog(props) {
|
|
|
3403
3157
|
xl: "max-w-4xl",
|
|
3404
3158
|
full: "max-w-7xl"
|
|
3405
3159
|
};
|
|
3406
|
-
const
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3160
|
+
const alpineData = `{
|
|
3161
|
+
closeDialog() {
|
|
3162
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
3163
|
+
if (backdrop) {
|
|
3164
|
+
backdrop.classList.add('dialog-exit');
|
|
3165
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
3166
|
+
if (content) {
|
|
3167
|
+
content.classList.add('dialog-content-exit');
|
|
3168
|
+
}
|
|
3169
|
+
setTimeout(() => {
|
|
3170
|
+
backdrop.remove();
|
|
3171
|
+
}, 200);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
}`;
|
|
3411
3175
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3412
3176
|
"div",
|
|
3413
3177
|
{
|
|
3178
|
+
id: dialogId,
|
|
3414
3179
|
className: "fixed inset-0 bg-black bg-opacity-50 z-[100] flex items-center justify-center p-4 dialog-backdrop",
|
|
3415
3180
|
style: {
|
|
3416
3181
|
animation: "fadeIn 0.2s ease-out"
|
|
3417
3182
|
},
|
|
3418
|
-
|
|
3183
|
+
"x-data": alpineData,
|
|
3184
|
+
...closeOnBackdropClick && {
|
|
3185
|
+
"x-on:click": "if ($event.target === $el) closeDialog()"
|
|
3186
|
+
},
|
|
3419
3187
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3420
3188
|
"div",
|
|
3421
3189
|
{
|
|
@@ -3423,7 +3191,7 @@ function Dialog(props) {
|
|
|
3423
3191
|
style: {
|
|
3424
3192
|
animation: "slideIn 0.3s ease-out"
|
|
3425
3193
|
},
|
|
3426
|
-
|
|
3194
|
+
...{ "x-on:click.stop": "" },
|
|
3427
3195
|
children: [
|
|
3428
3196
|
(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
3197
|
title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: title }),
|
|
@@ -3431,7 +3199,7 @@ function Dialog(props) {
|
|
|
3431
3199
|
"button",
|
|
3432
3200
|
{
|
|
3433
3201
|
className: "text-gray-400 hover:text-gray-600 transition-colors",
|
|
3434
|
-
|
|
3202
|
+
"x-on:click": "closeDialog()",
|
|
3435
3203
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3436
3204
|
"svg",
|
|
3437
3205
|
{
|
|
@@ -3528,11 +3296,26 @@ function PermissionDeniedContent(props) {
|
|
|
3528
3296
|
Button,
|
|
3529
3297
|
{
|
|
3530
3298
|
variant: "secondary",
|
|
3531
|
-
|
|
3299
|
+
"x-data": `{
|
|
3300
|
+
closeDialog() {
|
|
3301
|
+
const backdrop = this.$el.closest('.dialog-backdrop');
|
|
3302
|
+
if (backdrop) {
|
|
3303
|
+
backdrop.classList.add('dialog-exit');
|
|
3304
|
+
const content = backdrop.querySelector('.dialog-content');
|
|
3305
|
+
if (content) {
|
|
3306
|
+
content.classList.add('dialog-content-exit');
|
|
3307
|
+
}
|
|
3308
|
+
setTimeout(() => {
|
|
3309
|
+
backdrop.remove();
|
|
3310
|
+
}, 200);
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
}`,
|
|
3314
|
+
"x-on:click": "closeDialog()",
|
|
3532
3315
|
children: "\u5173\u95ED"
|
|
3533
3316
|
}
|
|
3534
3317
|
),
|
|
3535
|
-
!isDialog && userInfo && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary",
|
|
3318
|
+
!isDialog && userInfo && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary", onclick: "window.history.back()", children: "\u8FD4\u56DE" })
|
|
3536
3319
|
] })
|
|
3537
3320
|
] });
|
|
3538
3321
|
}
|
|
@@ -3553,13 +3336,8 @@ var getResourceUrl = (prefix, name) => {
|
|
|
3553
3336
|
function globalScripts(prefix) {
|
|
3554
3337
|
return html.html`
|
|
3555
3338
|
<script src=${getResourceUrl(prefix, "htmx")}></script>
|
|
3556
|
-
<script src=${getResourceUrl(prefix, "htmx-ext-form-json")}></script>
|
|
3557
|
-
<script src=${getResourceUrl(prefix, "hyperscript")}></script>
|
|
3558
3339
|
<script src=${getResourceUrl(prefix, "tailwindcss")}></script>
|
|
3559
3340
|
<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
3341
|
`;
|
|
3564
3342
|
}
|
|
3565
3343
|
function globalStyles() {
|
|
@@ -3689,36 +3467,6 @@ function globalStyles() {
|
|
|
3689
3467
|
}
|
|
3690
3468
|
</style>`;
|
|
3691
3469
|
}
|
|
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
3470
|
function Breadcrumb(props) {
|
|
3723
3471
|
const { items } = props;
|
|
3724
3472
|
if (items.length === 0) {
|
|
@@ -4074,193 +3822,183 @@ function SortableList(props) {
|
|
|
4074
3822
|
function StringArrayEditor(props) {
|
|
4075
3823
|
const {
|
|
4076
3824
|
value,
|
|
4077
|
-
fieldName,
|
|
4078
3825
|
placeholder = "\u8BF7\u8F93\u5165\u5185\u5BB9",
|
|
4079
3826
|
allowEmpty = false,
|
|
4080
3827
|
rows = 1
|
|
4081
3828
|
} = props;
|
|
3829
|
+
const name = props.name;
|
|
4082
3830
|
const initialItems = value || [];
|
|
4083
3831
|
const initialDataJson = JSON.stringify({
|
|
4084
3832
|
items: initialItems.map((item) => item || ""),
|
|
4085
|
-
fieldName,
|
|
3833
|
+
fieldName: name,
|
|
4086
3834
|
placeholder,
|
|
4087
3835
|
allowEmpty,
|
|
4088
3836
|
rows
|
|
4089
3837
|
});
|
|
4090
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4091
|
-
"div",
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
"button",
|
|
4098
|
-
{
|
|
4099
|
-
type: "button",
|
|
4100
|
-
...{
|
|
4101
|
-
"x-on:click": `
|
|
3838
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", "x-data": initialDataJson, children: [
|
|
3839
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3840
|
+
"button",
|
|
3841
|
+
{
|
|
3842
|
+
type: "button",
|
|
3843
|
+
...{
|
|
3844
|
+
"x-on:click": `
|
|
4102
3845
|
items.push('');
|
|
4103
3846
|
`
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
3847
|
+
},
|
|
3848
|
+
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",
|
|
3849
|
+
"data-testid": `${name}-add-button`,
|
|
3850
|
+
children: [
|
|
3851
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3852
|
+
"svg",
|
|
3853
|
+
{
|
|
3854
|
+
className: "w-4 h-4",
|
|
3855
|
+
fill: "none",
|
|
3856
|
+
stroke: "currentColor",
|
|
3857
|
+
viewBox: "0 0 24 24",
|
|
3858
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3859
|
+
"path",
|
|
4110
3860
|
{
|
|
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
|
-
)
|
|
3861
|
+
strokeLinecap: "round",
|
|
3862
|
+
strokeLinejoin: "round",
|
|
3863
|
+
strokeWidth: "2",
|
|
3864
|
+
d: "M12 4v16m8-8H4"
|
|
4124
3865
|
}
|
|
4125
|
-
)
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
3866
|
+
)
|
|
3867
|
+
}
|
|
3868
|
+
),
|
|
3869
|
+
"\u6DFB\u52A0\u9879"
|
|
3870
|
+
]
|
|
3871
|
+
}
|
|
3872
|
+
) }),
|
|
3873
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3874
|
+
"div",
|
|
3875
|
+
{
|
|
3876
|
+
"x-show": "items.length > 0",
|
|
3877
|
+
"data-testid": `${name}-list-container`,
|
|
3878
|
+
...{
|
|
3879
|
+
"@sortable:change.stop": `
|
|
4137
3880
|
(function() {
|
|
4138
3881
|
const { oldIndex, newIndex } = $event.detail;
|
|
4139
3882
|
[items[oldIndex], items[newIndex]] = [items[newIndex], items[oldIndex]];
|
|
4140
3883
|
})();
|
|
4141
3884
|
`
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
}
|
|
4157
|
-
);
|
|
3885
|
+
},
|
|
3886
|
+
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 }) }) })
|
|
3887
|
+
}
|
|
3888
|
+
),
|
|
3889
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3890
|
+
"div",
|
|
3891
|
+
{
|
|
3892
|
+
className: "empty-state text-center py-8 text-gray-400 text-sm border border-dashed border-gray-300 rounded-lg",
|
|
3893
|
+
"x-show": "items.length === 0",
|
|
3894
|
+
"data-testid": `${name}-empty-state`,
|
|
3895
|
+
children: '\u6682\u65E0\u9879\uFF0C\u70B9\u51FB"\u6DFB\u52A0\u9879"\u6309\u94AE\u6DFB\u52A0'
|
|
3896
|
+
}
|
|
3897
|
+
)
|
|
3898
|
+
] });
|
|
4158
3899
|
}
|
|
4159
|
-
function ArrayItem({
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
3900
|
+
function ArrayItem({
|
|
3901
|
+
fieldName,
|
|
3902
|
+
rows = 1
|
|
3903
|
+
}) {
|
|
3904
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-array-item": true, className: "flex items-center gap-2 group", children: [
|
|
3905
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3906
|
+
"div",
|
|
3907
|
+
{
|
|
3908
|
+
className: "flex-shrink-0 cursor-move text-gray-400 hover:text-gray-600 transition-colors p-1",
|
|
3909
|
+
"data-drag-handle": true,
|
|
3910
|
+
"data-testid": `${fieldName}-drag-handle`,
|
|
3911
|
+
title: "\u62D6\u62FD\u6392\u5E8F",
|
|
3912
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3913
|
+
"svg",
|
|
4168
3914
|
{
|
|
4169
|
-
className: "
|
|
4170
|
-
"
|
|
4171
|
-
"
|
|
4172
|
-
|
|
3915
|
+
className: "w-5 h-5",
|
|
3916
|
+
fill: "none",
|
|
3917
|
+
stroke: "currentColor",
|
|
3918
|
+
viewBox: "0 0 24 24",
|
|
4173
3919
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4174
|
-
"
|
|
3920
|
+
"path",
|
|
4175
3921
|
{
|
|
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
|
-
)
|
|
3922
|
+
strokeLinecap: "round",
|
|
3923
|
+
strokeLinejoin: "round",
|
|
3924
|
+
strokeWidth: "2",
|
|
3925
|
+
d: "M4 8h16M4 16h16"
|
|
4189
3926
|
}
|
|
4190
3927
|
)
|
|
4191
3928
|
}
|
|
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
|
-
|
|
3929
|
+
)
|
|
3930
|
+
}
|
|
3931
|
+
),
|
|
3932
|
+
rows === 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3933
|
+
"input",
|
|
3934
|
+
{
|
|
3935
|
+
type: "text",
|
|
3936
|
+
"x-model": "items[index]",
|
|
3937
|
+
"x-bind:placeholder": "placeholder + ' ' + (index + 1)",
|
|
3938
|
+
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",
|
|
3939
|
+
"data-testid": `${fieldName}-input`,
|
|
3940
|
+
"x-bind:required": "!allowEmpty"
|
|
3941
|
+
}
|
|
3942
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3943
|
+
"textarea",
|
|
3944
|
+
{
|
|
3945
|
+
"x-model": "items[index]",
|
|
3946
|
+
"x-bind:placeholder": "placeholder + ' ' + (index + 1)",
|
|
3947
|
+
rows,
|
|
3948
|
+
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",
|
|
3949
|
+
"data-testid": `${fieldName}-input`,
|
|
3950
|
+
"x-bind:required": "!allowEmpty"
|
|
3951
|
+
}
|
|
3952
|
+
),
|
|
3953
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3954
|
+
"input",
|
|
3955
|
+
{
|
|
3956
|
+
type: "hidden",
|
|
3957
|
+
"x-bind:name": "fieldName + '[' + index + ']'",
|
|
3958
|
+
"x-bind:value": "item"
|
|
3959
|
+
}
|
|
3960
|
+
),
|
|
3961
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3962
|
+
"button",
|
|
3963
|
+
{
|
|
3964
|
+
type: "button",
|
|
3965
|
+
...{
|
|
3966
|
+
"x-on:click": `
|
|
4228
3967
|
items.splice(index, 1);
|
|
4229
3968
|
`
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
3969
|
+
},
|
|
3970
|
+
className: "flex-shrink-0 px-3 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors",
|
|
3971
|
+
"data-testid": `${fieldName}-remove-button`,
|
|
3972
|
+
title: "\u5220\u9664\u6B64\u9879",
|
|
3973
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3974
|
+
"svg",
|
|
3975
|
+
{
|
|
3976
|
+
className: "w-5 h-5",
|
|
3977
|
+
fill: "none",
|
|
3978
|
+
stroke: "currentColor",
|
|
3979
|
+
viewBox: "0 0 24 24",
|
|
4234
3980
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4235
|
-
"
|
|
3981
|
+
"path",
|
|
4236
3982
|
{
|
|
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
|
-
)
|
|
3983
|
+
strokeLinecap: "round",
|
|
3984
|
+
strokeLinejoin: "round",
|
|
3985
|
+
strokeWidth: "2",
|
|
3986
|
+
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
3987
|
}
|
|
4251
3988
|
)
|
|
4252
3989
|
}
|
|
4253
3990
|
)
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
);
|
|
3991
|
+
}
|
|
3992
|
+
)
|
|
3993
|
+
] });
|
|
4257
3994
|
}
|
|
4258
3995
|
function TagsEditor(props) {
|
|
4259
|
-
const { value,
|
|
3996
|
+
const { value, placeholder = "\u8F93\u5165\u6807\u7B7E\u540E\u6309\u56DE\u8F66\u6DFB\u52A0" } = props;
|
|
3997
|
+
const name = props.name;
|
|
4260
3998
|
const initialTags = value || [];
|
|
4261
3999
|
const initialDataJson = JSON.stringify({
|
|
4262
4000
|
tags: initialTags.map((tag) => tag || ""),
|
|
4263
|
-
fieldName,
|
|
4001
|
+
fieldName: name,
|
|
4264
4002
|
newTag: "",
|
|
4265
4003
|
editingIndex: null,
|
|
4266
4004
|
editingValue: "",
|
|
@@ -4287,7 +4025,7 @@ function TagsEditor(props) {
|
|
|
4287
4025
|
placeholder,
|
|
4288
4026
|
autocomplete: "off",
|
|
4289
4027
|
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": `${
|
|
4028
|
+
"data-testid": `${name}-input`
|
|
4291
4029
|
}
|
|
4292
4030
|
),
|
|
4293
4031
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4296,7 +4034,7 @@ function TagsEditor(props) {
|
|
|
4296
4034
|
"x-show": "error && editingIndex === null",
|
|
4297
4035
|
"x-text": "error",
|
|
4298
4036
|
className: "text-red-600 text-sm p-2",
|
|
4299
|
-
id: `${
|
|
4037
|
+
id: `${name}-error`
|
|
4300
4038
|
}
|
|
4301
4039
|
)
|
|
4302
4040
|
] }),
|
|
@@ -4304,7 +4042,7 @@ function TagsEditor(props) {
|
|
|
4304
4042
|
"div",
|
|
4305
4043
|
{
|
|
4306
4044
|
"x-show": "tags.length > 0",
|
|
4307
|
-
"data-testid": `${
|
|
4045
|
+
"data-testid": `${name}-tags-container`,
|
|
4308
4046
|
...{
|
|
4309
4047
|
"@sortable:change.stop": `
|
|
4310
4048
|
(function() {
|
|
@@ -4327,8 +4065,8 @@ function TagsEditor(props) {
|
|
|
4327
4065
|
"x-bind:value": "editingIndex === index ? editingValue : tag"
|
|
4328
4066
|
}
|
|
4329
4067
|
),
|
|
4330
|
-
/* @__PURE__ */ jsxRuntime.jsx(TagItem, { fieldName }),
|
|
4331
|
-
/* @__PURE__ */ jsxRuntime.jsx(TagItemEdit, { fieldName })
|
|
4068
|
+
/* @__PURE__ */ jsxRuntime.jsx(TagItem, { fieldName: name }),
|
|
4069
|
+
/* @__PURE__ */ jsxRuntime.jsx(TagItemEdit, { fieldName: name })
|
|
4332
4070
|
] }) })
|
|
4333
4071
|
}
|
|
4334
4072
|
)
|
|
@@ -4339,7 +4077,7 @@ function TagsEditor(props) {
|
|
|
4339
4077
|
{
|
|
4340
4078
|
className: "empty-state text-center py-4 text-gray-400 text-sm border border-dashed border-gray-300 rounded-md",
|
|
4341
4079
|
"x-show": "tags.length === 0",
|
|
4342
|
-
"data-testid": `${
|
|
4080
|
+
"data-testid": `${name}-empty-state`,
|
|
4343
4081
|
children: "\u6682\u65E0\u6807\u7B7E\uFF0C\u5728\u4E0A\u65B9\u8F93\u5165\u6846\u4E2D\u8F93\u5165\u6807\u7B7E\u540E\u6309\u56DE\u8F66\u6DFB\u52A0"
|
|
4344
4082
|
}
|
|
4345
4083
|
)
|
|
@@ -4520,7 +4258,7 @@ function TagItemEdit({ fieldName }) {
|
|
|
4520
4258
|
);
|
|
4521
4259
|
}
|
|
4522
4260
|
function ObjectEditor(props) {
|
|
4523
|
-
const { value,
|
|
4261
|
+
const { value, name, objectSchema } = props;
|
|
4524
4262
|
if (!objectSchema) {
|
|
4525
4263
|
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
4264
|
}
|
|
@@ -4540,7 +4278,7 @@ function ObjectEditor(props) {
|
|
|
4540
4278
|
const initialValueJson = JSON.stringify(initialObject);
|
|
4541
4279
|
JSON.stringify(fields.map((f) => f.name));
|
|
4542
4280
|
const generateField = (field) => {
|
|
4543
|
-
const fieldId = `${
|
|
4281
|
+
const fieldId = `${String(name)}-${field.name}`;
|
|
4544
4282
|
const fieldValue = initialObject[field.name];
|
|
4545
4283
|
const fieldValueStr = fieldValue === void 0 || fieldValue === null ? "" : typeof fieldValue === "object" ? JSON.stringify(fieldValue) : String(fieldValue);
|
|
4546
4284
|
const requiredAttr = field.required ? "required" : "";
|
|
@@ -4550,11 +4288,11 @@ function ObjectEditor(props) {
|
|
|
4550
4288
|
<input
|
|
4551
4289
|
type="text"
|
|
4552
4290
|
id="${fieldId}"
|
|
4553
|
-
name="${
|
|
4291
|
+
name="${name}.${field.name}"
|
|
4554
4292
|
value="${fieldValueStr}"
|
|
4555
4293
|
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('${
|
|
4294
|
+
data-testid="${name}-input-${field.name}"
|
|
4295
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4558
4296
|
${requiredAttr}
|
|
4559
4297
|
/>
|
|
4560
4298
|
`;
|
|
@@ -4562,11 +4300,11 @@ function ObjectEditor(props) {
|
|
|
4562
4300
|
inputElement = html.html`
|
|
4563
4301
|
<textarea
|
|
4564
4302
|
id="${fieldId}"
|
|
4565
|
-
name="${
|
|
4303
|
+
name="${name}.${field.name}"
|
|
4566
4304
|
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
4305
|
rows="4"
|
|
4568
|
-
data-testid="${
|
|
4569
|
-
oninput="updateObjectField('${
|
|
4306
|
+
data-testid="${name}-input-${field.name}"
|
|
4307
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4570
4308
|
${requiredAttr}
|
|
4571
4309
|
>${fieldValueStr}</textarea>
|
|
4572
4310
|
`;
|
|
@@ -4576,12 +4314,12 @@ function ObjectEditor(props) {
|
|
|
4576
4314
|
<input
|
|
4577
4315
|
type="number"
|
|
4578
4316
|
id="${fieldId}"
|
|
4579
|
-
name="${
|
|
4317
|
+
name="${name}.${field.name}"
|
|
4580
4318
|
value="${fieldValueStr}"
|
|
4581
4319
|
step="${step}"
|
|
4582
4320
|
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('${
|
|
4321
|
+
data-testid="${name}-input-${field.name}"
|
|
4322
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'number', ${field.required})"
|
|
4585
4323
|
${requiredAttr}
|
|
4586
4324
|
/>
|
|
4587
4325
|
`;
|
|
@@ -4590,11 +4328,11 @@ function ObjectEditor(props) {
|
|
|
4590
4328
|
<input
|
|
4591
4329
|
type="date"
|
|
4592
4330
|
id="${fieldId}"
|
|
4593
|
-
name="${
|
|
4331
|
+
name="${name}.${field.name}"
|
|
4594
4332
|
value="${fieldValueStr}"
|
|
4595
4333
|
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('${
|
|
4334
|
+
data-testid="${name}-input-${field.name}"
|
|
4335
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'date', ${field.required})"
|
|
4598
4336
|
${requiredAttr}
|
|
4599
4337
|
/>
|
|
4600
4338
|
`;
|
|
@@ -4603,11 +4341,11 @@ function ObjectEditor(props) {
|
|
|
4603
4341
|
<input
|
|
4604
4342
|
type="email"
|
|
4605
4343
|
id="${fieldId}"
|
|
4606
|
-
name="${
|
|
4344
|
+
name="${name}.${field.name}"
|
|
4607
4345
|
value="${fieldValueStr}"
|
|
4608
4346
|
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('${
|
|
4347
|
+
data-testid="${name}-input-${field.name}"
|
|
4348
|
+
oninput="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4611
4349
|
${requiredAttr}
|
|
4612
4350
|
/>
|
|
4613
4351
|
`;
|
|
@@ -4615,10 +4353,10 @@ function ObjectEditor(props) {
|
|
|
4615
4353
|
inputElement = html.html`
|
|
4616
4354
|
<select
|
|
4617
4355
|
id="${fieldId}"
|
|
4618
|
-
name="${
|
|
4356
|
+
name="${name}.${field.name}"
|
|
4619
4357
|
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('${
|
|
4358
|
+
data-testid="${name}-select-${field.name}"
|
|
4359
|
+
onchange="updateObjectField('${name}', '${field.name}', this.value, 'text', ${field.required})"
|
|
4622
4360
|
${requiredAttr}
|
|
4623
4361
|
>
|
|
4624
4362
|
${!field.required ? html.html`<option value="">请选择</option>` : ""}
|
|
@@ -4641,11 +4379,11 @@ function ObjectEditor(props) {
|
|
|
4641
4379
|
<input
|
|
4642
4380
|
type="checkbox"
|
|
4643
4381
|
id="${fieldId}"
|
|
4644
|
-
name="${
|
|
4382
|
+
name="${name}.${field.name}"
|
|
4645
4383
|
${checked ? "checked" : ""}
|
|
4646
4384
|
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
|
|
4647
|
-
data-testid="${
|
|
4648
|
-
onchange="updateObjectField('${
|
|
4385
|
+
data-testid="${name}-checkbox-${field.name}"
|
|
4386
|
+
onchange="updateObjectField('${name}', '${field.name}', this.checked, 'checkbox', ${field.required}')"
|
|
4649
4387
|
/>
|
|
4650
4388
|
<label for="${fieldId}" class="ml-2 text-sm text-gray-700">
|
|
4651
4389
|
${field.label}
|
|
@@ -4654,12 +4392,12 @@ function ObjectEditor(props) {
|
|
|
4654
4392
|
`;
|
|
4655
4393
|
}
|
|
4656
4394
|
return html.html`
|
|
4657
|
-
<div class="space-y-2" data-testid="${
|
|
4395
|
+
<div class="space-y-2" data-testid="${name}-field-${field.name}">
|
|
4658
4396
|
${field.type !== "checkbox" ? html.html`
|
|
4659
4397
|
<label
|
|
4660
4398
|
for="${fieldId}"
|
|
4661
4399
|
class="block text-sm font-semibold text-gray-700"
|
|
4662
|
-
data-testid="${
|
|
4400
|
+
data-testid="${name}-label-${field.name}"
|
|
4663
4401
|
>
|
|
4664
4402
|
${field.label}
|
|
4665
4403
|
${field.required ? html.html`<span class="text-red-500 ml-1">*</span>` : ""}
|
|
@@ -4671,15 +4409,15 @@ function ObjectEditor(props) {
|
|
|
4671
4409
|
};
|
|
4672
4410
|
return html.html`
|
|
4673
4411
|
<div
|
|
4674
|
-
id="object-editor-${
|
|
4412
|
+
id="object-editor-${name}"
|
|
4675
4413
|
class="space-y-4"
|
|
4676
4414
|
data-initial-value="${initialValueJson}"
|
|
4677
4415
|
>
|
|
4678
4416
|
<input
|
|
4679
4417
|
type="hidden"
|
|
4680
|
-
name="${
|
|
4418
|
+
name="${name}"
|
|
4681
4419
|
value="${initialValueJson}"
|
|
4682
|
-
data-testid="hidden-${
|
|
4420
|
+
data-testid="hidden-${name}"
|
|
4683
4421
|
/>
|
|
4684
4422
|
<div class="space-y-4">
|
|
4685
4423
|
${fields.map((field) => generateField(field))}
|
|
@@ -4741,14 +4479,13 @@ function BaseLayout(props) {
|
|
|
4741
4479
|
<meta name="description" content="${props.description || ""}" />
|
|
4742
4480
|
${globalScripts(props.prefix)} ${globalStyles()}
|
|
4743
4481
|
</head>
|
|
4744
|
-
<body
|
|
4482
|
+
<body className="bg-gray-50" hx-indicator="#loading-bar">
|
|
4745
4483
|
${LoadingBar()} ${props.children}
|
|
4746
4484
|
<div
|
|
4747
|
-
id="
|
|
4748
|
-
|
|
4485
|
+
id="notification-container"
|
|
4486
|
+
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
4487
|
></div>
|
|
4750
4488
|
<div id="dialog-container"></div>
|
|
4751
|
-
${sortableScript()}
|
|
4752
4489
|
</body>
|
|
4753
4490
|
</html>
|
|
4754
4491
|
`;
|
|
@@ -5000,7 +4737,7 @@ async function handlePermissionDenied(ctx, result, options) {
|
|
|
5000
4737
|
if (isHtmxRequest) {
|
|
5001
4738
|
const headers = {
|
|
5002
4739
|
"HX-Retarget": "#dialog-container",
|
|
5003
|
-
"HX-Reswap": "
|
|
4740
|
+
"HX-Reswap": "beforeend",
|
|
5004
4741
|
"X-Permission-Denied": "true"
|
|
5005
4742
|
};
|
|
5006
4743
|
return ctx.html(
|
|
@@ -5045,22 +4782,15 @@ function buildNotificationFragments(notifications) {
|
|
|
5045
4782
|
if (notifications.length === 0) {
|
|
5046
4783
|
return null;
|
|
5047
4784
|
}
|
|
5048
|
-
return notifications.map((notification, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5049
|
-
|
|
4785
|
+
return notifications.map((notification, index) => /* @__PURE__ */ jsxRuntime.jsx("div", { id: "notification-container", "hx-swap-oob": "beforeend", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4786
|
+
ErrorAlert,
|
|
5050
4787
|
{
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
ErrorAlert,
|
|
5055
|
-
{
|
|
5056
|
-
type: notification.type,
|
|
5057
|
-
title: notification.title,
|
|
5058
|
-
message: notification.message
|
|
5059
|
-
}
|
|
5060
|
-
)
|
|
4788
|
+
type: notification.type,
|
|
4789
|
+
title: notification.title,
|
|
4790
|
+
message: notification.message
|
|
5061
4791
|
},
|
|
5062
4792
|
`notification-${index}`
|
|
5063
|
-
));
|
|
4793
|
+
) }));
|
|
5064
4794
|
}
|
|
5065
4795
|
function isEmptyContent(result) {
|
|
5066
4796
|
if (result === null || result === void 0) return true;
|
|
@@ -5154,7 +4884,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5154
4884
|
if (context.isDialog) {
|
|
5155
4885
|
return ctx.html(
|
|
5156
4886
|
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5157
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { id: "dialog-container", "hx-swap-oob": "innerHTML" }),
|
|
5158
4887
|
notificationFragments,
|
|
5159
4888
|
/* @__PURE__ */ jsxRuntime.jsx("title", { children: metadata.title })
|
|
5160
4889
|
] }),
|
|
@@ -5210,7 +4939,7 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5210
4939
|
);
|
|
5211
4940
|
}
|
|
5212
4941
|
const target = context.isDialog ? "#dialog-container" : "#main-content";
|
|
5213
|
-
const swap = context.isDialog ? "
|
|
4942
|
+
const swap = context.isDialog ? "beforeend" : "outerHTML";
|
|
5214
4943
|
const headers = {
|
|
5215
4944
|
"HX-Retarget": target,
|
|
5216
4945
|
"HX-Reswap": swap
|
|
@@ -5273,7 +5002,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5273
5002
|
useAdminLayout,
|
|
5274
5003
|
currentPath,
|
|
5275
5004
|
userInfo: user,
|
|
5276
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5277
5005
|
breadcrumbs,
|
|
5278
5006
|
actions,
|
|
5279
5007
|
children: result
|
|
@@ -5309,7 +5037,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5309
5037
|
prefix: options.prefix,
|
|
5310
5038
|
title: dynamicMetadata.title,
|
|
5311
5039
|
description: dynamicMetadata.description,
|
|
5312
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5313
5040
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5314
5041
|
AdminLayout,
|
|
5315
5042
|
{
|
|
@@ -5321,7 +5048,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5321
5048
|
userInfo: user,
|
|
5322
5049
|
breadcrumbs,
|
|
5323
5050
|
actions,
|
|
5324
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5325
5051
|
children: result
|
|
5326
5052
|
}
|
|
5327
5053
|
)
|
|
@@ -5336,7 +5062,6 @@ async function renderResult(ctx, context, result, renderOptions) {
|
|
|
5336
5062
|
prefix: options.prefix,
|
|
5337
5063
|
title: dynamicMetadata.title,
|
|
5338
5064
|
description: dynamicMetadata.description,
|
|
5339
|
-
componentRegistry: renderOptions.componentRegistry,
|
|
5340
5065
|
children: /* @__PURE__ */ jsxRuntime.jsx(NoLayout, { children: result })
|
|
5341
5066
|
}
|
|
5342
5067
|
)
|
|
@@ -5425,14 +5150,15 @@ async function handleRequest(ctx, page, feature, handlerOptions) {
|
|
|
5425
5150
|
if (isHtmxRequest) {
|
|
5426
5151
|
return ctx.html(
|
|
5427
5152
|
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5428
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5153
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5429
5154
|
ErrorAlert,
|
|
5430
5155
|
{
|
|
5156
|
+
"hx-swap-oob": "beforeend:#notification-container",
|
|
5431
5157
|
type: "error",
|
|
5432
5158
|
title: "\u8BF7\u6C42\u5931\u8D25",
|
|
5433
5159
|
message: "Feature has no handler or render method"
|
|
5434
5160
|
}
|
|
5435
|
-
)
|
|
5161
|
+
),
|
|
5436
5162
|
/* @__PURE__ */ jsxRuntime.jsx("title", { children: "\u9519\u8BEF" })
|
|
5437
5163
|
] }),
|
|
5438
5164
|
500,
|
|
@@ -5449,10 +5175,15 @@ async function handleRequest(ctx, page, feature, handlerOptions) {
|
|
|
5449
5175
|
if (isHtmxRequest) {
|
|
5450
5176
|
const errorMessage = error instanceof Error ? error.message : "Internal server error";
|
|
5451
5177
|
return ctx.html(
|
|
5452
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5178
|
+
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5179
|
+
ErrorAlert,
|
|
5180
|
+
{
|
|
5181
|
+
"hx-swap-oob": "beforeend:#notification-container",
|
|
5182
|
+
type: "error",
|
|
5183
|
+
title: "\u8BF7\u6C42\u5931\u8D25",
|
|
5184
|
+
message: errorMessage
|
|
5185
|
+
}
|
|
5186
|
+
) }),
|
|
5456
5187
|
500,
|
|
5457
5188
|
{
|
|
5458
5189
|
"HX-Reswap": "none"
|
|
@@ -5555,7 +5286,6 @@ var HtmxAdminPlugin = class {
|
|
|
5555
5286
|
options;
|
|
5556
5287
|
serviceName = "";
|
|
5557
5288
|
pages = /* @__PURE__ */ new Map();
|
|
5558
|
-
componentHandler;
|
|
5559
5289
|
constructor(options) {
|
|
5560
5290
|
this.options = {
|
|
5561
5291
|
title: options?.title || "\u7BA1\u7406\u540E\u53F0",
|
|
@@ -5564,8 +5294,7 @@ var HtmxAdminPlugin = class {
|
|
|
5564
5294
|
homePath: options?.homePath || "",
|
|
5565
5295
|
navigation: options?.navigation ?? [],
|
|
5566
5296
|
authProvider: options?.authProvider,
|
|
5567
|
-
pages: options?.pages ?? []
|
|
5568
|
-
components: options?.components ?? []
|
|
5297
|
+
pages: options?.pages ?? []
|
|
5569
5298
|
};
|
|
5570
5299
|
this.initPages();
|
|
5571
5300
|
}
|
|
@@ -5597,11 +5326,6 @@ var HtmxAdminPlugin = class {
|
|
|
5597
5326
|
imeanServiceEngine.logger.info(
|
|
5598
5327
|
`HtmxAdminPlugin initialized${this.serviceName ? ` (service: ${this.serviceName})` : ""}`
|
|
5599
5328
|
);
|
|
5600
|
-
this.componentHandler = new HtmxComponentHandler(
|
|
5601
|
-
this.hono,
|
|
5602
|
-
this.options.prefix,
|
|
5603
|
-
this.options.components
|
|
5604
|
-
);
|
|
5605
5329
|
initializeCdnCache().catch((error) => {
|
|
5606
5330
|
imeanServiceEngine.logger.error("[HtmxAdminPlugin] CDN \u7F13\u5B58\u521D\u59CB\u5316\u5931\u8D25", error);
|
|
5607
5331
|
});
|
|
@@ -5624,7 +5348,10 @@ var HtmxAdminPlugin = class {
|
|
|
5624
5348
|
};
|
|
5625
5349
|
|
|
5626
5350
|
exports.BaseFeature = BaseFeature;
|
|
5627
|
-
exports.
|
|
5351
|
+
exports.BaseFormFeature = BaseFormFeature;
|
|
5352
|
+
exports.Breadcrumb = Breadcrumb;
|
|
5353
|
+
exports.Button = Button;
|
|
5354
|
+
exports.Card = Card;
|
|
5628
5355
|
exports.CustomFeature = CustomFeature;
|
|
5629
5356
|
exports.DefaultCreateFeature = DefaultCreateFeature;
|
|
5630
5357
|
exports.DefaultDeleteFeature = DefaultDeleteFeature;
|
|
@@ -5632,16 +5359,20 @@ exports.DefaultDetailFeature = DefaultDetailFeature;
|
|
|
5632
5359
|
exports.DefaultEditFeature = DefaultEditFeature;
|
|
5633
5360
|
exports.DefaultListFeature = DefaultListFeature;
|
|
5634
5361
|
exports.Dialog = Dialog;
|
|
5362
|
+
exports.EmptyState = EmptyState;
|
|
5635
5363
|
exports.ErrorAlert = ErrorAlert;
|
|
5364
|
+
exports.FilterForm = FilterForm;
|
|
5365
|
+
exports.Header = Header;
|
|
5636
5366
|
exports.HtmxAdminPlugin = HtmxAdminPlugin;
|
|
5637
|
-
exports.HtmxComponent = HtmxComponent;
|
|
5638
5367
|
exports.LoadingBar = LoadingBar;
|
|
5639
|
-
exports.Method = Method;
|
|
5640
5368
|
exports.ObjectEditor = ObjectEditor;
|
|
5641
5369
|
exports.PageModel = PageModel;
|
|
5642
|
-
exports.
|
|
5370
|
+
exports.Pagination = Pagination;
|
|
5371
|
+
exports.PermissionDeniedContent = PermissionDeniedContent;
|
|
5372
|
+
exports.PermissionDeniedPage = PermissionDeniedPage;
|
|
5643
5373
|
exports.SortableList = SortableList;
|
|
5644
5374
|
exports.StringArrayEditor = StringArrayEditor;
|
|
5375
|
+
exports.Table = Table;
|
|
5645
5376
|
exports.TagsEditor = TagsEditor;
|
|
5646
5377
|
exports.checkUserPermission = checkUserPermission;
|
|
5647
5378
|
exports.getUserInfo = getUserInfo;
|