@xuda.io/account_module 1.2.2300 → 1.2.2302
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/index.mjs +78 -28
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -55,6 +55,18 @@ const module_path = path.join(process.env.XUDA_HOME, 'cpi') + (!_conf.is_debug ?
|
|
|
55
55
|
|
|
56
56
|
const db_module = await import(`${module_path}/db_module/index.mjs`);
|
|
57
57
|
|
|
58
|
+
// Sort keys for the dashboard list tabs, per docType. Each entry is a fallback
|
|
59
|
+
// chain (first defined value wins) because doc shapes differ. A profile keeps
|
|
60
|
+
// its display name under profile_name, a contact under name. See
|
|
61
|
+
// db_module.find_app_couch_sorted_page.
|
|
62
|
+
const LIST_SORT_PATHS = {
|
|
63
|
+
contact: { created: ['date_created_ts', 'date_created', 'ts'], updated: ['ts', 'date_created_ts'], name: ['name', 'contact_name', 'email'] },
|
|
64
|
+
account_profile: { created: ['date_created_ts', 'date_created', 'ts'], updated: ['ts', 'date_created_ts'], name: ['profile_name', 'name'] },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Dashboard list tabs whose sort preference is remembered per profile.
|
|
68
|
+
const LIST_SORT_TABS = ['ai_chats', 'apps', 'contacts', 'ai_agents', 'account_profiles'];
|
|
69
|
+
|
|
58
70
|
const ai_ms = await import(`${module_path}/ai_module/index_ms.mjs`);
|
|
59
71
|
const drive_ms = await import(`${module_path}/drive_module/index_ms.mjs`);
|
|
60
72
|
|
|
@@ -370,7 +382,7 @@ export const update_account_info = async function (req, job_id, headers) {
|
|
|
370
382
|
return save_ret;
|
|
371
383
|
};
|
|
372
384
|
export const update_account_preferences = async function (req) {
|
|
373
|
-
const { uid, hide_create_button, default_dashboard, sidebar_style, enable_thumbnail_avatar_generation, sidenav_mode, newsletter_opt_in } = req;
|
|
385
|
+
const { uid, hide_create_button, default_dashboard, sidebar_style, enable_thumbnail_avatar_generation, sidenav_mode, newsletter_opt_in, dashboard_sort } = req;
|
|
374
386
|
try {
|
|
375
387
|
let account_doc = await db_module.get_couch_doc_native('xuda_accounts', uid);
|
|
376
388
|
account_doc.ts = Date.now();
|
|
@@ -386,6 +398,32 @@ export const update_account_preferences = async function (req) {
|
|
|
386
398
|
// flag via router /newsletter/unsubscribe. Only touched when the caller sends it.
|
|
387
399
|
if (newsletter_opt_in !== undefined) account_doc.preferences.newsletter_opt_in = !!newsletter_opt_in;
|
|
388
400
|
|
|
401
|
+
// Dashboard list sort, remembered per PROFILE and per tab so switching
|
|
402
|
+
// profiles brings back that profile's own order:
|
|
403
|
+
// preferences.dashboard_sort[<account_profile_id>][<tab>] = { by, dir }
|
|
404
|
+
// Callers send one tab at a time ({ tab, sort_by, sort_dir, profile_id })
|
|
405
|
+
// and the merge below is surgical, so saving the Contacts order can never
|
|
406
|
+
// drop the one saved for AI Chats or for another profile. Sending
|
|
407
|
+
// sort_by:null clears that tab back to the default order.
|
|
408
|
+
if (dashboard_sort !== undefined) {
|
|
409
|
+
const { tab, sort_by, sort_dir } = dashboard_sort || {};
|
|
410
|
+
if (LIST_SORT_TABS.includes(tab)) {
|
|
411
|
+
const profile_info = await get_active_account_profile_info(uid, dashboard_sort?.profile_id);
|
|
412
|
+
const profile_key = profile_info?.account_profile_id || 'default';
|
|
413
|
+
const all = { ...(account_doc.preferences.dashboard_sort || {}) };
|
|
414
|
+
const for_profile = { ...(all[profile_key] || {}) };
|
|
415
|
+
|
|
416
|
+
if (['date', 'updated', 'name'].includes(sort_by)) {
|
|
417
|
+
for_profile[tab] = { by: sort_by, dir: sort_dir === 'asc' ? 'asc' : 'desc' };
|
|
418
|
+
} else {
|
|
419
|
+
delete for_profile[tab];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
all[profile_key] = for_profile;
|
|
423
|
+
account_doc.preferences.dashboard_sort = all;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
389
427
|
const save_ret = await db_module.save_couch_doc('xuda_accounts', account_doc);
|
|
390
428
|
if (save_ret.code < 0) {
|
|
391
429
|
throw new Error(save_ret.data);
|
|
@@ -1176,7 +1214,7 @@ export const backfill_app_costs = async function (opts = {}) {
|
|
|
1176
1214
|
} else if (!BILLABLE_APP_TYPES.includes(doc.app_type) && !doc.is_deployment) {
|
|
1177
1215
|
reason = `app_type ${doc.app_type} not billable`;
|
|
1178
1216
|
} else {
|
|
1179
|
-
const has_addons = doc.deploy_data?.enable_backups || doc.deploy_data?.enable_ai_maintenance || doc.deploy_data?.enable_ai_instructions || doc.deploy_data?.enable_offline || doc.deploy_data?.
|
|
1217
|
+
const has_addons = doc.deploy_data?.enable_backups || doc.deploy_data?.enable_ai_maintenance || doc.deploy_data?.enable_ai_instructions || doc.deploy_data?.enable_offline || doc.deploy_data?.enable_user_assist;
|
|
1180
1218
|
if (doc.is_deployment && !has_addons && !doc.deploy_data?.app_server_type) {
|
|
1181
1219
|
reason = 'deployment without addons → datacenter bears cost';
|
|
1182
1220
|
} else {
|
|
@@ -5466,17 +5504,25 @@ export const get_contacts = async function (req, job_id, headers) {
|
|
|
5466
5504
|
let contacts = { docs: [], total_docs: 0 };
|
|
5467
5505
|
|
|
5468
5506
|
if (filter_type !== 'pending') {
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5507
|
+
// User-picked order from the dashboard list controls, see
|
|
5508
|
+
// db_module.find_app_couch_sorted_page. Null when none was asked for,
|
|
5509
|
+
// which leaves the default newest-first path below untouched.
|
|
5510
|
+
const sorted = contact_id ? null : await db_module.find_app_couch_sorted_page(account_profile_info.app_id, opt, req, LIST_SORT_PATHS.contact);
|
|
5511
|
+
if (sorted) {
|
|
5512
|
+
contacts = sorted;
|
|
5472
5513
|
} else {
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5514
|
+
contacts = await find_contact_query(account_profile_info.uid, opt);
|
|
5515
|
+
if (!limit || contact_id) {
|
|
5516
|
+
contacts.total_docs = contacts.docs.length;
|
|
5517
|
+
} else {
|
|
5518
|
+
delete opt.sort;
|
|
5519
|
+
delete opt.skip;
|
|
5520
|
+
opt.limit = 9999;
|
|
5521
|
+
opt.fields = ['_id'];
|
|
5477
5522
|
|
|
5478
|
-
|
|
5479
|
-
|
|
5523
|
+
const counter = await find_contact_query(account_profile_info.uid, opt);
|
|
5524
|
+
contacts.total_docs = counter.docs.length;
|
|
5525
|
+
}
|
|
5480
5526
|
}
|
|
5481
5527
|
}
|
|
5482
5528
|
|
|
@@ -5953,14 +5999,9 @@ export const get_account_profile_info = async function (uid, contact_profile_doc
|
|
|
5953
5999
|
doc.profile_picture = account_info_ret.data.profile_picture;
|
|
5954
6000
|
}
|
|
5955
6001
|
|
|
5956
|
-
// The main profile
|
|
5957
|
-
//
|
|
5958
|
-
//
|
|
5959
|
-
// runtime (ai_module.auto_response) also hard-skips the main profile.
|
|
5960
|
-
if (doc.main) {
|
|
5961
|
-
doc.auto_respond = false;
|
|
5962
|
-
}
|
|
5963
|
-
|
|
6002
|
+
// The main profile's stored auto_respond is returned as-is (Boaz, 2026-07-31, reversing
|
|
6003
|
+
// UI-44 part 2). This used to be forced to false so the card would hide the control; with
|
|
6004
|
+
// the control back, forcing it would make the toggle read as off however it was saved.
|
|
5964
6005
|
if (!doc.account_type) {
|
|
5965
6006
|
doc.account_type = account_info_ret.data.account_type;
|
|
5966
6007
|
}
|
|
@@ -6157,17 +6198,26 @@ export const get_account_profiles = async function (req) {
|
|
|
6157
6198
|
let profiles = { docs: [], total_docs: 0 };
|
|
6158
6199
|
|
|
6159
6200
|
if (filter_type !== 'pending') {
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6201
|
+
// User-picked order from the dashboard list controls, see
|
|
6202
|
+
// db_module.find_app_couch_sorted_page. Null when none was asked for,
|
|
6203
|
+
// which leaves the default newest-first path below untouched. The main
|
|
6204
|
+
// profile is still floated to the top of the page after enrichment.
|
|
6205
|
+
const sorted = profile_id ? null : await db_module.find_app_couch_sorted_page(app_id, opt, req, LIST_SORT_PATHS.account_profile);
|
|
6206
|
+
if (sorted) {
|
|
6207
|
+
profiles = sorted;
|
|
6163
6208
|
} else {
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6209
|
+
profiles = await db_module.find_app_couch_query(app_id, opt);
|
|
6210
|
+
if (!limit || profile_id) {
|
|
6211
|
+
profiles.total_docs = profiles.docs.length;
|
|
6212
|
+
} else {
|
|
6213
|
+
delete opt.sort;
|
|
6214
|
+
delete opt.skip;
|
|
6215
|
+
opt.limit = 9999;
|
|
6216
|
+
opt.fields = ['_id'];
|
|
6168
6217
|
|
|
6169
|
-
|
|
6170
|
-
|
|
6218
|
+
const counter = await db_module.find_app_couch_query(app_id, opt);
|
|
6219
|
+
profiles.total_docs = counter.docs.length;
|
|
6220
|
+
}
|
|
6171
6221
|
}
|
|
6172
6222
|
}
|
|
6173
6223
|
|