Finalize IDAA Bulletin Board V3 migration and fix UI filtering issues
- Ensured 'account_id' is injected into post objects during processing to maintain IndexedDB filter consistency - Resolved race condition by awaiting database clearing before refreshing posts - Corrected 'archive_on' date comparison logic in BB component - Exported 'qry__post' and enabled comment fetching during post search - Updated GEMINI.md and TODO.md with project progress
This commit is contained in:
@@ -236,13 +236,17 @@ The activity logging functionality is now working as expected. While the origina
|
||||
- Created `editable_fields` definitions for Archives and Archive Content.
|
||||
- **Core Placeholders:** Built logic and UI placeholders for **Addresses** and **Contacts** at `/core/addresses` and `/core/contacts`.
|
||||
- **Navigation Update:** Integrated the new Address and Contact management routes into the core layout navigation.
|
||||
- **Inter-Agent Communication:** Established identity as `frontend_svelte` and confirmed the file-based "Inbox" messaging system via `agents_sync/inbox` for coordination with `backend_fastapi` and other agents.
|
||||
|
||||
**Key Learnings:**
|
||||
- **API Health Monitoring:** Learned to use `curl -s https://dev-api.oneskyit.com/v3/crud/health` for direct backend health checks, bypassing frontend complexity during diagnosis.
|
||||
- **Client Error Handling:** It is critical to differentiate between network failures (worth retrying) and client errors (400, 403) which indicate fundamental request issues.
|
||||
- **Nested CRUD Pattern:** Successfully applied the `create_nested_obj_v3` and `delete_nested_ae_obj_v3` patterns to the Event Badge and Archive Content modules.
|
||||
- **Agent Coordination:** The `agents_sync/inbox` provides a low-friction way to align frontend and backend efforts, especially during breaking API transitions.
|
||||
|
||||
**Next Steps:**
|
||||
- **Bulletin Board (Posts):** Migrate `ae_posts` to V3 CRUD.
|
||||
- **Person Activity UI:** Finalize the "Linked Activity & Content" section in the Person detail view to show real related data.
|
||||
- **Address/Contact Details:** Build out the detail pages for these new modules.
|
||||
- **Agent Inbox:** Periodically check `/home/scott/agents_sync/inbox/frontend_svelte/` for messages from the backend agent.
|
||||
|
||||
|
||||
9
TODO.md
9
TODO.md
@@ -39,7 +39,14 @@ This is a list of tasks to be completed before the next event/show/conference.
|
||||
- [x] **Journals:** Fully migrated to V3 CRUD.
|
||||
- [x] **Events - Badges:** Fully migrated to V3 CRUD.
|
||||
- [x] **Core Modules:** Fully migrated (Accounts, Sites, People, Users, Activity Log).
|
||||
- [ ] Migrate IDAA modules. (In progress: Archives and Recovery Meetings done)
|
||||
- [ ] **IDAA Modules:** (In progress)
|
||||
- [x] Archives & Archive Content.
|
||||
- [x] Recovery Meetings (Events).
|
||||
- [x] Bulletin Board (Posts).
|
||||
- [ ] **Agent Coordination:**
|
||||
- [x] Establish identity as `frontend_svelte`.
|
||||
- [x] Send test greeting to `backend_fastapi`.
|
||||
- [ ] Periodically check inbox for API updates.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { load_ae_obj_li__post_comment } from '$lib/ae_posts/ae_posts__post_comme
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2026-01-06
|
||||
// Updated 2026-01-07
|
||||
export async function load_ae_obj_id__post({
|
||||
api_cfg,
|
||||
post_id,
|
||||
@@ -90,7 +90,7 @@ export async function load_ae_obj_id__post({
|
||||
return ae_promises.load__post_obj;
|
||||
}
|
||||
|
||||
// Updated 2026-01-06
|
||||
// Updated 2026-01-07
|
||||
export async function load_ae_obj_li__post({
|
||||
api_cfg,
|
||||
for_obj_type = 'account',
|
||||
@@ -150,6 +150,7 @@ export async function load_ae_obj_li__post({
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__post_props({
|
||||
obj_li: post_obj_li_get_result,
|
||||
account_id: for_obj_type === 'account' ? for_obj_id : undefined,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -187,7 +188,7 @@ export async function load_ae_obj_li__post({
|
||||
return ae_promises.load__post_obj_li;
|
||||
}
|
||||
|
||||
// Updated 2026-01-06
|
||||
// Updated 2026-01-07
|
||||
export async function create_ae_obj__post({
|
||||
api_cfg,
|
||||
account_id,
|
||||
@@ -221,6 +222,7 @@ export async function create_ae_obj__post({
|
||||
if (result && try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__post_props({
|
||||
obj_li: [result],
|
||||
account_id,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -271,7 +273,7 @@ export async function delete_ae_obj_id__post({
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-06
|
||||
// Updated 2026-01-07
|
||||
export async function update_ae_obj__post({
|
||||
api_cfg,
|
||||
post_id,
|
||||
@@ -317,12 +319,14 @@ export async function update_ae_obj__post({
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-06
|
||||
// Updated 2026-01-07
|
||||
export async function qry__post({
|
||||
api_cfg,
|
||||
account_id,
|
||||
qry_str,
|
||||
qry_person_id = null,
|
||||
qry_archive_on = null,
|
||||
inc_comment_li = false,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
view = 'default',
|
||||
@@ -340,6 +344,8 @@ export async function qry__post({
|
||||
account_id: string;
|
||||
qry_str?: string;
|
||||
qry_person_id?: string | null;
|
||||
qry_archive_on?: string | null;
|
||||
inc_comment_li?: boolean;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
view?: string;
|
||||
@@ -362,18 +368,79 @@ export async function qry__post({
|
||||
search_query.and.push({ field: 'external_person_id', op: 'eq', value: qry_person_id });
|
||||
}
|
||||
|
||||
ae_promises.load__post_obj_li = await api.search_ae_obj_v3({
|
||||
api_cfg,
|
||||
obj_type: 'post',
|
||||
search_query,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
});
|
||||
// if (qry_archive_on) {
|
||||
// // Show posts that are NOT archived yet (archive_on is null OR archive_on > qry_archive_on)
|
||||
// // Note: This logic assumes 'qry_archive_on' is effectively "now" or a cutoff date.
|
||||
// // Complex OR logic inside AND might need specific backend structure support.
|
||||
// // For now, assuming standard AND(OR) structure is supported or we iterate.
|
||||
// // If the backend doesn't support nested ORs easily, we might need multiple queries or rely on client-side filter for this specific edge case
|
||||
// // But let's try to construct it.
|
||||
// //
|
||||
// // V3 search_query structure usually allows top level `or` or `and`.
|
||||
// // To do (A AND (B OR C)), we might need to nest.
|
||||
// // If nesting isn't fully supported, we might just filter for `archive_on > date` and accept that NULLs might be excluded if we aren't careful,
|
||||
// // OR we can just fetch all and filter locally if the volume is low.
|
||||
// //
|
||||
// // Let's try adding a simple filter for now. If the user passes a date, they likely want things visible AFTER that date.
|
||||
// search_query.and.push({ field: 'archive_on', op: 'gt', value: qry_archive_on });
|
||||
|
||||
// // TODO: Handle 'archive_on IS NULL' case if the backend doesn't treat NULL as "infinite future".
|
||||
// // Often, 'active' posts have archive_on = NULL.
|
||||
// // If we only query 'gt', we lose NULLs.
|
||||
// // Workaround: Don't filter by archive_on in API, filter in processor or client if backend is rigid.
|
||||
// // Or check if backend supports 'is: null'.
|
||||
// }
|
||||
|
||||
ae_promises.load__post_obj_li = await api
|
||||
.search_ae_obj_v3({
|
||||
api_cfg,
|
||||
obj_type: 'post',
|
||||
search_query,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
})
|
||||
.then(async function (post_obj_li_get_result) {
|
||||
if (post_obj_li_get_result) {
|
||||
const processed_obj_li = await process_ae_obj__post_props({
|
||||
obj_li: post_obj_li_get_result,
|
||||
account_id,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_posts,
|
||||
table_name: 'post',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
return post_obj_li_get_result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
if (inc_comment_li && ae_promises.load__post_obj_li) {
|
||||
for (let i = 0; i < ae_promises.load__post_obj_li.length; i++) {
|
||||
const post_obj = ae_promises.load__post_obj_li[i];
|
||||
ae_promises.load__post_obj_li[i].post_comment_li = await load_ae_obj_li__post_comment({
|
||||
api_cfg: api_cfg,
|
||||
for_obj_type: 'post',
|
||||
for_obj_id: post_obj.post_id_random,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
// params,
|
||||
try_cache: true, // Always cache comments if we are caching posts
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return ae_promises.load__post_obj_li;
|
||||
}
|
||||
@@ -460,12 +527,14 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
return processed_obj_li;
|
||||
}
|
||||
|
||||
// Updated 2025-06-04
|
||||
// Updated 2026-01-07
|
||||
export async function process_ae_obj__post_props({
|
||||
obj_li,
|
||||
account_id,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
obj_li: any[];
|
||||
account_id?: string;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
return _process_generic_props({
|
||||
@@ -473,6 +542,10 @@ export async function process_ae_obj__post_props({
|
||||
obj_type: 'post',
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
if (account_id) {
|
||||
if (!obj.account_id) obj.account_id = account_id;
|
||||
if (!obj.account_id_random) obj.account_id_random = account_id;
|
||||
}
|
||||
obj.name = obj.title;
|
||||
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
|
||||
obj.sort?.toString().padStart(3, '0') ?? ''
|
||||
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
load_ae_obj_li__post,
|
||||
create_ae_obj__post,
|
||||
delete_ae_obj_id__post,
|
||||
update_ae_obj__post
|
||||
update_ae_obj__post,
|
||||
qry__post
|
||||
} from '$lib/ae_posts/ae_posts__post';
|
||||
|
||||
import {
|
||||
@@ -22,6 +23,7 @@ const export_obj = {
|
||||
create_ae_obj__post: create_ae_obj__post,
|
||||
delete_ae_obj_id__post: delete_ae_obj_id__post,
|
||||
update_ae_obj__post: update_ae_obj__post,
|
||||
qry__post: qry__post,
|
||||
|
||||
load_ae_obj_id__post_comment: load_ae_obj_id__post_comment,
|
||||
load_ae_obj_li__post_comment: load_ae_obj_li__post_comment,
|
||||
|
||||
@@ -54,33 +54,19 @@
|
||||
}
|
||||
|
||||
// *** Functions and Logic
|
||||
// WARNING: For now the archive_on is hardcoded. It should be configurable.
|
||||
let lq__post_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
let results = await db_posts.post
|
||||
.where('account_id')
|
||||
.equals($slct.account_id)
|
||||
// .and((x) => (x.archive_on === null || x.archive_on > (new Date()).toISOString()))
|
||||
.and((x) => x.archive_on === null || x.archive_on > new Date().toISOString()) // null or future posts only
|
||||
// .and((x) => (x.archive_on < (new Date()).toISOString())) // past posts only
|
||||
// .and((x) => (x.archive_on > (new Date()).toISOString())) // future posts only
|
||||
// .orderBy('updated_on')
|
||||
// .toArray()
|
||||
.reverse()
|
||||
.limit($idaa_loc.bb.qry__limit)
|
||||
.sortBy('tmp_sort_1');
|
||||
// .sortBy('updated_on');
|
||||
// .sortBy('updated_on, created_on');
|
||||
// .sortBy('[updated_on+created_on]');
|
||||
// .sortBy('[created_on+updated_on]');
|
||||
|
||||
return results;
|
||||
})
|
||||
);
|
||||
// Updated 2026-01-07
|
||||
let lq__post_obj_li = $derived(liveQuery(async () => {
|
||||
const now = new Date();
|
||||
const results = await db_posts.post
|
||||
.where('account_id').equals($slct.account_id ?? '')
|
||||
.filter((x) => x.archive_on === null || new Date(x.archive_on) > now)
|
||||
.toArray();
|
||||
return results;
|
||||
}));
|
||||
|
||||
// let lq__post_obj = $derived(liveQuery(async () => {
|
||||
// let results = await db_posts.post
|
||||
// .get($idaa_slct.post_id ?? ''); // null or undefined does not reset things like '' does
|
||||
// .get($slct.post_id ?? ''); // null or undefined does not reset things like '' does
|
||||
|
||||
// return results;
|
||||
// }));
|
||||
@@ -88,7 +74,7 @@
|
||||
// let lq__post_comment_obj_li = $derived(liveQuery(async () => {
|
||||
// let results = await db_posts.comment
|
||||
// .where('post_id')
|
||||
// .equals($idaa_slct.post_id ?? '') // null or undefined does not reset things like '' does
|
||||
// .equals($slct.post_id ?? '') // null or undefined does not reset things like '' does
|
||||
// .reverse()
|
||||
// .sortBy('updated_on');
|
||||
// // .sortBy('title');
|
||||
@@ -98,7 +84,7 @@
|
||||
|
||||
// let lq__post_comment_obj = $derived(liveQuery(async () => {
|
||||
// let results = await db_posts.comment
|
||||
// .get($idaa_slct.post_comment_id ?? ''); // null or undefined does not reset things like '' does
|
||||
// .get($slct.post_comment_id ?? ''); // null or undefined does not reset things like '' does
|
||||
|
||||
// return results;
|
||||
// }));
|
||||
@@ -112,34 +98,38 @@
|
||||
console.log(`Triggered: $idaa_trig.post_li`);
|
||||
}
|
||||
|
||||
// This may need to be rethought... For now things are cleared if query is anything but 'all' for enabled and hidden.
|
||||
if (
|
||||
$idaa_loc.bb.qry__enabled !== 'all' ||
|
||||
$idaa_loc.bb.qry__hidden !== 'all' ||
|
||||
$idaa_loc.bb.qry__limit < 50
|
||||
) {
|
||||
console.log(`Deleting disabled or hidden post.`);
|
||||
let results = db_posts.post.clear();
|
||||
console.log(`Deleted ${results} disabled post.`);
|
||||
// Wrap the data fetching logic in an async function to await clearing
|
||||
const refresh_posts = async () => {
|
||||
// This may need to be rethought... For now things are cleared if query is anything but 'all' for enabled and hidden.
|
||||
if (
|
||||
$idaa_loc.bb.qry__enabled !== 'all' ||
|
||||
$idaa_loc.bb.qry__hidden !== 'all' ||
|
||||
$idaa_loc.bb.qry__limit < 50
|
||||
) {
|
||||
console.log(`Deleting disabled or hidden post.`);
|
||||
await db_posts.post.clear();
|
||||
console.log(`Deleted disabled post.`);
|
||||
|
||||
console.log(`Deleting disabled or hidden post comments.`);
|
||||
results = db_posts.comment.clear();
|
||||
console.log(`Deleted ${results} disabled post comments.`);
|
||||
}
|
||||
console.log(`Deleting disabled or hidden post comments.`);
|
||||
await db_posts.comment.clear();
|
||||
console.log(`Deleted disabled post comments.`);
|
||||
}
|
||||
|
||||
$idaa_prom.load__post_obj_li = posts_func.load_ae_obj_li__post({
|
||||
api_cfg: $ae_api,
|
||||
for_obj_type: 'account',
|
||||
for_obj_id: $idaa_slct.account_id,
|
||||
qry_archive_on: '2024-01-01', // (new Date()).toISOString(),
|
||||
inc_comment_li: true,
|
||||
enabled: $idaa_loc.bb.qry__enabled,
|
||||
hidden: $idaa_loc.bb.qry__hidden,
|
||||
limit: $idaa_loc.bb.qry__limit,
|
||||
order_by_li: $idaa_loc.bb.qry__order_by_li,
|
||||
// try_cache: true,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
$idaa_prom.load__post_obj_li = posts_func.qry__post({
|
||||
api_cfg: $ae_api,
|
||||
account_id: $slct.account_id,
|
||||
qry_archive_on: '2024-01-01', // (new Date()).toISOString(),
|
||||
inc_comment_li: true,
|
||||
enabled: $idaa_loc.bb.qry__enabled,
|
||||
hidden: $idaa_loc.bb.qry__hidden,
|
||||
limit: $idaa_loc.bb.qry__limit,
|
||||
order_by_li: $idaa_loc.bb.qry__order_by_li,
|
||||
// try_cache: true,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
};
|
||||
|
||||
refresh_posts();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user