@yuneta/gobj-ui 7.23.170 → 7.23.172
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/README.md +24 -0
- package/dist/gobj-ui.cjs.js +668 -737
- package/dist/gobj-ui.es.js +669 -738
- package/package.json +3 -3
- package/src/c_yui_treedb_schema.js +26 -5
- package/src/c_yui_treedb_topics.css +3 -0
- package/src/c_yui_treedb_topics.js +57 -35
- package/src/treedb_topic_keys.js +122 -0
- package/src/treedb_topic_keys.test.js +79 -0
- package/src/yui_dev.js +152 -363
- package/src/dev_machine_trace.js +0 -116
- package/src/dev_machine_trace.test.js +0 -123
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -32,7 +32,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
32
32
|
}) : target, mod));
|
|
33
33
|
//#endregion
|
|
34
34
|
let _yuneta_gobj_js = require("@yuneta/gobj-js");
|
|
35
|
-
_yuneta_gobj_js = __toESM(_yuneta_gobj_js, 1);
|
|
36
35
|
let i18next = require("i18next");
|
|
37
36
|
i18next = __toESM(i18next, 1);
|
|
38
37
|
let tom_select = require("tom-select");
|
|
@@ -23051,13 +23050,455 @@ function nodes_answer(data) {
|
|
|
23051
23050
|
};
|
|
23052
23051
|
}
|
|
23053
23052
|
//#endregion
|
|
23053
|
+
//#region src/schema_model.js
|
|
23054
|
+
/***********************************************************************
|
|
23055
|
+
* schema_model.js
|
|
23056
|
+
*
|
|
23057
|
+
* A SCHEMA out of the three meta-topics that store it.
|
|
23058
|
+
*
|
|
23059
|
+
* `treedb_system_schema` keeps every schema of a yuno as DATA, in
|
|
23060
|
+
* three flat topics — `treedbs`, `topics`, `cols` — linked by
|
|
23061
|
+
* fkeys. That is the right STORAGE and the wrong thing to put in
|
|
23062
|
+
* front of an operator: adding one column to one topic means
|
|
23063
|
+
* finding it in a table holding every column of every topic of
|
|
23064
|
+
* every treedb the yuno has.
|
|
23065
|
+
*
|
|
23066
|
+
* This module turns those three lists back into what they
|
|
23067
|
+
* describe: treedb -> topics -> columns, each in its declared
|
|
23068
|
+
* `order`. Pure, so the editor's model can be tested with no DOM
|
|
23069
|
+
* and no backend — the gclass fetches and draws, this decides
|
|
23070
|
+
* what the records MEAN.
|
|
23071
|
+
*
|
|
23072
|
+
* TWO THINGS IT EXISTS TO STATE ONCE:
|
|
23073
|
+
*
|
|
23074
|
+
* 1. A record is grouped by its FKEY, not by its id. The id is
|
|
23075
|
+
* qualified (`<treedb>.<topic>.<column>`) and reading it back
|
|
23076
|
+
* with a split on '.' works right up to the first treedb or
|
|
23077
|
+
* topic whose name carries one. The fkey is the link the store
|
|
23078
|
+
* itself uses; the id is only the fallback for a record whose
|
|
23079
|
+
* fkey never arrived.
|
|
23080
|
+
*
|
|
23081
|
+
* 2. A fkey reaches this code in FOUR shapes, because `nodes`
|
|
23082
|
+
* answers differently depending on the options it was called
|
|
23083
|
+
* with: the bare ref string, the expanded object, a list of
|
|
23084
|
+
* either, or a dict keyed by the ref. All four are the same
|
|
23085
|
+
* fact and parse_fkey_ref() flattens them to it.
|
|
23086
|
+
*
|
|
23087
|
+
* Copyright (c) 2026, ArtGins.
|
|
23088
|
+
* All Rights Reserved.
|
|
23089
|
+
***********************************************************************/
|
|
23090
|
+
var DEFAULT_ORDER = 9999;
|
|
23091
|
+
/***************************************************************
|
|
23092
|
+
* parse_fkey_ref(value) -> [{topic_name, id, hook_name}, ...]
|
|
23093
|
+
*
|
|
23094
|
+
* Every shape a fkey column can arrive in, flattened to the
|
|
23095
|
+
* refs it names. Anything unrecognizable contributes nothing —
|
|
23096
|
+
* a schema drawn without one link beats a screen that throws.
|
|
23097
|
+
***************************************************************/
|
|
23098
|
+
function parse_fkey_ref(value) {
|
|
23099
|
+
let refs = [];
|
|
23100
|
+
let push_one = (v) => {
|
|
23101
|
+
if (typeof v === "string") {
|
|
23102
|
+
let parts = v.split("^");
|
|
23103
|
+
if (parts.length !== 3) return;
|
|
23104
|
+
refs.push({
|
|
23105
|
+
topic_name: parts[0],
|
|
23106
|
+
id: parts[1],
|
|
23107
|
+
hook_name: parts[2]
|
|
23108
|
+
});
|
|
23109
|
+
return;
|
|
23110
|
+
}
|
|
23111
|
+
if (v && typeof v === "object") {
|
|
23112
|
+
let id = v.id;
|
|
23113
|
+
if (typeof id !== "string" || id.length === 0) return;
|
|
23114
|
+
refs.push({
|
|
23115
|
+
topic_name: v.topic_name || "",
|
|
23116
|
+
id,
|
|
23117
|
+
hook_name: v.hook_name || ""
|
|
23118
|
+
});
|
|
23119
|
+
}
|
|
23120
|
+
};
|
|
23121
|
+
if (value === null || value === void 0) return refs;
|
|
23122
|
+
if (typeof value === "string") {
|
|
23123
|
+
push_one(value);
|
|
23124
|
+
return refs;
|
|
23125
|
+
}
|
|
23126
|
+
if (Array.isArray(value)) {
|
|
23127
|
+
for (let v of value) push_one(v);
|
|
23128
|
+
return refs;
|
|
23129
|
+
}
|
|
23130
|
+
if (typeof value === "object") for (let [key, v] of Object.entries(value)) if (v && typeof v === "object" && typeof v.id === "string") push_one(v);
|
|
23131
|
+
else push_one(key);
|
|
23132
|
+
return refs;
|
|
23133
|
+
}
|
|
23134
|
+
/***************************************************************
|
|
23135
|
+
* The id of the FIRST parent a record names, or "" when it
|
|
23136
|
+
* names none. A record has one parent here — a column belongs to
|
|
23137
|
+
* one topic, a topic to one treedb — and a second ref would be a
|
|
23138
|
+
* store this editor cannot draw anyway.
|
|
23139
|
+
***************************************************************/
|
|
23140
|
+
function parent_id(record, fkey_col) {
|
|
23141
|
+
let refs = parse_fkey_ref(record ? record[fkey_col] : null);
|
|
23142
|
+
return refs.length > 0 ? refs[0].id : "";
|
|
23143
|
+
}
|
|
23144
|
+
/***************************************************************
|
|
23145
|
+
* The name a record is KNOWN by, which is not what it is keyed
|
|
23146
|
+
* by: `topics` and `cols` key by the qualified id and carry the
|
|
23147
|
+
* bare name in `value` (its pkey2). An older store that still
|
|
23148
|
+
* keyed by rowid has no `value` worth showing, so the id stands
|
|
23149
|
+
* in — the same fallback as node_label().
|
|
23150
|
+
***************************************************************/
|
|
23151
|
+
function record_name(record) {
|
|
23152
|
+
if (!record) return "";
|
|
23153
|
+
if (typeof record.value === "string" && record.value.length > 0) return record.value;
|
|
23154
|
+
return typeof record.id === "string" ? record.id : "";
|
|
23155
|
+
}
|
|
23156
|
+
/***************************************************************
|
|
23157
|
+
* The `order` of a record as a NUMBER, whatever the store put
|
|
23158
|
+
* there: an integer column read back from JSON may arrive as a
|
|
23159
|
+
* string, and comparing "10" with 9 sorts the schema wrong.
|
|
23160
|
+
***************************************************************/
|
|
23161
|
+
function record_order(record) {
|
|
23162
|
+
let order = record ? record.order : void 0;
|
|
23163
|
+
if (typeof order === "number" && isFinite(order)) return order;
|
|
23164
|
+
if (typeof order === "string" && order.trim().length > 0) {
|
|
23165
|
+
let n = Number(order);
|
|
23166
|
+
if (isFinite(n)) return n;
|
|
23167
|
+
}
|
|
23168
|
+
return DEFAULT_ORDER;
|
|
23169
|
+
}
|
|
23170
|
+
/***************************************************************
|
|
23171
|
+
* Sort in place by `order`, ties broken by name so a schema
|
|
23172
|
+
* whose records all default to 9999 still draws the same way
|
|
23173
|
+
* twice.
|
|
23174
|
+
***************************************************************/
|
|
23175
|
+
function sort_by_order(list) {
|
|
23176
|
+
list.sort((a, b) => {
|
|
23177
|
+
if (a.order !== b.order) return a.order - b.order;
|
|
23178
|
+
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
23179
|
+
});
|
|
23180
|
+
return list;
|
|
23181
|
+
}
|
|
23182
|
+
/***************************************************************
|
|
23183
|
+
* build_schema_model({treedbs, topics, cols}) -> model
|
|
23184
|
+
*
|
|
23185
|
+
* model = {
|
|
23186
|
+
* treedbs: [{
|
|
23187
|
+
* id, name, record,
|
|
23188
|
+
* schema_version, c_schema_version, system_schema_version,
|
|
23189
|
+
* topics: [{
|
|
23190
|
+
* id, name, order, record,
|
|
23191
|
+
* pkey, topic_version, system_topic, main_topic,
|
|
23192
|
+
* cols: [{id, name, order, record}]
|
|
23193
|
+
* }]
|
|
23194
|
+
* }],
|
|
23195
|
+
* orphan_topics: [...], topics whose treedb is not in the store
|
|
23196
|
+
* orphan_cols: [...] columns whose topic is not in the store
|
|
23197
|
+
* }
|
|
23198
|
+
*
|
|
23199
|
+
* An orphan is NOT dropped. A column whose topic was deleted is
|
|
23200
|
+
* exactly the kind of leftover an operator opens this editor to
|
|
23201
|
+
* find, and a model that hides it makes the editor lie.
|
|
23202
|
+
***************************************************************/
|
|
23203
|
+
function build_schema_model(records) {
|
|
23204
|
+
let r = records || {};
|
|
23205
|
+
let treedb_rows = Array.isArray(r.treedbs) ? r.treedbs : [];
|
|
23206
|
+
let topic_rows = Array.isArray(r.topics) ? r.topics : [];
|
|
23207
|
+
let col_rows = Array.isArray(r.cols) ? r.cols : [];
|
|
23208
|
+
let treedbs = [];
|
|
23209
|
+
let by_treedb_id = {};
|
|
23210
|
+
for (let record of treedb_rows) {
|
|
23211
|
+
if (!record || typeof record.id !== "string") continue;
|
|
23212
|
+
let entry = {
|
|
23213
|
+
id: record.id,
|
|
23214
|
+
name: record.id,
|
|
23215
|
+
record,
|
|
23216
|
+
schema_version: record.schema_version,
|
|
23217
|
+
c_schema_version: record.c_schema_version,
|
|
23218
|
+
system_schema_version: record.system_schema_version,
|
|
23219
|
+
topics: []
|
|
23220
|
+
};
|
|
23221
|
+
treedbs.push(entry);
|
|
23222
|
+
by_treedb_id[entry.id] = entry;
|
|
23223
|
+
}
|
|
23224
|
+
let orphan_topics = [];
|
|
23225
|
+
let by_topic_id = {};
|
|
23226
|
+
for (let record of topic_rows) {
|
|
23227
|
+
if (!record || typeof record.id !== "string") continue;
|
|
23228
|
+
let entry = {
|
|
23229
|
+
id: record.id,
|
|
23230
|
+
name: record_name(record),
|
|
23231
|
+
order: record_order(record),
|
|
23232
|
+
record,
|
|
23233
|
+
treedb_id: parent_id(record, "treedbs"),
|
|
23234
|
+
pkey: record.pkey || "",
|
|
23235
|
+
pkey2s: record.pkey2s,
|
|
23236
|
+
system_flag: record.system_flag || "",
|
|
23237
|
+
tkey: record.tkey || "",
|
|
23238
|
+
topic_version: record.topic_version,
|
|
23239
|
+
system_topic: !!record.system_topic,
|
|
23240
|
+
main_topic: !!record.main_topic,
|
|
23241
|
+
cols: []
|
|
23242
|
+
};
|
|
23243
|
+
by_topic_id[entry.id] = entry;
|
|
23244
|
+
let parent = by_treedb_id[entry.treedb_id];
|
|
23245
|
+
if (parent) parent.topics.push(entry);
|
|
23246
|
+
else orphan_topics.push(entry);
|
|
23247
|
+
}
|
|
23248
|
+
let orphan_cols = [];
|
|
23249
|
+
for (let record of col_rows) {
|
|
23250
|
+
if (!record || typeof record.id !== "string") continue;
|
|
23251
|
+
let entry = {
|
|
23252
|
+
id: record.id,
|
|
23253
|
+
name: record_name(record),
|
|
23254
|
+
order: record_order(record),
|
|
23255
|
+
record,
|
|
23256
|
+
topic_id: parent_id(record, "topics")
|
|
23257
|
+
};
|
|
23258
|
+
let parent = by_topic_id[entry.topic_id];
|
|
23259
|
+
if (parent) parent.cols.push(entry);
|
|
23260
|
+
else orphan_cols.push(entry);
|
|
23261
|
+
}
|
|
23262
|
+
for (let treedb of treedbs) {
|
|
23263
|
+
sort_by_order(treedb.topics);
|
|
23264
|
+
for (let topic of treedb.topics) sort_by_order(topic.cols);
|
|
23265
|
+
}
|
|
23266
|
+
for (let topic of orphan_topics) sort_by_order(topic.cols);
|
|
23267
|
+
treedbs.sort((a, b) => {
|
|
23268
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
23269
|
+
});
|
|
23270
|
+
sort_by_order(orphan_topics);
|
|
23271
|
+
sort_by_order(orphan_cols);
|
|
23272
|
+
return {
|
|
23273
|
+
treedbs,
|
|
23274
|
+
orphan_topics,
|
|
23275
|
+
orphan_cols
|
|
23276
|
+
};
|
|
23277
|
+
}
|
|
23278
|
+
/***************************************************************
|
|
23279
|
+
* Is there a value here at all?
|
|
23280
|
+
*
|
|
23281
|
+
* The store answers a `blob` column that was never set with an
|
|
23282
|
+
* EMPTY COLLECTION, not with nothing: `enum: {}`, `hook: {}`,
|
|
23283
|
+
* `default: {}`. Read as "a value", those turn every export into
|
|
23284
|
+
* a schema full of empty objects — and `'hook': {}` in a literal
|
|
23285
|
+
* is a hook with no mapping, which is a link the treedb builds
|
|
23286
|
+
* and nothing writes.
|
|
23287
|
+
***************************************************************/
|
|
23288
|
+
function is_empty_value(value) {
|
|
23289
|
+
if (value === null || value === void 0 || value === "") return true;
|
|
23290
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
23291
|
+
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
23292
|
+
return false;
|
|
23293
|
+
}
|
|
23294
|
+
/***************************************************************
|
|
23295
|
+
* The fields of a column that are DECLARED as one thing and
|
|
23296
|
+
* STORED as another.
|
|
23297
|
+
*
|
|
23298
|
+
* `hook`, `enum`, `default`, `pkey2s` and `properties` are `blob`
|
|
23299
|
+
* columns of the `cols` topic (treedb_system_schema.c), so what
|
|
23300
|
+
* comes back may be the value or the JSON text of the value,
|
|
23301
|
+
* depending on how it was written — a projection writes the
|
|
23302
|
+
* value, a hand edit through a plain text field writes the text.
|
|
23303
|
+
* `flag` is an array that a single-flag edit can leave as a bare
|
|
23304
|
+
* string. Reading these without saying so is how a hook drawn
|
|
23305
|
+
* from `{"users":"department"}` becomes no hook at all.
|
|
23306
|
+
***************************************************************/
|
|
23307
|
+
function as_json(value) {
|
|
23308
|
+
if (typeof value !== "string") return value;
|
|
23309
|
+
let text = value.trim();
|
|
23310
|
+
if (text.length === 0) return null;
|
|
23311
|
+
try {
|
|
23312
|
+
return JSON.parse(text);
|
|
23313
|
+
} catch (e) {
|
|
23314
|
+
return value;
|
|
23315
|
+
}
|
|
23316
|
+
}
|
|
23317
|
+
function col_flags(record) {
|
|
23318
|
+
let flag = record ? record.flag : null;
|
|
23319
|
+
if (Array.isArray(flag)) return flag.filter((f) => typeof f === "string" && f.length > 0);
|
|
23320
|
+
if (typeof flag === "string" && flag.length > 0) {
|
|
23321
|
+
let parsed = as_json(flag);
|
|
23322
|
+
if (Array.isArray(parsed)) return parsed.filter((f) => typeof f === "string" && f.length > 0);
|
|
23323
|
+
return [flag];
|
|
23324
|
+
}
|
|
23325
|
+
return [];
|
|
23326
|
+
}
|
|
23327
|
+
function col_hook(record) {
|
|
23328
|
+
let hook = as_json(record ? record.hook : null);
|
|
23329
|
+
if (hook && typeof hook === "object" && !Array.isArray(hook)) return hook;
|
|
23330
|
+
return null;
|
|
23331
|
+
}
|
|
23332
|
+
function col_enum(record) {
|
|
23333
|
+
let e = as_json(record ? record.enum : null);
|
|
23334
|
+
if (Array.isArray(e)) return e;
|
|
23335
|
+
return [];
|
|
23336
|
+
}
|
|
23337
|
+
function topic_pkey2s(record) {
|
|
23338
|
+
let pkey2s = as_json(record ? record.pkey2s : null);
|
|
23339
|
+
if (Array.isArray(pkey2s)) return pkey2s.filter((k) => typeof k === "string" && k.length > 0);
|
|
23340
|
+
if (typeof pkey2s === "string" && pkey2s.length > 0) return [pkey2s];
|
|
23341
|
+
return [];
|
|
23342
|
+
}
|
|
23343
|
+
/***************************************************************
|
|
23344
|
+
* Lookups by id. The editor addresses a position by NAME (the
|
|
23345
|
+
* url carries `<treedb>/<topic>`), so both are offered.
|
|
23346
|
+
***************************************************************/
|
|
23347
|
+
function find_treedb(model, treedb_id) {
|
|
23348
|
+
if (!model || !Array.isArray(model.treedbs)) return null;
|
|
23349
|
+
for (let treedb of model.treedbs) if (treedb.id === treedb_id) return treedb;
|
|
23350
|
+
return null;
|
|
23351
|
+
}
|
|
23352
|
+
function find_topic(model, treedb_id, topic_name) {
|
|
23353
|
+
let treedb = find_treedb(model, treedb_id);
|
|
23354
|
+
if (!treedb) return null;
|
|
23355
|
+
for (let topic of treedb.topics) if (topic.name === topic_name || topic.id === topic_name) return topic;
|
|
23356
|
+
return null;
|
|
23357
|
+
}
|
|
23358
|
+
function find_col(model, treedb_id, topic_name, col_name) {
|
|
23359
|
+
let topic = find_topic(model, treedb_id, topic_name);
|
|
23360
|
+
if (!topic) return null;
|
|
23361
|
+
for (let col of topic.cols) if (col.name === col_name || col.id === col_name) return col;
|
|
23362
|
+
return null;
|
|
23363
|
+
}
|
|
23364
|
+
/***************************************************************
|
|
23365
|
+
* The fkey a NEW record must carry to belong to `parent_id`.
|
|
23366
|
+
* Written here because the editor is the only writer that has to
|
|
23367
|
+
* compose one, and getting the hook name wrong links the record
|
|
23368
|
+
* to nothing while the write still succeeds.
|
|
23369
|
+
***************************************************************/
|
|
23370
|
+
function fkey_ref(parent_topic, parent_id_, hook_name) {
|
|
23371
|
+
return `${parent_topic}^${parent_id_}^${hook_name}`;
|
|
23372
|
+
}
|
|
23373
|
+
/***************************************************************
|
|
23374
|
+
* Where a new sibling goes: after the last one. The store's own
|
|
23375
|
+
* default (9999) would put every hand-made column in the same
|
|
23376
|
+
* place and let their names decide the schema's order.
|
|
23377
|
+
***************************************************************/
|
|
23378
|
+
function next_order(siblings) {
|
|
23379
|
+
let max = 0;
|
|
23380
|
+
if (Array.isArray(siblings)) for (let s of siblings) {
|
|
23381
|
+
let order = s && typeof s.order === "number" ? s.order : DEFAULT_ORDER;
|
|
23382
|
+
if (order < 9999 && order > max) max = order;
|
|
23383
|
+
}
|
|
23384
|
+
return max + 1;
|
|
23385
|
+
}
|
|
23386
|
+
/***************************************************************
|
|
23387
|
+
* Renumber a list AFTER a move, as the writes it takes: only the
|
|
23388
|
+
* records whose order actually changed, so a drag of one row in a
|
|
23389
|
+
* 40-column topic is not 40 writes.
|
|
23390
|
+
*
|
|
23391
|
+
* moved_orders(list) -> [{id, order}, ...]
|
|
23392
|
+
***************************************************************/
|
|
23393
|
+
function moved_orders(list) {
|
|
23394
|
+
let writes = [];
|
|
23395
|
+
if (!Array.isArray(list)) return writes;
|
|
23396
|
+
for (let i = 0; i < list.length; i++) {
|
|
23397
|
+
let entry = list[i];
|
|
23398
|
+
let order = i + 1;
|
|
23399
|
+
if (!entry || typeof entry.id !== "string") continue;
|
|
23400
|
+
if (entry.order !== order) writes.push({
|
|
23401
|
+
id: entry.id,
|
|
23402
|
+
order
|
|
23403
|
+
});
|
|
23404
|
+
}
|
|
23405
|
+
return writes;
|
|
23406
|
+
}
|
|
23407
|
+
//#endregion
|
|
23408
|
+
//#region src/treedb_topic_keys.js
|
|
23409
|
+
/***********************************************************************
|
|
23410
|
+
* treedb_topic_keys.js
|
|
23411
|
+
*
|
|
23412
|
+
* The KEYS of a treedb topic, read from its desc: the pkey, the
|
|
23413
|
+
* secondary keys (`pkey2s`) and the time key (`tkey`), plus the
|
|
23414
|
+
* names behind its `system_flag` number.
|
|
23415
|
+
*
|
|
23416
|
+
* Every view that describes a topic -- the schema diagram, the
|
|
23417
|
+
* topic-info panel, the topic cards -- must say them, and say them
|
|
23418
|
+
* the same way. A topic with `pkey2s` is not a topic with one more
|
|
23419
|
+
* column: one id holds several INSTANCES, an update has to carry
|
|
23420
|
+
* the pkey2 or it lands on the primary, and `delete-instance`
|
|
23421
|
+
* exists. `tkey` names where the time of every record comes from.
|
|
23422
|
+
* The views said neither, so this is where they ask.
|
|
23423
|
+
*
|
|
23424
|
+
* Pure, so it is tested with no DOM.
|
|
23425
|
+
*
|
|
23426
|
+
* Copyright (c) 2026, ArtGins.
|
|
23427
|
+
* All Rights Reserved.
|
|
23428
|
+
***********************************************************************/
|
|
23429
|
+
var SF_NAMES = [
|
|
23430
|
+
"sf_string_key",
|
|
23431
|
+
"sf_rowid_key",
|
|
23432
|
+
"sf_int_key",
|
|
23433
|
+
"",
|
|
23434
|
+
"sf_zip_record",
|
|
23435
|
+
"sf_cipher_record",
|
|
23436
|
+
"",
|
|
23437
|
+
"",
|
|
23438
|
+
"sf_t_ms",
|
|
23439
|
+
"sf_tm_ms",
|
|
23440
|
+
"sf_deleted_instance",
|
|
23441
|
+
"sf_immutable_record",
|
|
23442
|
+
"sf_loading_from_disk",
|
|
23443
|
+
"",
|
|
23444
|
+
"",
|
|
23445
|
+
""
|
|
23446
|
+
];
|
|
23447
|
+
/************************************************************
|
|
23448
|
+
* The secondary keys of a topic, always a list. The desc
|
|
23449
|
+
* carries a list; a schema literal may declare a bare
|
|
23450
|
+
* string.
|
|
23451
|
+
************************************************************/
|
|
23452
|
+
function desc_pkey2s(desc) {
|
|
23453
|
+
return topic_pkey2s(desc);
|
|
23454
|
+
}
|
|
23455
|
+
/************************************************************
|
|
23456
|
+
* The time key of a topic, "" when it has none -- and then
|
|
23457
|
+
* the time of a record is the time it was appended.
|
|
23458
|
+
************************************************************/
|
|
23459
|
+
function desc_tkey(desc) {
|
|
23460
|
+
let tkey = desc ? desc.tkey : "";
|
|
23461
|
+
return typeof tkey === "string" ? tkey : "";
|
|
23462
|
+
}
|
|
23463
|
+
/************************************************************
|
|
23464
|
+
* Which keys of its topic a column IS, in the order the
|
|
23465
|
+
* views print them: "pkey", "pkey2", "tkey". Empty for a
|
|
23466
|
+
* column that is none.
|
|
23467
|
+
************************************************************/
|
|
23468
|
+
function col_key_roles(desc, col_id) {
|
|
23469
|
+
let roles = [];
|
|
23470
|
+
if (!desc || typeof col_id !== "string" || col_id.length === 0) return roles;
|
|
23471
|
+
if (col_id === (desc.pkey || "id")) roles.push("pkey");
|
|
23472
|
+
if (desc_pkey2s(desc).includes(col_id)) roles.push("pkey2");
|
|
23473
|
+
if (desc_tkey(desc) === col_id) roles.push("tkey");
|
|
23474
|
+
return roles;
|
|
23475
|
+
}
|
|
23476
|
+
/************************************************************
|
|
23477
|
+
* The names of a system_flag. The desc carries the NUMBER
|
|
23478
|
+
* (`1`), a schema literal carries the names
|
|
23479
|
+
* ("sf_string_key|sf_t_ms"); both come back as a list. A
|
|
23480
|
+
* set bit with no name is shown by its value, never
|
|
23481
|
+
* dropped.
|
|
23482
|
+
************************************************************/
|
|
23483
|
+
function system_flag_names(system_flag) {
|
|
23484
|
+
if (Array.isArray(system_flag)) return system_flag.filter((n) => typeof n === "string" && n.length > 0);
|
|
23485
|
+
if (typeof system_flag === "string") return system_flag.split(/[|,]/).map((n) => n.trim()).filter((n) => n.length > 0);
|
|
23486
|
+
if (typeof system_flag !== "number" || !Number.isInteger(system_flag) || system_flag <= 0) return [];
|
|
23487
|
+
let names = [];
|
|
23488
|
+
for (let bit = 0; bit < SF_NAMES.length; bit++) {
|
|
23489
|
+
let mask = 1 << bit;
|
|
23490
|
+
if (system_flag & mask) names.push(SF_NAMES[bit] || `0x${mask.toString(16).padStart(4, "0")}`);
|
|
23491
|
+
}
|
|
23492
|
+
return names;
|
|
23493
|
+
}
|
|
23494
|
+
//#endregion
|
|
23054
23495
|
//#region src/c_yui_treedb_topics.js
|
|
23055
23496
|
/***********************************************************************
|
|
23056
23497
|
* c_yui_treedb_topics.js
|
|
23057
23498
|
*
|
|
23058
23499
|
* Management of TreeDB's topics with Bulma tabs
|
|
23059
23500
|
*
|
|
23060
|
-
* Copyright (c) 2025, ArtGins.
|
|
23501
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
23061
23502
|
* All Rights Reserved.
|
|
23062
23503
|
***********************************************************************/
|
|
23063
23504
|
/***************************************************************
|
|
@@ -23571,6 +24012,29 @@ function topic_card_meta(desc) {
|
|
|
23571
24012
|
{ class: "TREEDB_TOPIC_CARD_META" },
|
|
23572
24013
|
head
|
|
23573
24014
|
]);
|
|
24015
|
+
let pkey2s = desc_pkey2s(desc);
|
|
24016
|
+
if (pkey2s.length) {
|
|
24017
|
+
let list = pkey2s.join(", ");
|
|
24018
|
+
meta.push([
|
|
24019
|
+
"div",
|
|
24020
|
+
{
|
|
24021
|
+
class: "TREEDB_TOPIC_CARD_REL TREEDB_TOPIC_CARD_PKEY2S",
|
|
24022
|
+
title: list
|
|
24023
|
+
},
|
|
24024
|
+
[[
|
|
24025
|
+
"span",
|
|
24026
|
+
{
|
|
24027
|
+
class: "TREEDB_TOPIC_CARD_REL_LABEL",
|
|
24028
|
+
i18n: "pkey2s"
|
|
24029
|
+
},
|
|
24030
|
+
"pkey2s"
|
|
24031
|
+
], [
|
|
24032
|
+
"span",
|
|
24033
|
+
{ class: "TREEDB_TOPIC_CARD_REL_LIST" },
|
|
24034
|
+
list
|
|
24035
|
+
]]
|
|
24036
|
+
]);
|
|
24037
|
+
}
|
|
23574
24038
|
let relation = (cls, key, arrow, names) => {
|
|
23575
24039
|
let list = names.join(", ");
|
|
23576
24040
|
return [
|
|
@@ -23834,33 +24298,26 @@ function show_topic_info(gobj, topic) {
|
|
|
23834
24298
|
}
|
|
23835
24299
|
/************************************************************
|
|
23836
24300
|
* Build the read-only topic-info panel from a topic desc: the
|
|
23837
|
-
* topic name, its
|
|
24301
|
+
* topic name, its KEYS, and a table of columns (name / type /
|
|
23838
24302
|
* key relationship). Everything is guarded — a malformed desc
|
|
23839
24303
|
* renders a shorter panel, never throws.
|
|
24304
|
+
*
|
|
24305
|
+
* The keys are what an operator has to know before touching a
|
|
24306
|
+
* record, so they are all said, and the empty ones too: a
|
|
24307
|
+
* topic with `pkey2s` keeps several instances under one id,
|
|
24308
|
+
* and an empty `tkey` means the time of a record is the time
|
|
24309
|
+
* it was appended -- a row missing is not the same as "none".
|
|
23840
24310
|
************************************************************/
|
|
23841
24311
|
function build_topic_info_panel(gobj, $info, topic, desc) {
|
|
23842
24312
|
while ($info.firstChild) $info.removeChild($info.firstChild);
|
|
23843
24313
|
let pkey = desc.pkey || "";
|
|
23844
|
-
let
|
|
23845
|
-
|
|
23846
|
-
if ((0, _yuneta_gobj_js.is_object)(v)) return Object.keys(v).join(", ");
|
|
23847
|
-
return v === void 0 || v === null ? "" : String(v);
|
|
23848
|
-
};
|
|
24314
|
+
let pkey2s = desc_pkey2s(desc);
|
|
24315
|
+
let tkey = desc_tkey(desc);
|
|
23849
24316
|
let $meta = [];
|
|
23850
|
-
let push_meta = (key,
|
|
23851
|
-
if (value === void 0 || value === null || value === "") return;
|
|
23852
|
-
let $val = highlight ? [
|
|
23853
|
-
"span",
|
|
23854
|
-
{ class: "tag is-info" },
|
|
23855
|
-
`${value}`
|
|
23856
|
-
] : [
|
|
23857
|
-
"code",
|
|
23858
|
-
{},
|
|
23859
|
-
`${value}`
|
|
23860
|
-
];
|
|
24317
|
+
let push_meta = (key, $val) => {
|
|
23861
24318
|
$meta.push([
|
|
23862
24319
|
"tr",
|
|
23863
|
-
{},
|
|
24320
|
+
{ class: `TREEDB_TOPIC_INFO_${key.toUpperCase()}` },
|
|
23864
24321
|
[[
|
|
23865
24322
|
"th",
|
|
23866
24323
|
{
|
|
@@ -23875,29 +24332,64 @@ function build_topic_info_panel(gobj, $info, topic, desc) {
|
|
|
23875
24332
|
]]
|
|
23876
24333
|
]);
|
|
23877
24334
|
};
|
|
23878
|
-
push_meta("version",
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
|
|
24335
|
+
if (desc.topic_version !== void 0 && desc.topic_version !== null && desc.topic_version !== "") push_meta("version", [
|
|
24336
|
+
"span",
|
|
24337
|
+
{ class: "tag is-info" },
|
|
24338
|
+
`${desc.topic_version}`
|
|
24339
|
+
]);
|
|
24340
|
+
let sf_names = system_flag_names(desc.system_flag);
|
|
24341
|
+
if (sf_names.length > 0) push_meta("system", [
|
|
24342
|
+
"code",
|
|
24343
|
+
{ title: `${desc.system_flag}` },
|
|
24344
|
+
sf_names.join(" | ")
|
|
24345
|
+
]);
|
|
24346
|
+
if (pkey) push_meta("pkey", [
|
|
24347
|
+
"code",
|
|
24348
|
+
{},
|
|
24349
|
+
pkey
|
|
24350
|
+
]);
|
|
24351
|
+
if (pkey2s.length > 0) push_meta("pkey2s", [
|
|
24352
|
+
"span",
|
|
24353
|
+
{ class: "tags" },
|
|
24354
|
+
pkey2s.map((name) => [
|
|
24355
|
+
"span",
|
|
24356
|
+
{ class: "tag is-warning" },
|
|
24357
|
+
name
|
|
24358
|
+
])
|
|
24359
|
+
]);
|
|
24360
|
+
push_meta("tkey", tkey ? [
|
|
24361
|
+
"code",
|
|
24362
|
+
{},
|
|
24363
|
+
tkey
|
|
24364
|
+
] : [
|
|
24365
|
+
"span",
|
|
24366
|
+
{
|
|
24367
|
+
class: "has-text-grey",
|
|
24368
|
+
i18n: "append time"
|
|
24369
|
+
},
|
|
24370
|
+
"append time"
|
|
24371
|
+
]);
|
|
23882
24372
|
let $rows = [];
|
|
23883
24373
|
let cols = (0, _yuneta_gobj_js.is_array)(desc.cols) ? desc.cols : [];
|
|
23884
24374
|
for (let col of cols) {
|
|
23885
24375
|
if (!col || !col.id || col.id.charAt(0) === "_") continue;
|
|
23886
24376
|
let type = col.type || ((0, _yuneta_gobj_js.is_array)(col.flag) ? col.flag.join(", ") : col.flag || "");
|
|
23887
|
-
let
|
|
23888
|
-
|
|
23889
|
-
|
|
23890
|
-
else if ((0, _yuneta_gobj_js.is_object)(col.hook))
|
|
24377
|
+
let roles = col_key_roles(desc, col.id);
|
|
24378
|
+
let parts = roles.slice();
|
|
24379
|
+
if ((0, _yuneta_gobj_js.is_object)(col.fkey)) parts.push("→ " + Object.keys(col.fkey).join(", "));
|
|
24380
|
+
else if ((0, _yuneta_gobj_js.is_object)(col.hook)) parts.push("hook → " + Object.keys(col.hook).join(", "));
|
|
24381
|
+
let rel = parts.join(" · ");
|
|
24382
|
+
let is_key = roles.length > 0;
|
|
23891
24383
|
$rows.push([
|
|
23892
24384
|
"tr",
|
|
23893
|
-
{},
|
|
24385
|
+
is_key ? { class: "TREEDB_TOPIC_INFO_KEY_COL" } : {},
|
|
23894
24386
|
[
|
|
23895
24387
|
[
|
|
23896
24388
|
"td",
|
|
23897
24389
|
{},
|
|
23898
24390
|
[[
|
|
23899
24391
|
"code",
|
|
23900
|
-
{},
|
|
24392
|
+
is_key ? { class: "has-text-weight-bold" } : {},
|
|
23901
24393
|
`${col.id}`
|
|
23902
24394
|
]]
|
|
23903
24395
|
],
|
|
@@ -23908,7 +24400,7 @@ function build_topic_info_panel(gobj, $info, topic, desc) {
|
|
|
23908
24400
|
],
|
|
23909
24401
|
[
|
|
23910
24402
|
"td",
|
|
23911
|
-
{},
|
|
24403
|
+
is_key ? { class: "has-text-weight-semibold" } : {},
|
|
23912
24404
|
`${rel}`
|
|
23913
24405
|
]
|
|
23914
24406
|
]
|
|
@@ -25643,361 +26135,6 @@ function row_matches(row, term) {
|
|
|
25643
26135
|
});
|
|
25644
26136
|
}
|
|
25645
26137
|
//#endregion
|
|
25646
|
-
//#region src/schema_model.js
|
|
25647
|
-
/***********************************************************************
|
|
25648
|
-
* schema_model.js
|
|
25649
|
-
*
|
|
25650
|
-
* A SCHEMA out of the three meta-topics that store it.
|
|
25651
|
-
*
|
|
25652
|
-
* `treedb_system_schema` keeps every schema of a yuno as DATA, in
|
|
25653
|
-
* three flat topics — `treedbs`, `topics`, `cols` — linked by
|
|
25654
|
-
* fkeys. That is the right STORAGE and the wrong thing to put in
|
|
25655
|
-
* front of an operator: adding one column to one topic means
|
|
25656
|
-
* finding it in a table holding every column of every topic of
|
|
25657
|
-
* every treedb the yuno has.
|
|
25658
|
-
*
|
|
25659
|
-
* This module turns those three lists back into what they
|
|
25660
|
-
* describe: treedb -> topics -> columns, each in its declared
|
|
25661
|
-
* `order`. Pure, so the editor's model can be tested with no DOM
|
|
25662
|
-
* and no backend — the gclass fetches and draws, this decides
|
|
25663
|
-
* what the records MEAN.
|
|
25664
|
-
*
|
|
25665
|
-
* TWO THINGS IT EXISTS TO STATE ONCE:
|
|
25666
|
-
*
|
|
25667
|
-
* 1. A record is grouped by its FKEY, not by its id. The id is
|
|
25668
|
-
* qualified (`<treedb>.<topic>.<column>`) and reading it back
|
|
25669
|
-
* with a split on '.' works right up to the first treedb or
|
|
25670
|
-
* topic whose name carries one. The fkey is the link the store
|
|
25671
|
-
* itself uses; the id is only the fallback for a record whose
|
|
25672
|
-
* fkey never arrived.
|
|
25673
|
-
*
|
|
25674
|
-
* 2. A fkey reaches this code in FOUR shapes, because `nodes`
|
|
25675
|
-
* answers differently depending on the options it was called
|
|
25676
|
-
* with: the bare ref string, the expanded object, a list of
|
|
25677
|
-
* either, or a dict keyed by the ref. All four are the same
|
|
25678
|
-
* fact and parse_fkey_ref() flattens them to it.
|
|
25679
|
-
*
|
|
25680
|
-
* Copyright (c) 2026, ArtGins.
|
|
25681
|
-
* All Rights Reserved.
|
|
25682
|
-
***********************************************************************/
|
|
25683
|
-
var DEFAULT_ORDER = 9999;
|
|
25684
|
-
/***************************************************************
|
|
25685
|
-
* parse_fkey_ref(value) -> [{topic_name, id, hook_name}, ...]
|
|
25686
|
-
*
|
|
25687
|
-
* Every shape a fkey column can arrive in, flattened to the
|
|
25688
|
-
* refs it names. Anything unrecognizable contributes nothing —
|
|
25689
|
-
* a schema drawn without one link beats a screen that throws.
|
|
25690
|
-
***************************************************************/
|
|
25691
|
-
function parse_fkey_ref(value) {
|
|
25692
|
-
let refs = [];
|
|
25693
|
-
let push_one = (v) => {
|
|
25694
|
-
if (typeof v === "string") {
|
|
25695
|
-
let parts = v.split("^");
|
|
25696
|
-
if (parts.length !== 3) return;
|
|
25697
|
-
refs.push({
|
|
25698
|
-
topic_name: parts[0],
|
|
25699
|
-
id: parts[1],
|
|
25700
|
-
hook_name: parts[2]
|
|
25701
|
-
});
|
|
25702
|
-
return;
|
|
25703
|
-
}
|
|
25704
|
-
if (v && typeof v === "object") {
|
|
25705
|
-
let id = v.id;
|
|
25706
|
-
if (typeof id !== "string" || id.length === 0) return;
|
|
25707
|
-
refs.push({
|
|
25708
|
-
topic_name: v.topic_name || "",
|
|
25709
|
-
id,
|
|
25710
|
-
hook_name: v.hook_name || ""
|
|
25711
|
-
});
|
|
25712
|
-
}
|
|
25713
|
-
};
|
|
25714
|
-
if (value === null || value === void 0) return refs;
|
|
25715
|
-
if (typeof value === "string") {
|
|
25716
|
-
push_one(value);
|
|
25717
|
-
return refs;
|
|
25718
|
-
}
|
|
25719
|
-
if (Array.isArray(value)) {
|
|
25720
|
-
for (let v of value) push_one(v);
|
|
25721
|
-
return refs;
|
|
25722
|
-
}
|
|
25723
|
-
if (typeof value === "object") for (let [key, v] of Object.entries(value)) if (v && typeof v === "object" && typeof v.id === "string") push_one(v);
|
|
25724
|
-
else push_one(key);
|
|
25725
|
-
return refs;
|
|
25726
|
-
}
|
|
25727
|
-
/***************************************************************
|
|
25728
|
-
* The id of the FIRST parent a record names, or "" when it
|
|
25729
|
-
* names none. A record has one parent here — a column belongs to
|
|
25730
|
-
* one topic, a topic to one treedb — and a second ref would be a
|
|
25731
|
-
* store this editor cannot draw anyway.
|
|
25732
|
-
***************************************************************/
|
|
25733
|
-
function parent_id(record, fkey_col) {
|
|
25734
|
-
let refs = parse_fkey_ref(record ? record[fkey_col] : null);
|
|
25735
|
-
return refs.length > 0 ? refs[0].id : "";
|
|
25736
|
-
}
|
|
25737
|
-
/***************************************************************
|
|
25738
|
-
* The name a record is KNOWN by, which is not what it is keyed
|
|
25739
|
-
* by: `topics` and `cols` key by the qualified id and carry the
|
|
25740
|
-
* bare name in `value` (its pkey2). An older store that still
|
|
25741
|
-
* keyed by rowid has no `value` worth showing, so the id stands
|
|
25742
|
-
* in — the same fallback as node_label().
|
|
25743
|
-
***************************************************************/
|
|
25744
|
-
function record_name(record) {
|
|
25745
|
-
if (!record) return "";
|
|
25746
|
-
if (typeof record.value === "string" && record.value.length > 0) return record.value;
|
|
25747
|
-
return typeof record.id === "string" ? record.id : "";
|
|
25748
|
-
}
|
|
25749
|
-
/***************************************************************
|
|
25750
|
-
* The `order` of a record as a NUMBER, whatever the store put
|
|
25751
|
-
* there: an integer column read back from JSON may arrive as a
|
|
25752
|
-
* string, and comparing "10" with 9 sorts the schema wrong.
|
|
25753
|
-
***************************************************************/
|
|
25754
|
-
function record_order(record) {
|
|
25755
|
-
let order = record ? record.order : void 0;
|
|
25756
|
-
if (typeof order === "number" && isFinite(order)) return order;
|
|
25757
|
-
if (typeof order === "string" && order.trim().length > 0) {
|
|
25758
|
-
let n = Number(order);
|
|
25759
|
-
if (isFinite(n)) return n;
|
|
25760
|
-
}
|
|
25761
|
-
return DEFAULT_ORDER;
|
|
25762
|
-
}
|
|
25763
|
-
/***************************************************************
|
|
25764
|
-
* Sort in place by `order`, ties broken by name so a schema
|
|
25765
|
-
* whose records all default to 9999 still draws the same way
|
|
25766
|
-
* twice.
|
|
25767
|
-
***************************************************************/
|
|
25768
|
-
function sort_by_order(list) {
|
|
25769
|
-
list.sort((a, b) => {
|
|
25770
|
-
if (a.order !== b.order) return a.order - b.order;
|
|
25771
|
-
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
25772
|
-
});
|
|
25773
|
-
return list;
|
|
25774
|
-
}
|
|
25775
|
-
/***************************************************************
|
|
25776
|
-
* build_schema_model({treedbs, topics, cols}) -> model
|
|
25777
|
-
*
|
|
25778
|
-
* model = {
|
|
25779
|
-
* treedbs: [{
|
|
25780
|
-
* id, name, record,
|
|
25781
|
-
* schema_version, c_schema_version, system_schema_version,
|
|
25782
|
-
* topics: [{
|
|
25783
|
-
* id, name, order, record,
|
|
25784
|
-
* pkey, topic_version, system_topic, main_topic,
|
|
25785
|
-
* cols: [{id, name, order, record}]
|
|
25786
|
-
* }]
|
|
25787
|
-
* }],
|
|
25788
|
-
* orphan_topics: [...], topics whose treedb is not in the store
|
|
25789
|
-
* orphan_cols: [...] columns whose topic is not in the store
|
|
25790
|
-
* }
|
|
25791
|
-
*
|
|
25792
|
-
* An orphan is NOT dropped. A column whose topic was deleted is
|
|
25793
|
-
* exactly the kind of leftover an operator opens this editor to
|
|
25794
|
-
* find, and a model that hides it makes the editor lie.
|
|
25795
|
-
***************************************************************/
|
|
25796
|
-
function build_schema_model(records) {
|
|
25797
|
-
let r = records || {};
|
|
25798
|
-
let treedb_rows = Array.isArray(r.treedbs) ? r.treedbs : [];
|
|
25799
|
-
let topic_rows = Array.isArray(r.topics) ? r.topics : [];
|
|
25800
|
-
let col_rows = Array.isArray(r.cols) ? r.cols : [];
|
|
25801
|
-
let treedbs = [];
|
|
25802
|
-
let by_treedb_id = {};
|
|
25803
|
-
for (let record of treedb_rows) {
|
|
25804
|
-
if (!record || typeof record.id !== "string") continue;
|
|
25805
|
-
let entry = {
|
|
25806
|
-
id: record.id,
|
|
25807
|
-
name: record.id,
|
|
25808
|
-
record,
|
|
25809
|
-
schema_version: record.schema_version,
|
|
25810
|
-
c_schema_version: record.c_schema_version,
|
|
25811
|
-
system_schema_version: record.system_schema_version,
|
|
25812
|
-
topics: []
|
|
25813
|
-
};
|
|
25814
|
-
treedbs.push(entry);
|
|
25815
|
-
by_treedb_id[entry.id] = entry;
|
|
25816
|
-
}
|
|
25817
|
-
let orphan_topics = [];
|
|
25818
|
-
let by_topic_id = {};
|
|
25819
|
-
for (let record of topic_rows) {
|
|
25820
|
-
if (!record || typeof record.id !== "string") continue;
|
|
25821
|
-
let entry = {
|
|
25822
|
-
id: record.id,
|
|
25823
|
-
name: record_name(record),
|
|
25824
|
-
order: record_order(record),
|
|
25825
|
-
record,
|
|
25826
|
-
treedb_id: parent_id(record, "treedbs"),
|
|
25827
|
-
pkey: record.pkey || "",
|
|
25828
|
-
pkey2s: record.pkey2s,
|
|
25829
|
-
system_flag: record.system_flag || "",
|
|
25830
|
-
tkey: record.tkey || "",
|
|
25831
|
-
topic_version: record.topic_version,
|
|
25832
|
-
system_topic: !!record.system_topic,
|
|
25833
|
-
main_topic: !!record.main_topic,
|
|
25834
|
-
cols: []
|
|
25835
|
-
};
|
|
25836
|
-
by_topic_id[entry.id] = entry;
|
|
25837
|
-
let parent = by_treedb_id[entry.treedb_id];
|
|
25838
|
-
if (parent) parent.topics.push(entry);
|
|
25839
|
-
else orphan_topics.push(entry);
|
|
25840
|
-
}
|
|
25841
|
-
let orphan_cols = [];
|
|
25842
|
-
for (let record of col_rows) {
|
|
25843
|
-
if (!record || typeof record.id !== "string") continue;
|
|
25844
|
-
let entry = {
|
|
25845
|
-
id: record.id,
|
|
25846
|
-
name: record_name(record),
|
|
25847
|
-
order: record_order(record),
|
|
25848
|
-
record,
|
|
25849
|
-
topic_id: parent_id(record, "topics")
|
|
25850
|
-
};
|
|
25851
|
-
let parent = by_topic_id[entry.topic_id];
|
|
25852
|
-
if (parent) parent.cols.push(entry);
|
|
25853
|
-
else orphan_cols.push(entry);
|
|
25854
|
-
}
|
|
25855
|
-
for (let treedb of treedbs) {
|
|
25856
|
-
sort_by_order(treedb.topics);
|
|
25857
|
-
for (let topic of treedb.topics) sort_by_order(topic.cols);
|
|
25858
|
-
}
|
|
25859
|
-
for (let topic of orphan_topics) sort_by_order(topic.cols);
|
|
25860
|
-
treedbs.sort((a, b) => {
|
|
25861
|
-
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
25862
|
-
});
|
|
25863
|
-
sort_by_order(orphan_topics);
|
|
25864
|
-
sort_by_order(orphan_cols);
|
|
25865
|
-
return {
|
|
25866
|
-
treedbs,
|
|
25867
|
-
orphan_topics,
|
|
25868
|
-
orphan_cols
|
|
25869
|
-
};
|
|
25870
|
-
}
|
|
25871
|
-
/***************************************************************
|
|
25872
|
-
* Is there a value here at all?
|
|
25873
|
-
*
|
|
25874
|
-
* The store answers a `blob` column that was never set with an
|
|
25875
|
-
* EMPTY COLLECTION, not with nothing: `enum: {}`, `hook: {}`,
|
|
25876
|
-
* `default: {}`. Read as "a value", those turn every export into
|
|
25877
|
-
* a schema full of empty objects — and `'hook': {}` in a literal
|
|
25878
|
-
* is a hook with no mapping, which is a link the treedb builds
|
|
25879
|
-
* and nothing writes.
|
|
25880
|
-
***************************************************************/
|
|
25881
|
-
function is_empty_value(value) {
|
|
25882
|
-
if (value === null || value === void 0 || value === "") return true;
|
|
25883
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
25884
|
-
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
25885
|
-
return false;
|
|
25886
|
-
}
|
|
25887
|
-
/***************************************************************
|
|
25888
|
-
* The fields of a column that are DECLARED as one thing and
|
|
25889
|
-
* STORED as another.
|
|
25890
|
-
*
|
|
25891
|
-
* `hook`, `enum`, `default`, `pkey2s` and `properties` are `blob`
|
|
25892
|
-
* columns of the `cols` topic (treedb_system_schema.c), so what
|
|
25893
|
-
* comes back may be the value or the JSON text of the value,
|
|
25894
|
-
* depending on how it was written — a projection writes the
|
|
25895
|
-
* value, a hand edit through a plain text field writes the text.
|
|
25896
|
-
* `flag` is an array that a single-flag edit can leave as a bare
|
|
25897
|
-
* string. Reading these without saying so is how a hook drawn
|
|
25898
|
-
* from `{"users":"department"}` becomes no hook at all.
|
|
25899
|
-
***************************************************************/
|
|
25900
|
-
function as_json(value) {
|
|
25901
|
-
if (typeof value !== "string") return value;
|
|
25902
|
-
let text = value.trim();
|
|
25903
|
-
if (text.length === 0) return null;
|
|
25904
|
-
try {
|
|
25905
|
-
return JSON.parse(text);
|
|
25906
|
-
} catch (e) {
|
|
25907
|
-
return value;
|
|
25908
|
-
}
|
|
25909
|
-
}
|
|
25910
|
-
function col_flags(record) {
|
|
25911
|
-
let flag = record ? record.flag : null;
|
|
25912
|
-
if (Array.isArray(flag)) return flag.filter((f) => typeof f === "string" && f.length > 0);
|
|
25913
|
-
if (typeof flag === "string" && flag.length > 0) {
|
|
25914
|
-
let parsed = as_json(flag);
|
|
25915
|
-
if (Array.isArray(parsed)) return parsed.filter((f) => typeof f === "string" && f.length > 0);
|
|
25916
|
-
return [flag];
|
|
25917
|
-
}
|
|
25918
|
-
return [];
|
|
25919
|
-
}
|
|
25920
|
-
function col_hook(record) {
|
|
25921
|
-
let hook = as_json(record ? record.hook : null);
|
|
25922
|
-
if (hook && typeof hook === "object" && !Array.isArray(hook)) return hook;
|
|
25923
|
-
return null;
|
|
25924
|
-
}
|
|
25925
|
-
function col_enum(record) {
|
|
25926
|
-
let e = as_json(record ? record.enum : null);
|
|
25927
|
-
if (Array.isArray(e)) return e;
|
|
25928
|
-
return [];
|
|
25929
|
-
}
|
|
25930
|
-
function topic_pkey2s(record) {
|
|
25931
|
-
let pkey2s = as_json(record ? record.pkey2s : null);
|
|
25932
|
-
if (Array.isArray(pkey2s)) return pkey2s.filter((k) => typeof k === "string" && k.length > 0);
|
|
25933
|
-
if (typeof pkey2s === "string" && pkey2s.length > 0) return [pkey2s];
|
|
25934
|
-
return [];
|
|
25935
|
-
}
|
|
25936
|
-
/***************************************************************
|
|
25937
|
-
* Lookups by id. The editor addresses a position by NAME (the
|
|
25938
|
-
* url carries `<treedb>/<topic>`), so both are offered.
|
|
25939
|
-
***************************************************************/
|
|
25940
|
-
function find_treedb(model, treedb_id) {
|
|
25941
|
-
if (!model || !Array.isArray(model.treedbs)) return null;
|
|
25942
|
-
for (let treedb of model.treedbs) if (treedb.id === treedb_id) return treedb;
|
|
25943
|
-
return null;
|
|
25944
|
-
}
|
|
25945
|
-
function find_topic(model, treedb_id, topic_name) {
|
|
25946
|
-
let treedb = find_treedb(model, treedb_id);
|
|
25947
|
-
if (!treedb) return null;
|
|
25948
|
-
for (let topic of treedb.topics) if (topic.name === topic_name || topic.id === topic_name) return topic;
|
|
25949
|
-
return null;
|
|
25950
|
-
}
|
|
25951
|
-
function find_col(model, treedb_id, topic_name, col_name) {
|
|
25952
|
-
let topic = find_topic(model, treedb_id, topic_name);
|
|
25953
|
-
if (!topic) return null;
|
|
25954
|
-
for (let col of topic.cols) if (col.name === col_name || col.id === col_name) return col;
|
|
25955
|
-
return null;
|
|
25956
|
-
}
|
|
25957
|
-
/***************************************************************
|
|
25958
|
-
* The fkey a NEW record must carry to belong to `parent_id`.
|
|
25959
|
-
* Written here because the editor is the only writer that has to
|
|
25960
|
-
* compose one, and getting the hook name wrong links the record
|
|
25961
|
-
* to nothing while the write still succeeds.
|
|
25962
|
-
***************************************************************/
|
|
25963
|
-
function fkey_ref(parent_topic, parent_id_, hook_name) {
|
|
25964
|
-
return `${parent_topic}^${parent_id_}^${hook_name}`;
|
|
25965
|
-
}
|
|
25966
|
-
/***************************************************************
|
|
25967
|
-
* Where a new sibling goes: after the last one. The store's own
|
|
25968
|
-
* default (9999) would put every hand-made column in the same
|
|
25969
|
-
* place and let their names decide the schema's order.
|
|
25970
|
-
***************************************************************/
|
|
25971
|
-
function next_order(siblings) {
|
|
25972
|
-
let max = 0;
|
|
25973
|
-
if (Array.isArray(siblings)) for (let s of siblings) {
|
|
25974
|
-
let order = s && typeof s.order === "number" ? s.order : DEFAULT_ORDER;
|
|
25975
|
-
if (order < 9999 && order > max) max = order;
|
|
25976
|
-
}
|
|
25977
|
-
return max + 1;
|
|
25978
|
-
}
|
|
25979
|
-
/***************************************************************
|
|
25980
|
-
* Renumber a list AFTER a move, as the writes it takes: only the
|
|
25981
|
-
* records whose order actually changed, so a drag of one row in a
|
|
25982
|
-
* 40-column topic is not 40 writes.
|
|
25983
|
-
*
|
|
25984
|
-
* moved_orders(list) -> [{id, order}, ...]
|
|
25985
|
-
***************************************************************/
|
|
25986
|
-
function moved_orders(list) {
|
|
25987
|
-
let writes = [];
|
|
25988
|
-
if (!Array.isArray(list)) return writes;
|
|
25989
|
-
for (let i = 0; i < list.length; i++) {
|
|
25990
|
-
let entry = list[i];
|
|
25991
|
-
let order = i + 1;
|
|
25992
|
-
if (!entry || typeof entry.id !== "string") continue;
|
|
25993
|
-
if (entry.order !== order) writes.push({
|
|
25994
|
-
id: entry.id,
|
|
25995
|
-
order
|
|
25996
|
-
});
|
|
25997
|
-
}
|
|
25998
|
-
return writes;
|
|
25999
|
-
}
|
|
26000
|
-
//#endregion
|
|
26001
26138
|
//#region src/treedb_write_plan.js
|
|
26002
26139
|
/***********************************************************************
|
|
26003
26140
|
* treedb_write_plan.js
|
|
@@ -68843,12 +68980,20 @@ function hook_mark(type) {
|
|
|
68843
68980
|
* (↖) 1 fkey (1 parent)
|
|
68844
68981
|
* [↖] n fkeys (n parents)
|
|
68845
68982
|
* {↖} N fkeys (N parents)
|
|
68983
|
+
* (2) a secondary key (pkey2)
|
|
68984
|
+
* (t) the time key (tkey)
|
|
68846
68985
|
* * required
|
|
68847
68986
|
* # the primary key
|
|
68848
68987
|
*
|
|
68849
|
-
*
|
|
68850
|
-
*
|
|
68851
|
-
*
|
|
68988
|
+
* The key marks lead the mark column, and a pkey2 is drawn in
|
|
68989
|
+
* bold like the pkey: a topic with secondary keys keeps several
|
|
68990
|
+
* instances under one id, which is the first thing to know
|
|
68991
|
+
* about it. `(t)` is new to the notation: the literals' legend
|
|
68992
|
+
* carries it too.
|
|
68993
|
+
*
|
|
68994
|
+
* The flags are read here rather than through
|
|
68995
|
+
* treedb_get_field_desc's single `type`, which keeps only the
|
|
68996
|
+
* last flag it saw.
|
|
68852
68997
|
************************************************************/
|
|
68853
68998
|
function schema_rows(desc) {
|
|
68854
68999
|
let rows = [];
|
|
@@ -68858,19 +69003,25 @@ function schema_rows(desc) {
|
|
|
68858
69003
|
let flags = Array.isArray(col.flag) ? col.flag : [];
|
|
68859
69004
|
let is_hook = flags.indexOf("hook") >= 0;
|
|
68860
69005
|
let is_fkey = flags.indexOf("fkey") >= 0;
|
|
69006
|
+
let roles = col_key_roles(desc, col.id);
|
|
69007
|
+
let key_marks = [];
|
|
69008
|
+
if (roles.includes("pkey2")) key_marks.push("(2)");
|
|
69009
|
+
if (roles.includes("tkey")) key_marks.push("(t)");
|
|
68861
69010
|
let mark = "";
|
|
68862
69011
|
if (is_hook) mark = hook_mark(col.type);
|
|
68863
69012
|
if (is_fkey) {
|
|
68864
69013
|
let fmark = hook_mark(col.type).replace("}", "↖}").replace("]", "↖]").replace(")", "↖)");
|
|
68865
69014
|
mark = mark ? mark + " " + fmark : fmark;
|
|
68866
69015
|
}
|
|
69016
|
+
if (key_marks.length) mark = mark ? key_marks.join(" ") + " " + mark : key_marks.join(" ");
|
|
68867
69017
|
rows.push({
|
|
68868
69018
|
name: col.id,
|
|
68869
69019
|
type: col.type || "",
|
|
68870
69020
|
mark,
|
|
68871
69021
|
is_hook,
|
|
68872
69022
|
is_fkey,
|
|
68873
|
-
is_pkey:
|
|
69023
|
+
is_pkey: roles.includes("pkey"),
|
|
69024
|
+
is_pkey2: roles.includes("pkey2"),
|
|
68874
69025
|
required: flags.indexOf("required") >= 0 || flags.indexOf("notnull") >= 0
|
|
68875
69026
|
});
|
|
68876
69027
|
}
|
|
@@ -68917,7 +69068,7 @@ function build_card_innerHTML(topic, rows, color, dark) {
|
|
|
68917
69068
|
let rows_html = "";
|
|
68918
69069
|
for (let row of rows) {
|
|
68919
69070
|
let lead = row.is_pkey ? "#" : row.required ? "*" : "";
|
|
68920
|
-
let name_weight = row.is_pkey || row.required ? "600" : "400";
|
|
69071
|
+
let name_weight = row.is_pkey || row.is_pkey2 ? "700" : row.required ? "600" : "400";
|
|
68921
69072
|
let name_color = row.is_hook || row.is_fkey ? title_color : text_color;
|
|
68922
69073
|
rows_html += ` <div class="TREEDB_SCHEMA_FIELD" style="
|
|
68923
69074
|
display: flex; align-items: center; gap: 6px;
|
|
@@ -76005,86 +76156,6 @@ function register_c_yui_period() {
|
|
|
76005
76156
|
return create_gclass(GCLASS_NAME);
|
|
76006
76157
|
}
|
|
76007
76158
|
//#endregion
|
|
76008
|
-
//#region src/dev_machine_trace.js
|
|
76009
|
-
/***********************************************************************
|
|
76010
|
-
* dev_machine_trace.js
|
|
76011
|
-
*
|
|
76012
|
-
* Reading a MACHINE trace line back.
|
|
76013
|
-
*
|
|
76014
|
-
* The developer window mirrors the runtime's log, and the
|
|
76015
|
-
* `machine` trace is most of what lands there once it is on.
|
|
76016
|
-
* Those lines arrive as text, so to the window they were just
|
|
76017
|
-
* "a debug log" -- which is why its `Periodic` filter could
|
|
76018
|
-
* not touch them: the filter works on a signature, and every
|
|
76019
|
-
* mirrored log carried the same one (`log:debug`).
|
|
76020
|
-
*
|
|
76021
|
-
* This gives a machine line back its EVENT, which is the only
|
|
76022
|
-
* thing that says whether it is noise. Both formats gobj-js
|
|
76023
|
-
* emits (`gobj_set_trace_machine_format`):
|
|
76024
|
-
*
|
|
76025
|
-
* 0 verbose "🔄 mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ac: …"
|
|
76026
|
-
* "<- mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ret: 0"
|
|
76027
|
-
* 1 compact "🔄 EV_TIMEOUT C_TIMER^t ST_IDLE from C_TIMER^t"
|
|
76028
|
-
*
|
|
76029
|
-
* Copyright (c) 2026, ArtGins.
|
|
76030
|
-
* All Rights Reserved.
|
|
76031
|
-
***********************************************************************/
|
|
76032
|
-
var MACHINE_MARK_RE = /\bmach\(/;
|
|
76033
|
-
var EVENT_FIELD_RE = /\bev:\s*([A-Za-z0-9_]+)/;
|
|
76034
|
-
var EVENT_HEAD_RE = /^\s*\S{0,4}\s*(EV_[A-Za-z0-9_]+)(?=\s|$)/;
|
|
76035
|
-
var PERIODIC_EVENT_RE = /PERIODIC|TIMEOUT|HEARTBEAT|PING|POLL/i;
|
|
76036
|
-
/************************************************************
|
|
76037
|
-
* The event of a machine trace line, or "" when the line is
|
|
76038
|
-
* not one.
|
|
76039
|
-
*
|
|
76040
|
-
* "" is also the answer for a machine line that carries no
|
|
76041
|
-
* event -- a state change ("new st(…), prev st(…)") -- and
|
|
76042
|
-
* that is right: what it reports is not repetitive.
|
|
76043
|
-
************************************************************/
|
|
76044
|
-
function machine_event_of(text) {
|
|
76045
|
-
if (typeof text !== "string" || text.length === 0) return "";
|
|
76046
|
-
if (MACHINE_MARK_RE.test(text)) {
|
|
76047
|
-
let m = EVENT_FIELD_RE.exec(text);
|
|
76048
|
-
return m ? m[1] : "";
|
|
76049
|
-
}
|
|
76050
|
-
let m = EVENT_HEAD_RE.exec(text);
|
|
76051
|
-
return m ? m[1] : "";
|
|
76052
|
-
}
|
|
76053
|
-
/************************************************************
|
|
76054
|
-
* Is this event one of the ones that arrive by themselves,
|
|
76055
|
-
* for ever, and say nothing about what the app is doing?
|
|
76056
|
-
************************************************************/
|
|
76057
|
-
function is_periodic_event(event_name) {
|
|
76058
|
-
if (!event_name) return false;
|
|
76059
|
-
return PERIODIC_EVENT_RE.test(event_name);
|
|
76060
|
-
}
|
|
76061
|
-
/************************************************************
|
|
76062
|
-
* The signature of a mirrored log line: what the window
|
|
76063
|
-
* counts it under and what its filters match on.
|
|
76064
|
-
*
|
|
76065
|
-
* A machine line is signed by its EVENT, so a hundred
|
|
76066
|
-
* EV_TIMEOUTs are one recurring thing rather than a hundred
|
|
76067
|
-
* anonymous debug lines. Everything else is signed by its
|
|
76068
|
-
* level, as before.
|
|
76069
|
-
************************************************************/
|
|
76070
|
-
function log_signature(level, text) {
|
|
76071
|
-
let event = machine_event_of(text);
|
|
76072
|
-
if (event) return "mach:" + event;
|
|
76073
|
-
return "log:" + (level || "debug");
|
|
76074
|
-
}
|
|
76075
|
-
/************************************************************
|
|
76076
|
-
* May the periodic filter hide this log line?
|
|
76077
|
-
*
|
|
76078
|
-
* Only a machine transition, and only below warning level.
|
|
76079
|
-
* An ERROR that names EV_TIMEOUT -- "Event NOT DEFINED in
|
|
76080
|
-
* state", which is exactly the loud one the framework wants
|
|
76081
|
-
* seen -- must never disappear because of the word in it.
|
|
76082
|
-
************************************************************/
|
|
76083
|
-
function log_is_periodic(level, text) {
|
|
76084
|
-
if (level === "error" || level === "warning") return false;
|
|
76085
|
-
return is_periodic_event(machine_event_of(text));
|
|
76086
|
-
}
|
|
76087
|
-
//#endregion
|
|
76088
76159
|
//#region src/yui_dev.js
|
|
76089
76160
|
/***********************************************************************
|
|
76090
76161
|
* ui_dev.js
|
|
@@ -76102,10 +76173,7 @@ function log_is_periodic(level, text) {
|
|
|
76102
76173
|
* losing history. Reopening the window repaints the buffer.
|
|
76103
76174
|
***********************************************************************/
|
|
76104
76175
|
var TRAFFIC_MAX = 600;
|
|
76105
|
-
var PERIODIC_THRESHOLD = 5;
|
|
76106
|
-
var PERIODIC_RE = /PERIODIC|TIMEOUT|HEARTBEAT|PING/i;
|
|
76107
76176
|
var TRAFFIC_LOG = [];
|
|
76108
|
-
var TRAFFIC_COUNTS = /* @__PURE__ */ new Map();
|
|
76109
76177
|
var SEARCH_TEXT = "";
|
|
76110
76178
|
var LOG_ERR_COUNT = 0;
|
|
76111
76179
|
var LOG_WARN_COUNT = 0;
|
|
@@ -76122,39 +76190,53 @@ var TRAFFIC_TS_FIELDS = {
|
|
|
76122
76190
|
};
|
|
76123
76191
|
var TRACE_DEFS = [
|
|
76124
76192
|
[
|
|
76125
|
-
"trace_automata",
|
|
76126
76193
|
"automata",
|
|
76127
|
-
|
|
76194
|
+
"automata",
|
|
76195
|
+
"trace every event of every automaton",
|
|
76196
|
+
automata_state,
|
|
76197
|
+
toggle_automata
|
|
76128
76198
|
],
|
|
76129
76199
|
[
|
|
76130
|
-
"trace_creation",
|
|
76131
76200
|
"creation",
|
|
76132
|
-
|
|
76201
|
+
"creation",
|
|
76202
|
+
"trace the creation and destruction of gobjs",
|
|
76203
|
+
() => global_bit(_yuneta_gobj_js.trace_level_t.TRACE_CREATE_DELETE),
|
|
76204
|
+
() => toggle_global("create_delete")
|
|
76133
76205
|
],
|
|
76134
76206
|
[
|
|
76135
|
-
"
|
|
76207
|
+
"start_stop",
|
|
76136
76208
|
"start / stop",
|
|
76137
|
-
|
|
76209
|
+
"trace the start and stop of gobjs",
|
|
76210
|
+
() => global_bit(_yuneta_gobj_js.trace_level_t.TRACE_START_STOP),
|
|
76211
|
+
() => toggle_global("start_stop")
|
|
76138
76212
|
],
|
|
76139
76213
|
[
|
|
76140
|
-
"trace_subscriptions",
|
|
76141
76214
|
"subscriptions",
|
|
76142
|
-
|
|
76215
|
+
"subscriptions",
|
|
76216
|
+
"trace subscriptions and publications",
|
|
76217
|
+
() => global_bit(_yuneta_gobj_js.trace_level_t.TRACE_SUBSCRIPTIONS),
|
|
76218
|
+
() => toggle_global("subscriptions")
|
|
76143
76219
|
],
|
|
76144
76220
|
[
|
|
76145
|
-
"trace_i18n",
|
|
76146
76221
|
"i18n",
|
|
76147
|
-
|
|
76222
|
+
"i18n",
|
|
76223
|
+
"i18next debug output",
|
|
76224
|
+
i18n_state,
|
|
76225
|
+
toggle_i18n
|
|
76148
76226
|
],
|
|
76149
76227
|
[
|
|
76150
|
-
"trace_traffic",
|
|
76151
76228
|
"traffic",
|
|
76152
|
-
|
|
76229
|
+
"traffic",
|
|
76230
|
+
"trace the messages to and from the backend",
|
|
76231
|
+
traffic_state,
|
|
76232
|
+
toggle_traffic
|
|
76153
76233
|
],
|
|
76154
76234
|
[
|
|
76155
|
-
"
|
|
76156
|
-
"
|
|
76157
|
-
|
|
76235
|
+
"periodic",
|
|
76236
|
+
"periodic",
|
|
76237
|
+
"trace the periodic timer event",
|
|
76238
|
+
periodic_state,
|
|
76239
|
+
toggle_periodic
|
|
76158
76240
|
]
|
|
76159
76241
|
];
|
|
76160
76242
|
/******************************
|
|
@@ -76221,45 +76303,24 @@ function dev_view() {
|
|
|
76221
76303
|
let v = (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_view_mode", "detailed", false);
|
|
76222
76304
|
return v === "compact" || v === "name" || v === "full" ? v : "detailed";
|
|
76223
76305
|
}
|
|
76224
|
-
var HIDE_PERIODIC_DEFAULT = 1;
|
|
76225
76306
|
var SIMPLE_MACH_DEFAULT = 1;
|
|
76226
76307
|
var SIMPLE_MACH_KEY = "dev_mach_simple";
|
|
76227
76308
|
function dev_simple_mach() {
|
|
76228
76309
|
return dev_num(SIMPLE_MACH_KEY, SIMPLE_MACH_DEFAULT) ? 1 : 0;
|
|
76229
76310
|
}
|
|
76230
|
-
function dev_hide_periodic() {
|
|
76231
|
-
return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
|
|
76232
|
-
}
|
|
76233
76311
|
function dev_route() {
|
|
76234
76312
|
let v = (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_output_route", "both", false);
|
|
76235
76313
|
return v === "window" || v === "console" ? v : "both";
|
|
76236
76314
|
}
|
|
76237
76315
|
function apply_console_route() {
|
|
76238
76316
|
(0, _yuneta_gobj_js.set_console_log_enabled)(dev_route() !== "window");
|
|
76239
|
-
if (typeof _yuneta_gobj_js.set_console_log_filter === "function") _yuneta_gobj_js.set_console_log_filter((level, msg) => {
|
|
76240
|
-
if (!dev_hide_periodic()) return true;
|
|
76241
|
-
return !log_is_periodic(level, (0, _yuneta_gobj_js.is_string)(msg) ? msg : String(msg));
|
|
76242
|
-
});
|
|
76243
|
-
else if (!__console_filter_warned__) {
|
|
76244
|
-
__console_filter_warned__ = true;
|
|
76245
|
-
console.warn("yui_dev: gobj-js has no set_console_log_filter (needs >= 7.13.6): the Periodic filter applies to this window only, not to the console");
|
|
76246
|
-
}
|
|
76247
76317
|
}
|
|
76248
|
-
var __console_filter_warned__ = false;
|
|
76249
76318
|
function console_traffic(title, jn, direction, size) {
|
|
76250
76319
|
let event = jn && jn.event ? String(jn.event) : "(no event)";
|
|
76251
76320
|
let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : jn;
|
|
76252
76321
|
let color = direction === 2 ? "#16a34a" : direction === 3 ? "#dc2626" : "#2563eb";
|
|
76253
76322
|
window.console.log("%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event + (size ? " (" + size + "b)" : ""), "color:" + color, kw);
|
|
76254
76323
|
}
|
|
76255
|
-
function dev_muted() {
|
|
76256
|
-
let a = (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_muted_events", [], false);
|
|
76257
|
-
if (!Array.isArray(a)) a = [];
|
|
76258
|
-
return new Set(a);
|
|
76259
|
-
}
|
|
76260
|
-
function dev_set_muted(set) {
|
|
76261
|
-
(0, _yuneta_gobj_js.kw_set_local_storage_value)("dev_muted_events", Array.from(set));
|
|
76262
|
-
}
|
|
76263
76324
|
function set_view(v) {
|
|
76264
76325
|
(0, _yuneta_gobj_js.kw_set_local_storage_value)("dev_view_mode", v);
|
|
76265
76326
|
rerender_all();
|
|
@@ -76275,54 +76336,25 @@ function set_output_route(v) {
|
|
|
76275
76336
|
function toggle_pref(key, def) {
|
|
76276
76337
|
let v = dev_num(key, def) ? 0 : 1;
|
|
76277
76338
|
(0, _yuneta_gobj_js.kw_set_local_storage_value)(key, v);
|
|
76278
|
-
apply_console_route();
|
|
76279
|
-
rerender_all();
|
|
76280
|
-
refresh_dev_chrome();
|
|
76281
|
-
}
|
|
76282
|
-
function mute_signature(sig) {
|
|
76283
|
-
let set = dev_muted();
|
|
76284
|
-
set.add(sig);
|
|
76285
|
-
dev_set_muted(set);
|
|
76286
|
-
rerender_all();
|
|
76287
|
-
refresh_dev_chrome();
|
|
76288
|
-
}
|
|
76289
|
-
function unmute_signature(sig) {
|
|
76290
|
-
let set = dev_muted();
|
|
76291
|
-
set.delete(sig);
|
|
76292
|
-
dev_set_muted(set);
|
|
76293
76339
|
rerender_all();
|
|
76294
76340
|
refresh_dev_chrome();
|
|
76295
76341
|
}
|
|
76296
76342
|
/******************************
|
|
76297
76343
|
* Filtering
|
|
76298
76344
|
******************************/
|
|
76299
|
-
function traffic_signature(event, command) {
|
|
76300
|
-
return command ? event + " · " + command : event;
|
|
76301
|
-
}
|
|
76302
|
-
function traffic_is_periodic(sig) {
|
|
76303
|
-
if (PERIODIC_RE.test(sig)) return true;
|
|
76304
|
-
return (TRAFFIC_COUNTS.get(sig) || 0) >= PERIODIC_THRESHOLD;
|
|
76305
|
-
}
|
|
76306
76345
|
function build_filter_ctx() {
|
|
76307
76346
|
return {
|
|
76308
76347
|
out: dev_num("dev_filter_out", 1),
|
|
76309
76348
|
inc: dev_num("dev_filter_in", 1),
|
|
76310
76349
|
err: dev_num("dev_filter_err", 1),
|
|
76311
|
-
muted: dev_muted(),
|
|
76312
|
-
hide_periodic: dev_hide_periodic(),
|
|
76313
76350
|
search: SEARCH_TEXT
|
|
76314
76351
|
};
|
|
76315
76352
|
}
|
|
76316
76353
|
function entry_hidden(e, ctx) {
|
|
76317
|
-
if (e.kind === "log")
|
|
76318
|
-
if (ctx.hide_periodic && e.periodic) return true;
|
|
76319
|
-
return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
|
|
76320
|
-
}
|
|
76354
|
+
if (e.kind === "log") return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
|
|
76321
76355
|
if (e.dir === 1 && !ctx.out) return true;
|
|
76322
76356
|
if (e.dir === 2 && !ctx.inc) return true;
|
|
76323
76357
|
if (e.dir === 3 && !ctx.err) return true;
|
|
76324
|
-
if (ctx.muted.has(e.sig)) return true;
|
|
76325
|
-
if (ctx.hide_periodic && traffic_is_periodic(e.sig)) return true;
|
|
76326
76358
|
if (ctx.search && e.hay.indexOf(ctx.search) < 0) return true;
|
|
76327
76359
|
return false;
|
|
76328
76360
|
}
|
|
@@ -76346,11 +76378,6 @@ function ensure_dev_style() {
|
|
|
76346
76378
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
76347
76379
|
}
|
|
76348
76380
|
.YDEV_LOG { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px 10px; }
|
|
76349
|
-
.YDEV_MUTED {
|
|
76350
|
-
display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
|
|
76351
|
-
padding: 4px 10px; border-bottom: 1px solid rgba(0,0,0,0.08); font-size: 12px;
|
|
76352
|
-
}
|
|
76353
|
-
.YDEV_MUTED:empty { display: none; }
|
|
76354
76381
|
.YDEV_STATS {
|
|
76355
76382
|
flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 14px;
|
|
76356
76383
|
padding: 6px 10px; border-top: 1px solid rgba(0,0,0,0.1);
|
|
@@ -76382,7 +76409,6 @@ function ensure_dev_style() {
|
|
|
76382
76409
|
.YDEV_CHIP.s-in.is-active { background: rgba(5,150,105,0.16); border-color: #059669; color: #059669; }
|
|
76383
76410
|
.YDEV_CHIP.s-err.is-active { background: rgba(220,38,38,0.16); border-color: #dc2626; color: #dc2626; }
|
|
76384
76411
|
.YDEV_CHIP[data-dir]:not(.is-active) { opacity: 0.4; text-decoration: line-through; }
|
|
76385
|
-
.YDEV_CHIP[data-toggle="periodic"].is-active { background: rgba(217,119,6,0.16); border-color: #d97706; color: #b45309; font-weight: 600; }
|
|
76386
76412
|
.YDEV_SEG { display: inline-flex; border: 1px solid rgba(0,0,0,0.18); border-radius: 7px; overflow: hidden; }
|
|
76387
76413
|
.YDEV_SEG_BTN {
|
|
76388
76414
|
font: inherit; font-size: 12px; padding: 4px 10px; border: 0;
|
|
@@ -76396,12 +76422,6 @@ function ensure_dev_style() {
|
|
|
76396
76422
|
border: 1px solid rgba(0,0,0,0.18); border-radius: 7px;
|
|
76397
76423
|
background: transparent; color: inherit;
|
|
76398
76424
|
}
|
|
76399
|
-
.YDEV_MUTED_CHIP {
|
|
76400
|
-
font: inherit; font-family: "DejaVu Sans Mono", monospace; font-size: 12px;
|
|
76401
|
-
display: inline-flex; align-items: center; gap: 6px; padding: 2px 8px;
|
|
76402
|
-
border: 1px solid rgba(217,119,6,0.5); border-radius: 999px;
|
|
76403
|
-
background: rgba(217,119,6,0.12); color: #b45309; cursor: pointer;
|
|
76404
|
-
}
|
|
76405
76425
|
.YDEV_STAT.s-out { color: #2563eb; } .YDEV_STAT.s-in { color: #059669; } .YDEV_STAT.s-err { color: #dc2626; }
|
|
76406
76426
|
.YDEV_STAT.s-warn { color: #d97706; }
|
|
76407
76427
|
.YDEV_STAT.is-strong { font-weight: 700; }
|
|
@@ -76429,10 +76449,7 @@ function ensure_dev_style() {
|
|
|
76429
76449
|
.dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
|
|
76430
76450
|
.TRAFFIC_SUMMARY { opacity: 0.6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; min-width: 0; }
|
|
76431
76451
|
.TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
|
|
76432
|
-
.
|
|
76433
|
-
.TRAFFIC_ENTRY:hover .TRAFFIC_MUTE, .TRAFFIC_LINE:hover .TRAFFIC_MUTE, .TRAFFIC_NAME:hover .TRAFFIC_MUTE { opacity: 0.5; }
|
|
76434
|
-
.TRAFFIC_MUTE:hover { opacity: 1 !important; color: #d97706; }
|
|
76435
|
-
.TRAFFIC_KW { margin: 2px 0 0 16px; }
|
|
76452
|
+
.TRAFFIC_ENTRY:hover .TRAFFIC_KW { margin: 2px 0 0 16px; }
|
|
76436
76453
|
.TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
|
|
76437
76454
|
.TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
|
|
76438
76455
|
.TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
|
|
@@ -76476,9 +76493,7 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
|
|
|
76476
76493
|
:root[data-theme="dark"] .TRAFFIC_VAL.t-bool, :root[data-theme="dark"] .TRAFFIC_VAL.t-null { color: #c084fc; }
|
|
76477
76494
|
:root[data-theme="dark"] .YDEV_CHIP.is-active { background: rgba(96,165,250,0.2); border-color: #60a5fa; color: #93c5fd; }
|
|
76478
76495
|
:root[data-theme="dark"] .YDEV_SEG_BTN.is-active { background: #2563eb; color: #fff; }
|
|
76479
|
-
:root[data-theme="dark"]
|
|
76480
|
-
:root[data-theme="dark"] .YDEV_MUTED_CHIP { border-color: rgba(245,158,11,0.5); background: rgba(245,158,11,0.16); color: #fbbf24; }
|
|
76481
|
-
`;
|
|
76496
|
+
:root[data-theme="dark"] `;
|
|
76482
76497
|
let $style = document.createElement("style");
|
|
76483
76498
|
$style.id = "yui-dev-style";
|
|
76484
76499
|
$style.textContent = css;
|
|
@@ -76621,23 +76636,6 @@ function traffic_bullets(obj) {
|
|
|
76621
76636
|
/******************************
|
|
76622
76637
|
* Entry rendering (per view)
|
|
76623
76638
|
******************************/
|
|
76624
|
-
function mute_button(sig) {
|
|
76625
|
-
return [
|
|
76626
|
-
"button",
|
|
76627
|
-
{
|
|
76628
|
-
class: "TRAFFIC_MUTE",
|
|
76629
|
-
type: "button",
|
|
76630
|
-
title: (0, i18next.t)("mute this message"),
|
|
76631
|
-
"data-i18n-title": "mute this message"
|
|
76632
|
-
},
|
|
76633
|
-
"⊘",
|
|
76634
|
-
{ click: (ev) => {
|
|
76635
|
-
ev.stopPropagation();
|
|
76636
|
-
ev.preventDefault();
|
|
76637
|
-
mute_signature(sig);
|
|
76638
|
-
} }
|
|
76639
|
-
];
|
|
76640
|
-
}
|
|
76641
76639
|
function event_spans(e) {
|
|
76642
76640
|
let spans = [[
|
|
76643
76641
|
"span",
|
|
@@ -76675,7 +76673,6 @@ function compact_summary(kw) {
|
|
|
76675
76673
|
}
|
|
76676
76674
|
function render_detailed(e) {
|
|
76677
76675
|
let head = event_spans(e);
|
|
76678
|
-
head.push(mute_button(e.sig));
|
|
76679
76676
|
head.push([
|
|
76680
76677
|
"span",
|
|
76681
76678
|
{ class: "TRAFFIC_META" },
|
|
@@ -76734,7 +76731,6 @@ function full_sections(payload) {
|
|
|
76734
76731
|
}
|
|
76735
76732
|
function render_full(e) {
|
|
76736
76733
|
let head = event_spans(e);
|
|
76737
|
-
head.push(mute_button(e.sig));
|
|
76738
76734
|
head.push([
|
|
76739
76735
|
"span",
|
|
76740
76736
|
{ class: "TRAFFIC_META" },
|
|
@@ -76772,7 +76768,6 @@ function render_compact(e) {
|
|
|
76772
76768
|
{ class: "TRAFFIC_SUMMARY" },
|
|
76773
76769
|
compact_summary(e.kw)
|
|
76774
76770
|
]);
|
|
76775
|
-
kids.push(mute_button(e.sig));
|
|
76776
76771
|
kids.push([
|
|
76777
76772
|
"span",
|
|
76778
76773
|
{ class: "TRAFFIC_META" },
|
|
@@ -76789,7 +76784,6 @@ function render_compact(e) {
|
|
|
76789
76784
|
}
|
|
76790
76785
|
function render_name(e) {
|
|
76791
76786
|
let kids = event_spans(e);
|
|
76792
|
-
kids.push(mute_button(e.sig));
|
|
76793
76787
|
kids.push([
|
|
76794
76788
|
"span",
|
|
76795
76789
|
{ class: "TRAFFIC_META" },
|
|
@@ -76846,7 +76840,6 @@ function render_entry(e) {
|
|
|
76846
76840
|
******************************/
|
|
76847
76841
|
function clear_traffic() {
|
|
76848
76842
|
TRAFFIC_LOG.length = 0;
|
|
76849
|
-
TRAFFIC_COUNTS.clear();
|
|
76850
76843
|
LOG_ERR_COUNT = 0;
|
|
76851
76844
|
LOG_WARN_COUNT = 0;
|
|
76852
76845
|
let logger = document.getElementById("developer-traffic-logger");
|
|
@@ -76958,7 +76951,6 @@ function info_traffic(title, msg, direction, size) {
|
|
|
76958
76951
|
let event = jn && jn.event ? String(jn.event) : "(no event)";
|
|
76959
76952
|
let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : null;
|
|
76960
76953
|
let command = kw && typeof kw.command === "string" ? kw.command : "";
|
|
76961
|
-
let sig = traffic_signature(event, command);
|
|
76962
76954
|
let hay = "";
|
|
76963
76955
|
try {
|
|
76964
76956
|
hay = (event + " " + command + " " + (kw ? JSON.stringify(kw) : "")).toLowerCase();
|
|
@@ -76969,7 +76961,6 @@ function info_traffic(title, msg, direction, size) {
|
|
|
76969
76961
|
title: title || "",
|
|
76970
76962
|
event,
|
|
76971
76963
|
command,
|
|
76972
|
-
sig,
|
|
76973
76964
|
dir: direction,
|
|
76974
76965
|
size,
|
|
76975
76966
|
ts: traffic_now(),
|
|
@@ -76979,17 +76970,11 @@ function info_traffic(title, msg, direction, size) {
|
|
|
76979
76970
|
$node: null
|
|
76980
76971
|
};
|
|
76981
76972
|
TRAFFIC_LOG.push(entry);
|
|
76982
|
-
TRAFFIC_COUNTS.set(sig, (TRAFFIC_COUNTS.get(sig) || 0) + 1);
|
|
76983
|
-
let crossed = dev_hide_periodic() && TRAFFIC_COUNTS.get(sig) === PERIODIC_THRESHOLD;
|
|
76984
76973
|
if (TRAFFIC_LOG.length > TRAFFIC_MAX) {
|
|
76985
76974
|
let old = TRAFFIC_LOG.shift();
|
|
76986
|
-
let c = (TRAFFIC_COUNTS.get(old.sig) || 0) - 1;
|
|
76987
|
-
if (c <= 0) TRAFFIC_COUNTS.delete(old.sig);
|
|
76988
|
-
else TRAFFIC_COUNTS.set(old.sig, c);
|
|
76989
76975
|
if (old.$node && old.$node.parentNode) old.$node.parentNode.removeChild(old.$node);
|
|
76990
76976
|
}
|
|
76991
|
-
if (
|
|
76992
|
-
else if (!entry_hidden(entry, build_filter_ctx())) {
|
|
76977
|
+
if (!entry_hidden(entry, build_filter_ctx())) {
|
|
76993
76978
|
let node = render_entry(entry);
|
|
76994
76979
|
entry.$node = node;
|
|
76995
76980
|
let ph = logger.querySelector(".YDEV_EMPTY");
|
|
@@ -77035,19 +77020,12 @@ function info_log(level, msg, hora) {
|
|
|
77035
77020
|
dir: 0,
|
|
77036
77021
|
size: 0,
|
|
77037
77022
|
ts: traffic_now(),
|
|
77038
|
-
sig: log_signature(lvl, text),
|
|
77039
|
-
periodic: log_is_periodic(lvl, text),
|
|
77040
77023
|
hay: (lvl + " " + text).toLowerCase(),
|
|
77041
77024
|
$node: null
|
|
77042
77025
|
};
|
|
77043
77026
|
TRAFFIC_LOG.push(entry);
|
|
77044
77027
|
if (TRAFFIC_LOG.length > TRAFFIC_MAX) {
|
|
77045
77028
|
let old = TRAFFIC_LOG.shift();
|
|
77046
|
-
if (old.kind !== "log") {
|
|
77047
|
-
let c = (TRAFFIC_COUNTS.get(old.sig) || 0) - 1;
|
|
77048
|
-
if (c <= 0) TRAFFIC_COUNTS.delete(old.sig);
|
|
77049
|
-
else TRAFFIC_COUNTS.set(old.sig, c);
|
|
77050
|
-
}
|
|
77051
77029
|
if (old.$node && old.$node.parentNode) old.$node.parentNode.removeChild(old.$node);
|
|
77052
77030
|
}
|
|
77053
77031
|
if (!entry_hidden(entry, build_filter_ctx())) {
|
|
@@ -77065,72 +77043,97 @@ function info_log(level, msg, hora) {
|
|
|
77065
77043
|
/******************************
|
|
77066
77044
|
* Trace toggles
|
|
77067
77045
|
******************************/
|
|
77068
|
-
function
|
|
77069
|
-
let
|
|
77070
|
-
if (
|
|
77071
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_inter_event", false);
|
|
77072
|
-
v = 0;
|
|
77073
|
-
} else {
|
|
77074
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_inter_event", true);
|
|
77075
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_ievent_callback", info_traffic);
|
|
77076
|
-
v = 1;
|
|
77077
|
-
}
|
|
77078
|
-
(0, _yuneta_gobj_js.kw_set_local_storage_value)("trace_traffic", v);
|
|
77046
|
+
function yuno_trace_command(command, kw) {
|
|
77047
|
+
let r = (0, _yuneta_gobj_js.gobj_command)((0, _yuneta_gobj_js.gobj_yuno)(), command, kw, (0, _yuneta_gobj_js.gobj_yuno)());
|
|
77048
|
+
if (!r || r.result < 0) (0, _yuneta_gobj_js.log_error)(`yui_dev: ${command} ${JSON.stringify(kw)}: ${r ? r.comment : "no answer"}`);
|
|
77079
77049
|
refresh_dev_chrome();
|
|
77080
77050
|
}
|
|
77081
|
-
function
|
|
77082
|
-
|
|
77083
|
-
if (v === 0) v = 1;
|
|
77084
|
-
else if (v === 1) v = 2;
|
|
77085
|
-
else v = 0;
|
|
77086
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "tracing", v);
|
|
77087
|
-
(0, _yuneta_gobj_js.kw_set_local_storage_value)("trace_automata", v);
|
|
77088
|
-
refresh_dev_chrome();
|
|
77051
|
+
function global_bit(bit) {
|
|
77052
|
+
return (0, _yuneta_gobj_js.gobj_global_trace_level)() & bit ? 1 : 0;
|
|
77089
77053
|
}
|
|
77090
|
-
|
|
77091
|
-
|
|
77092
|
-
|
|
77093
|
-
|
|
77094
|
-
|
|
77095
|
-
|
|
77054
|
+
var GLOBAL_TRACE_BITS = {
|
|
77055
|
+
"machine": _yuneta_gobj_js.trace_level_t.TRACE_MACHINE,
|
|
77056
|
+
"ev_kw": _yuneta_gobj_js.trace_level_t.TRACE_EV_KW,
|
|
77057
|
+
"create_delete": _yuneta_gobj_js.trace_level_t.TRACE_CREATE_DELETE,
|
|
77058
|
+
"start_stop": _yuneta_gobj_js.trace_level_t.TRACE_START_STOP,
|
|
77059
|
+
"subscriptions": _yuneta_gobj_js.trace_level_t.TRACE_SUBSCRIPTIONS
|
|
77060
|
+
};
|
|
77061
|
+
function toggle_global(level) {
|
|
77062
|
+
yuno_trace_command("set-global-trace", {
|
|
77063
|
+
level,
|
|
77064
|
+
set: global_bit(GLOBAL_TRACE_BITS[level]) ? 0 : 1
|
|
77065
|
+
});
|
|
77096
77066
|
}
|
|
77097
|
-
function
|
|
77098
|
-
|
|
77099
|
-
|
|
77100
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_start_stop", v);
|
|
77101
|
-
(0, _yuneta_gobj_js.kw_set_local_storage_value)("trace_start_stop", v);
|
|
77102
|
-
refresh_dev_chrome();
|
|
77067
|
+
function automata_state() {
|
|
77068
|
+
if (!global_bit(_yuneta_gobj_js.trace_level_t.TRACE_MACHINE)) return 0;
|
|
77069
|
+
return global_bit(_yuneta_gobj_js.trace_level_t.TRACE_EV_KW) ? 2 : 1;
|
|
77103
77070
|
}
|
|
77104
|
-
function
|
|
77105
|
-
let v =
|
|
77106
|
-
|
|
77107
|
-
|
|
77108
|
-
|
|
77109
|
-
|
|
77071
|
+
function toggle_automata() {
|
|
77072
|
+
let v = automata_state();
|
|
77073
|
+
if (v === 0) yuno_trace_command("set-global-trace", {
|
|
77074
|
+
level: "machine",
|
|
77075
|
+
set: 1
|
|
77076
|
+
});
|
|
77077
|
+
else if (v === 1) yuno_trace_command("set-global-trace", {
|
|
77078
|
+
level: "ev_kw",
|
|
77079
|
+
set: 1
|
|
77080
|
+
});
|
|
77081
|
+
else {
|
|
77082
|
+
yuno_trace_command("set-global-trace", {
|
|
77083
|
+
level: "ev_kw",
|
|
77084
|
+
set: 0
|
|
77085
|
+
});
|
|
77086
|
+
yuno_trace_command("set-global-trace", {
|
|
77087
|
+
level: "machine",
|
|
77088
|
+
set: 0
|
|
77089
|
+
});
|
|
77090
|
+
}
|
|
77091
|
+
}
|
|
77092
|
+
function traffic_state() {
|
|
77093
|
+
return (0, _yuneta_gobj_js.gobj_get_gclass_trace_level2)("C_IEVENT_CLI").includes("ievents") ? 1 : 0;
|
|
77110
77094
|
}
|
|
77111
|
-
function
|
|
77112
|
-
|
|
77113
|
-
|
|
77095
|
+
function toggle_traffic() {
|
|
77096
|
+
yuno_trace_command("set-gclass-trace", {
|
|
77097
|
+
gclass_name: "C_IEVENT_CLI",
|
|
77098
|
+
level: "ievents",
|
|
77099
|
+
set: traffic_state() ? 0 : 1
|
|
77100
|
+
});
|
|
77101
|
+
}
|
|
77102
|
+
function periodic_state() {
|
|
77103
|
+
let on = (0, _yuneta_gobj_js.gobj_global_trace_level)() & _yuneta_gobj_js.trace_level_t.TRACE_TIMER_PERIODIC;
|
|
77104
|
+
let off = (0, _yuneta_gobj_js.gobj_global_trace_no_level)() & _yuneta_gobj_js.trace_level_t.TRACE_TIMER_PERIODIC;
|
|
77105
|
+
return on && !off ? 1 : 0;
|
|
77106
|
+
}
|
|
77107
|
+
function toggle_periodic() {
|
|
77108
|
+
let v = periodic_state() ? 0 : 1;
|
|
77109
|
+
yuno_trace_command("set-global-trace", {
|
|
77110
|
+
level: "timer_periodic",
|
|
77111
|
+
set: v
|
|
77112
|
+
});
|
|
77113
|
+
yuno_trace_command("set-global-no-trace", {
|
|
77114
|
+
level: "timer_periodic",
|
|
77115
|
+
set: v ? 0 : 1
|
|
77116
|
+
});
|
|
77117
|
+
}
|
|
77118
|
+
function i18n_state() {
|
|
77119
|
+
return Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("trace_i18n", 0, false)) ? 1 : 0;
|
|
77120
|
+
}
|
|
77121
|
+
function toggle_i18n() {
|
|
77122
|
+
let v = i18n_state() ? 0 : 1;
|
|
77114
77123
|
i18next.default.options.debug = v ? true : false;
|
|
77115
77124
|
(0, _yuneta_gobj_js.kw_set_local_storage_value)("trace_i18n", v);
|
|
77116
77125
|
refresh_dev_chrome();
|
|
77117
77126
|
}
|
|
77118
|
-
function set_no_poll() {
|
|
77119
|
-
let v = Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("no_poll"));
|
|
77120
|
-
v = v ? 0 : 1;
|
|
77121
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "no_poll", v);
|
|
77122
|
-
(0, _yuneta_gobj_js.kw_set_local_storage_value)("no_poll", v);
|
|
77123
|
-
refresh_dev_chrome();
|
|
77124
|
-
}
|
|
77125
77127
|
/******************************
|
|
77126
77128
|
* Chrome (controls)
|
|
77127
77129
|
******************************/
|
|
77128
77130
|
function refresh_dev_chrome() {
|
|
77129
77131
|
document.querySelectorAll(".YDEV_CHIP[data-trace]").forEach(($b) => {
|
|
77130
77132
|
let key = $b.getAttribute("data-trace");
|
|
77133
|
+
let def = TRACE_DEFS.find((d) => d[0] === key);
|
|
77131
77134
|
let label = (0, i18next.t)($b.getAttribute("data-label") || "");
|
|
77132
|
-
let v =
|
|
77133
|
-
$b.textContent = key === "
|
|
77135
|
+
let v = def ? def[3]() : 0;
|
|
77136
|
+
$b.textContent = key === "automata" && v > 0 ? label + " " + v : label;
|
|
77134
77137
|
$b.classList.toggle("is-active", v > 0);
|
|
77135
77138
|
});
|
|
77136
77139
|
let view = dev_view();
|
|
@@ -77149,40 +77152,9 @@ function refresh_dev_chrome() {
|
|
|
77149
77152
|
document.querySelectorAll(".YDEV_CHIP[data-dir]").forEach(($b) => {
|
|
77150
77153
|
$b.classList.toggle("is-active", !!dev_num($b.getAttribute("data-dir"), 1));
|
|
77151
77154
|
});
|
|
77152
|
-
document.querySelectorAll(".YDEV_CHIP[data-toggle=\"periodic\"]").forEach(($b) => {
|
|
77153
|
-
$b.classList.toggle("is-active", dev_hide_periodic());
|
|
77154
|
-
});
|
|
77155
77155
|
document.querySelectorAll(".YDEV_CHIP[data-toggle=\"automata-simple\"]").forEach(($b) => {
|
|
77156
77156
|
$b.classList.toggle("is-active", !!dev_simple_mach());
|
|
77157
77157
|
});
|
|
77158
|
-
let $m = document.getElementById("ydev-muted");
|
|
77159
|
-
if ($m) {
|
|
77160
|
-
$m.replaceChildren();
|
|
77161
|
-
let set = dev_muted();
|
|
77162
|
-
if (set.size) {
|
|
77163
|
-
let $lbl = document.createElement("span");
|
|
77164
|
-
$lbl.className = "YDEV_LABEL";
|
|
77165
|
-
$lbl.textContent = (0, i18next.t)("muted");
|
|
77166
|
-
$lbl.setAttribute("data-i18n", "muted");
|
|
77167
|
-
$m.appendChild($lbl);
|
|
77168
|
-
set.forEach((sig) => {
|
|
77169
|
-
$m.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
77170
|
-
"button",
|
|
77171
|
-
{
|
|
77172
|
-
class: "YDEV_MUTED_CHIP",
|
|
77173
|
-
type: "button",
|
|
77174
|
-
title: (0, i18next.t)("unmute"),
|
|
77175
|
-
"data-i18n-title": "unmute"
|
|
77176
|
-
},
|
|
77177
|
-
"⊘ " + sig + " ✕",
|
|
77178
|
-
{ click: (ev) => {
|
|
77179
|
-
ev.stopPropagation();
|
|
77180
|
-
unmute_signature(sig);
|
|
77181
|
-
} }
|
|
77182
|
-
]));
|
|
77183
|
-
});
|
|
77184
|
-
}
|
|
77185
|
-
}
|
|
77186
77158
|
update_stats();
|
|
77187
77159
|
}
|
|
77188
77160
|
function traffic_to_text() {
|
|
@@ -77227,19 +77199,23 @@ function dev_fallback_copy(text) {
|
|
|
77227
77199
|
document.body.removeChild(ta);
|
|
77228
77200
|
}
|
|
77229
77201
|
function build_control_bar() {
|
|
77230
|
-
let trace_chips = TRACE_DEFS.map(([key, label_key,
|
|
77202
|
+
let trace_chips = TRACE_DEFS.map(([key, label_key, title_key, state, toggle]) => [
|
|
77231
77203
|
"button",
|
|
77232
77204
|
{
|
|
77233
77205
|
class: "YDEV_CHIP",
|
|
77234
77206
|
"data-trace": key,
|
|
77235
77207
|
"data-label": label_key,
|
|
77236
77208
|
"data-i18n": label_key,
|
|
77237
|
-
type: "button"
|
|
77209
|
+
type: "button",
|
|
77210
|
+
title: (0, i18next.t)(title_key),
|
|
77211
|
+
"data-i18n-title": title_key,
|
|
77212
|
+
"aria-label": (0, i18next.t)(label_key),
|
|
77213
|
+
"data-i18n-aria-label": label_key
|
|
77238
77214
|
},
|
|
77239
77215
|
(0, i18next.t)(label_key),
|
|
77240
77216
|
{ click: (ev) => {
|
|
77241
77217
|
ev.stopPropagation();
|
|
77242
|
-
|
|
77218
|
+
toggle();
|
|
77243
77219
|
} }
|
|
77244
77220
|
]);
|
|
77245
77221
|
let simple_mach = [
|
|
@@ -77377,29 +77353,6 @@ function build_control_bar() {
|
|
|
77377
77353
|
mk_dir("in", "⇠", "dev_filter_in", "incoming"),
|
|
77378
77354
|
mk_dir("err", "⚠", "dev_filter_err", "errors")
|
|
77379
77355
|
];
|
|
77380
|
-
let periodic_chip = [
|
|
77381
|
-
"button",
|
|
77382
|
-
{
|
|
77383
|
-
class: "YDEV_CHIP",
|
|
77384
|
-
"data-toggle": "periodic",
|
|
77385
|
-
type: "button",
|
|
77386
|
-
title: (0, i18next.t)("hide the timers and the recurring traffic"),
|
|
77387
|
-
"data-i18n-title": "hide the timers and the recurring traffic"
|
|
77388
|
-
},
|
|
77389
|
-
[[
|
|
77390
|
-
"span",
|
|
77391
|
-
{ class: "YDEV_GLYPH" },
|
|
77392
|
-
"⊘"
|
|
77393
|
-
], [
|
|
77394
|
-
"span",
|
|
77395
|
-
{ "data-i18n": "periodic" },
|
|
77396
|
-
(0, i18next.t)("periodic")
|
|
77397
|
-
]],
|
|
77398
|
-
{ click: (ev) => {
|
|
77399
|
-
ev.stopPropagation();
|
|
77400
|
-
toggle_pref("dev_hide_periodic", HIDE_PERIODIC_DEFAULT);
|
|
77401
|
-
} }
|
|
77402
|
-
];
|
|
77403
77356
|
let search = [
|
|
77404
77357
|
"input",
|
|
77405
77358
|
{
|
|
@@ -77480,7 +77433,7 @@ function build_control_bar() {
|
|
|
77480
77433
|
grp("view", [view_seg]),
|
|
77481
77434
|
expand_grp,
|
|
77482
77435
|
sep(),
|
|
77483
|
-
grp("show",
|
|
77436
|
+
grp("show", dir_chips),
|
|
77484
77437
|
sep(),
|
|
77485
77438
|
grp("find", [search]),
|
|
77486
77439
|
sep(),
|
|
@@ -77515,14 +77468,6 @@ function build_dev_body() {
|
|
|
77515
77468
|
{ class: "YDEV_BODY" },
|
|
77516
77469
|
[
|
|
77517
77470
|
build_control_bar(),
|
|
77518
|
-
[
|
|
77519
|
-
"div",
|
|
77520
|
-
{
|
|
77521
|
-
class: "YDEV_MUTED",
|
|
77522
|
-
id: "ydev-muted"
|
|
77523
|
-
},
|
|
77524
|
-
[]
|
|
77525
|
-
],
|
|
77526
77471
|
[
|
|
77527
77472
|
"div",
|
|
77528
77473
|
{
|
|
@@ -77555,28 +77500,16 @@ function dev_window_was_open() {
|
|
|
77555
77500
|
return Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("open_developer_window", 0, false)) ? true : false;
|
|
77556
77501
|
}
|
|
77557
77502
|
/************************************************************
|
|
77558
|
-
*
|
|
77559
|
-
*
|
|
77560
|
-
*
|
|
77503
|
+
* Wire the developer window's sinks and the browser-side prefs.
|
|
77504
|
+
* Call it once at app startup.
|
|
77505
|
+
*
|
|
77506
|
+
* The TRACE LEVELS are not here: the yuno restores the ones the user
|
|
77507
|
+
* persisted in its own mt_create (`trace_levels` / `no_trace_levels`),
|
|
77508
|
+
* as a C yuno does. What is left is where the output goes.
|
|
77561
77509
|
************************************************************/
|
|
77562
77510
|
function apply_dev_traces() {
|
|
77563
|
-
|
|
77564
|
-
|
|
77565
|
-
let creation = Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("trace_creation", 0, false));
|
|
77566
|
-
let start_stop = Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("trace_start_stop", 0, false));
|
|
77567
|
-
let subscriptions = Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("trace_subscriptions", 0, false));
|
|
77568
|
-
let i18n = Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("trace_i18n", 0, false));
|
|
77569
|
-
let no_poll = Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("no_poll", 0, false));
|
|
77570
|
-
if (traffic) {
|
|
77571
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_inter_event", true);
|
|
77572
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_ievent_callback", info_traffic);
|
|
77573
|
-
} else (0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_inter_event", false);
|
|
77574
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "tracing", trace);
|
|
77575
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_creation", creation);
|
|
77576
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_start_stop", start_stop);
|
|
77577
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_subscriptions", subscriptions);
|
|
77578
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "no_poll", no_poll);
|
|
77579
|
-
i18next.default.options.debug = i18n ? true : false;
|
|
77511
|
+
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_ievent_callback", info_traffic);
|
|
77512
|
+
i18next.default.options.debug = i18n_state() ? true : false;
|
|
77580
77513
|
(0, _yuneta_gobj_js.gobj_set_trace_machine_format)(dev_simple_mach());
|
|
77581
77514
|
(0, _yuneta_gobj_js.set_log_callback)(info_log);
|
|
77582
77515
|
apply_console_route();
|
|
@@ -77627,8 +77560,8 @@ function setup_dev(self, show) {
|
|
|
77627
77560
|
*
|
|
77628
77561
|
* Returns { $el, dispose }:
|
|
77629
77562
|
* - $el: the panel element (control bar + log + stats).
|
|
77630
|
-
* - dispose:
|
|
77631
|
-
* the
|
|
77563
|
+
* - dispose: call it from the modal's on_close (kept for the
|
|
77564
|
+
* contract; the traces outlive the panel).
|
|
77632
77565
|
************************************************************/
|
|
77633
77566
|
function build_dev_panel() {
|
|
77634
77567
|
ensure_dev_style();
|
|
@@ -77649,9 +77582,7 @@ function build_dev_panel() {
|
|
|
77649
77582
|
refresh_dev_chrome();
|
|
77650
77583
|
rerender_all();
|
|
77651
77584
|
}, 0);
|
|
77652
|
-
let dispose = function() {
|
|
77653
|
-
(0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_inter_event", false);
|
|
77654
|
-
};
|
|
77585
|
+
let dispose = function() {};
|
|
77655
77586
|
return {
|
|
77656
77587
|
$el,
|
|
77657
77588
|
dispose
|