feat(admin): preserve list return target for back and close actions
This commit is contained in:
@@ -152,6 +152,10 @@ const readSubmitLockMode = (submitter, form) => normalizeSubmitLock(
|
||||
const disableSubmitControlsForForm = (form, submitter, options = {}) => {
|
||||
const controls = findSubmitControlsForForm(form);
|
||||
controls.forEach((control) => {
|
||||
if (submitter instanceof HTMLElement && control === submitter) {
|
||||
// Keep the clicked submitter enabled so its name/value stays part of form submission.
|
||||
return;
|
||||
}
|
||||
control.disabled = true;
|
||||
});
|
||||
if (submitter instanceof HTMLElement) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { warnOnce } from './app-dom.js';
|
||||
import { confirmDialog } from './app-confirm-dialog.js';
|
||||
import { gridFiltersFromSchema } from '../pages/app-list-utils.js';
|
||||
import { gridFiltersFromSchema, withCurrentListReturn } from '../pages/app-list-utils.js';
|
||||
import { initListFilterExperience } from '../pages/app-list-filter-experience.js';
|
||||
import { buildChipsFromMeta, removeChipFromMetaState, clearMetaState } from '../pages/app-list-filter-state.js';
|
||||
|
||||
@@ -294,7 +294,11 @@ export function createServerGrid(options) {
|
||||
return '';
|
||||
}
|
||||
const url = rowDblClick.getUrl(rowData, rowIndex);
|
||||
return String(url || '').trim();
|
||||
const normalized = String(url || '').trim();
|
||||
if (normalized === '') {
|
||||
return '';
|
||||
}
|
||||
return withCurrentListReturn(normalized);
|
||||
};
|
||||
|
||||
const getInput = (input) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { initStandardListPage } from '../core/app-grid-factory.js';
|
||||
import { readPageConfig } from '../core/app-page-config.js';
|
||||
import { warnOnce } from '../core/app-dom.js';
|
||||
import { getAppBase } from './app-list-utils.js';
|
||||
import { getAppBase, withCurrentListReturn } from './app-list-utils.js';
|
||||
|
||||
const config = readPageConfig('admin-api-audit-index');
|
||||
if (config) {
|
||||
@@ -60,7 +60,7 @@ if (config) {
|
||||
if (!cell.uuid) {
|
||||
return gridjs.html(label);
|
||||
}
|
||||
const url = new URL(`admin/users/edit/${cell.uuid}`, appBase).toString();
|
||||
const url = withCurrentListReturn(new URL(`admin/users/edit/${cell.uuid}`, appBase).toString());
|
||||
return gridjs.html(`<a href="${url}">${label}</a>`);
|
||||
},
|
||||
},
|
||||
@@ -75,7 +75,7 @@ if (config) {
|
||||
if (!cell.uuid) {
|
||||
return gridjs.html(label);
|
||||
}
|
||||
const url = new URL(`admin/tenants/edit/${cell.uuid}`, appBase).toString();
|
||||
const url = withCurrentListReturn(new URL(`admin/tenants/edit/${cell.uuid}`, appBase).toString());
|
||||
return gridjs.html(`<a href="${url}">${label}</a>`);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { initStandardListPage } from '../core/app-grid-factory.js';
|
||||
import { readPageConfig } from '../core/app-page-config.js';
|
||||
import { warnOnce } from '../core/app-dom.js';
|
||||
import { getAppBase } from './app-list-utils.js';
|
||||
import { getAppBase, withCurrentListReturn } from './app-list-utils.js';
|
||||
|
||||
const config = readPageConfig('admin-import-audit-index');
|
||||
if (config) {
|
||||
@@ -56,7 +56,7 @@ if (config) {
|
||||
if (!cell.uuid) {
|
||||
return gridjs.html(label);
|
||||
}
|
||||
const url = new URL(`admin/users/edit/${cell.uuid}`, appBase).toString();
|
||||
const url = withCurrentListReturn(new URL(`admin/users/edit/${cell.uuid}`, appBase).toString());
|
||||
return gridjs.html(`<a href="${url}">${label}</a>`);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { initStandardListPage } from '../core/app-grid-factory.js';
|
||||
import { readPageConfig } from '../core/app-page-config.js';
|
||||
import { warnOnce } from '../core/app-dom.js';
|
||||
import { getAppBase } from './app-list-utils.js';
|
||||
import { getAppBase, withCurrentListReturn } from './app-list-utils.js';
|
||||
|
||||
const config = readPageConfig('admin-system-audit-index');
|
||||
if (config) {
|
||||
@@ -42,7 +42,7 @@ if (config) {
|
||||
if (!cell.uuid) {
|
||||
return gridjs.html(label);
|
||||
}
|
||||
const url = new URL(`admin/users/edit/${cell.uuid}`, appBase).toString();
|
||||
const url = withCurrentListReturn(new URL(`admin/users/edit/${cell.uuid}`, appBase).toString());
|
||||
return gridjs.html(`<a href="${url}">${label}</a>`);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,6 +8,83 @@ export const getAppBase = () => {
|
||||
return `${window.location.origin}/`;
|
||||
};
|
||||
|
||||
const resolveAppBaseUrl = () => {
|
||||
try {
|
||||
return new URL(getAppBase(), `${window.location.origin}/`);
|
||||
} catch {
|
||||
return new URL(`${window.location.origin}/`);
|
||||
}
|
||||
};
|
||||
|
||||
const normalizeBasePathname = (pathname) => {
|
||||
const trimmed = String(pathname ?? '').trim();
|
||||
if (trimmed === '' || trimmed === '/') {
|
||||
return '/';
|
||||
}
|
||||
return `/${trimmed.replace(/^\/+|\/+$/g, '')}/`;
|
||||
};
|
||||
|
||||
const toAppRelativePath = (pathname, appBasePathname) => {
|
||||
const normalizedPath = `/${String(pathname ?? '').replace(/^\/+/, '')}`;
|
||||
const normalizedBasePath = normalizeBasePathname(appBasePathname);
|
||||
let relativePath = normalizedPath;
|
||||
|
||||
if (normalizedBasePath !== '/' && relativePath.startsWith(normalizedBasePath)) {
|
||||
relativePath = relativePath.slice(normalizedBasePath.length - 1);
|
||||
} else if (normalizedBasePath !== '/' && relativePath === normalizedBasePath.slice(0, -1)) {
|
||||
relativePath = '/';
|
||||
}
|
||||
|
||||
return relativePath.replace(/^\/+/, '');
|
||||
};
|
||||
|
||||
const parseAppUrl = (value, baseUrl = resolveAppBaseUrl()) => {
|
||||
const raw = String(value ?? '').trim();
|
||||
if (raw === '') {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new URL(raw, baseUrl);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const normalizeListReturnTarget = (sourceUrl = window.location.href) => {
|
||||
const appBaseUrl = resolveAppBaseUrl();
|
||||
const parsed = parseAppUrl(sourceUrl, appBaseUrl);
|
||||
if (!parsed) {
|
||||
return '';
|
||||
}
|
||||
const relativePath = toAppRelativePath(parsed.pathname, appBaseUrl.pathname);
|
||||
if (relativePath === '') {
|
||||
return '';
|
||||
}
|
||||
const query = new URLSearchParams(parsed.search);
|
||||
query.delete('return');
|
||||
const queryString = query.toString();
|
||||
return `${relativePath}${queryString ? `?${queryString}` : ''}`;
|
||||
};
|
||||
|
||||
export const withReturnTarget = (targetUrl, returnTarget = '') => {
|
||||
const appBaseUrl = resolveAppBaseUrl();
|
||||
const parsedTarget = parseAppUrl(targetUrl, appBaseUrl);
|
||||
if (!parsedTarget) {
|
||||
return String(targetUrl ?? '');
|
||||
}
|
||||
if (parsedTarget.origin !== window.location.origin) {
|
||||
return String(targetUrl ?? '');
|
||||
}
|
||||
const normalizedReturn = normalizeListReturnTarget(returnTarget);
|
||||
parsedTarget.searchParams.delete('return');
|
||||
if (normalizedReturn !== '') {
|
||||
parsedTarget.searchParams.set('return', normalizedReturn);
|
||||
}
|
||||
return parsedTarget.toString();
|
||||
};
|
||||
|
||||
export const withCurrentListReturn = (targetUrl) => withReturnTarget(targetUrl, window.location.href);
|
||||
|
||||
export const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
|
||||
Reference in New Issue
Block a user