feat: enhance schema type handling with new formats and UI components
This commit is contained in:
@@ -959,6 +959,34 @@ a.job-bar:hover { filter: brightness(1.1); box-shadow: 0 0 0 1px rgba(255,255,25
|
||||
padding: 5px 8px;
|
||||
width: 100%;
|
||||
}
|
||||
.schema-type-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
.schema-type-cell .schema-type-select {
|
||||
width: auto;
|
||||
min-width: 80px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.schema-fmt-wrapper {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
}
|
||||
.schema-fmt-input {
|
||||
width: 100%;
|
||||
min-width: 80px;
|
||||
}
|
||||
.schema-dec-wrapper {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
.schema-dec-prec,
|
||||
.schema-dec-scale {
|
||||
width: 54px;
|
||||
}
|
||||
|
||||
/* Field mapping */
|
||||
.mapping-header {
|
||||
|
||||
@@ -290,6 +290,40 @@
|
||||
// ── Schema type options ─────────────────────────────────────────────────────
|
||||
const SCHEMA_TYPES = {{ schema_types | tojson }};
|
||||
const IS_NEW = {{ 'true' if is_new else 'false' }};
|
||||
|
||||
const DATE_FORMATS = [
|
||||
'%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%d-%m-%Y',
|
||||
'%Y%m%d', '%d %b %Y', '%d %B %Y', '%b %d, %Y',
|
||||
];
|
||||
const DATETIME_FORMATS = [
|
||||
'%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S',
|
||||
'%d/%m/%Y %H:%M:%S', '%d/%m/%Y %H:%M',
|
||||
'%Y-%m-%d %H:%M', '%Y%m%d%H%M%S', '%d %b %Y %H:%M:%S',
|
||||
];
|
||||
|
||||
function parseSchemaType(typeStr) {
|
||||
if (!typeStr) return { base: 'str' };
|
||||
let m;
|
||||
if ((m = typeStr.match(/^date\('([^']+)'\)$/))) return { base: 'date', format: m[1] };
|
||||
if ((m = typeStr.match(/^datetime\('([^']+)'\)$/))) return { base: 'datetime', format: m[1] };
|
||||
if ((m = typeStr.match(/^decimal\((\d+),\s*(\d+)\)$/))) return { base: 'decimal', precision: +m[1], scale: +m[2] };
|
||||
return { base: typeStr };
|
||||
}
|
||||
|
||||
function composeSchemaType(row) {
|
||||
const base = row.querySelector('.schema-type-select').value;
|
||||
if (base === 'date' || base === 'datetime') {
|
||||
const fmt = row.querySelector('.schema-fmt-input')?.value.trim()
|
||||
|| (base === 'date' ? '%Y-%m-%d' : '%Y-%m-%d %H:%M:%S');
|
||||
return `${base}('${fmt}')`;
|
||||
}
|
||||
if (base === 'decimal') {
|
||||
const prec = parseInt(row.querySelector('.schema-dec-prec')?.value) || 18;
|
||||
const scale = parseInt(row.querySelector('.schema-dec-scale')?.value) || 2;
|
||||
return `decimal(${prec}, ${scale})`;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
const CONFIG_REF = {{ (reference | tojson) if not is_new else 'null' }};
|
||||
|
||||
// ── Build a syscfg card from a data object ──────────────────────────────────
|
||||
@@ -412,20 +446,76 @@ function addSchemaRow(card, colName, colType, isIndex) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'schema-row';
|
||||
|
||||
const parsed = parseSchemaType(colType);
|
||||
|
||||
const colInput = document.createElement('input');
|
||||
colInput.type = 'text';
|
||||
colInput.placeholder = 'column_name';
|
||||
colInput.value = colName || '';
|
||||
colInput.addEventListener('input', () => updateSchemaCount(card));
|
||||
|
||||
// ── Type cell ────────────────────────────────────────────────
|
||||
const typeCell = document.createElement('div');
|
||||
typeCell.className = 'schema-type-cell';
|
||||
|
||||
const typeSelect = document.createElement('select');
|
||||
typeSelect.className = 'schema-type-select';
|
||||
SCHEMA_TYPES.forEach(t => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = t; opt.textContent = t;
|
||||
if (t === (colType || 'str')) opt.selected = true;
|
||||
if (t === parsed.base) opt.selected = true;
|
||||
typeSelect.appendChild(opt);
|
||||
});
|
||||
|
||||
// Date / datetime format combobox
|
||||
const fmtId = `fmt-${Math.random().toString(36).slice(2)}`;
|
||||
const fmtWrapper = document.createElement('span');
|
||||
fmtWrapper.className = 'schema-fmt-wrapper';
|
||||
const fmtInput = document.createElement('input');
|
||||
fmtInput.type = 'text';
|
||||
fmtInput.className = 'schema-fmt-input';
|
||||
fmtInput.setAttribute('list', fmtId);
|
||||
if (parsed.format) fmtInput.value = parsed.format;
|
||||
const fmtList = document.createElement('datalist');
|
||||
fmtList.id = fmtId;
|
||||
fmtWrapper.append(fmtInput, fmtList);
|
||||
|
||||
// Decimal precision + scale inputs
|
||||
const decWrapper = document.createElement('span');
|
||||
decWrapper.className = 'schema-dec-wrapper';
|
||||
const precInput = document.createElement('input');
|
||||
precInput.type = 'number';
|
||||
precInput.className = 'schema-dec-prec';
|
||||
precInput.placeholder = 'prec';
|
||||
precInput.min = 1; precInput.max = 38;
|
||||
if (parsed.precision != null) precInput.value = parsed.precision;
|
||||
const scaleInput = document.createElement('input');
|
||||
scaleInput.type = 'number';
|
||||
scaleInput.className = 'schema-dec-scale';
|
||||
scaleInput.placeholder = 'scale';
|
||||
scaleInput.min = 0; scaleInput.max = 38;
|
||||
if (parsed.scale != null) scaleInput.value = parsed.scale;
|
||||
decWrapper.append(precInput, scaleInput);
|
||||
|
||||
function syncExtras() {
|
||||
const base = typeSelect.value;
|
||||
const isDate = base === 'date', isDt = base === 'datetime';
|
||||
fmtWrapper.hidden = !(isDate || isDt);
|
||||
decWrapper.hidden = base !== 'decimal';
|
||||
if (isDate || isDt) {
|
||||
fmtList.innerHTML = '';
|
||||
(isDate ? DATE_FORMATS : DATETIME_FORMATS).forEach(f => {
|
||||
const o = document.createElement('option'); o.value = f; fmtList.appendChild(o);
|
||||
});
|
||||
if (!fmtInput.value) fmtInput.value = isDate ? '%Y-%m-%d' : '%Y-%m-%d %H:%M:%S';
|
||||
fmtInput.placeholder = isDate ? '%Y-%m-%d' : '%Y-%m-%d %H:%M:%S';
|
||||
}
|
||||
}
|
||||
typeSelect.addEventListener('change', syncExtras);
|
||||
syncExtras();
|
||||
|
||||
typeCell.append(typeSelect, fmtWrapper, decWrapper);
|
||||
|
||||
const idxCheck = document.createElement('input');
|
||||
idxCheck.type = 'checkbox';
|
||||
idxCheck.className = 'idx-check';
|
||||
@@ -438,7 +528,7 @@ function addSchemaRow(card, colName, colType, isIndex) {
|
||||
removeBtn.textContent = '×';
|
||||
removeBtn.addEventListener('click', () => { row.remove(); updateSchemaCount(card); });
|
||||
|
||||
row.append(colInput, typeSelect, idxCheck, removeBtn);
|
||||
row.append(colInput, typeCell, idxCheck, removeBtn);
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
@@ -474,7 +564,7 @@ function readSyscfgCard(card) {
|
||||
const index_fields = [];
|
||||
card.querySelectorAll('.schema-rows .schema-row').forEach(row => {
|
||||
const name = row.querySelector('input[type="text"]').value.trim();
|
||||
const type = row.querySelector('select').value;
|
||||
const type = composeSchemaType(row);
|
||||
if (!name) return;
|
||||
schema[name] = type;
|
||||
if (row.querySelector('.idx-check')?.checked) index_fields.push(name);
|
||||
|
||||
Reference in New Issue
Block a user