pres_mgmt: migrate to typed PersistedState store, canonical config schema
Replaces untyped $events_loc.pres_mgmt (svelte-persisted-store) with a dedicated pres_mgmt_loc (runed PersistedState) backed by a fully typed PresMgmtLocState interface and PressMgmtRemoteCfg for the server-side JSON. Key changes: - ae_events_stores__pres_mgmt_defaults.ts: canonical interfaces + defaults covering all hide__/show__ fields, labels, report prefs, query filters, and lock_config sync fields; qry_enabled uses 'not_enabled' (matches API) - ae_events_stores__pres_mgmt.svelte.ts: new PersistedState store - ae_events__event.ts: sync_config__event_pres_mgmt() rewired to write directly to pres_mgmt_loc.current; launcher link inversion preserved - All 26+ pres_mgmt templates migrated from $events_loc.pres_mgmt.* to pres_mgmt_loc.current.* - New config UI at (pres_mgmt)/pres_mgmt/config/ — manager + edit mode only - Event settings page: removed embedded pres_mgmt form, links to config page - event_page_menu: Config button visible only when manager_access + edit_mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
18
src/lib/stores/ae_events_stores__pres_mgmt.svelte.ts
Normal file
18
src/lib/stores/ae_events_stores__pres_mgmt.svelte.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* ae_events_stores__pres_mgmt.svelte.ts
|
||||
*
|
||||
* Svelte 5 PersistedState store for Presentation Management local config.
|
||||
* Replaces the `events_loc.pres_mgmt` sub-object from the Svelte 4 persisted store.
|
||||
*
|
||||
* localStorage key: 'ae_pres_mgmt_loc'
|
||||
* Version gate: AE_PRES_MGMT_LOC_VERSION in store_versions.ts
|
||||
*
|
||||
* Usage:
|
||||
* import { pres_mgmt_loc } from '$lib/stores/ae_events_stores__pres_mgmt.svelte';
|
||||
* pres_mgmt_loc.current.hide__session_code // read
|
||||
* pres_mgmt_loc.current.hide__session_code = true // write
|
||||
*/
|
||||
import { PersistedState } from 'runed';
|
||||
import { pres_mgmt_loc_defaults } from './ae_events_stores__pres_mgmt_defaults';
|
||||
|
||||
export const pres_mgmt_loc = new PersistedState('ae_pres_mgmt_loc', pres_mgmt_loc_defaults);
|
||||
@@ -1,19 +1,95 @@
|
||||
/**
|
||||
* ae_events_stores__pres_mgmt_defaults.ts
|
||||
*
|
||||
* Default state for the pres_mgmt (Presentation Management) section of ae_events_stores.ts.
|
||||
* pres_mgmt_loc_defaults → events_loc.pres_mgmt (persisted to localStorage)
|
||||
* pres_mgmt_sess_defaults → events_sess.pres_mgmt (in-memory, resets on page load)
|
||||
* Type definitions and defaults for the Pres Mgmt stores.
|
||||
*
|
||||
* PressMgmtRemoteCfg → shape of event.mod_pres_mgmt_json (server-side admin config)
|
||||
* PresMgmtLocState → pres_mgmt_loc (PersistedState, localStorage)
|
||||
* PresMgmtSessState → events_sess.pres_mgmt (in-memory, resets on page load)
|
||||
*
|
||||
* NAMING CONVENTION (enforced here, must not mix):
|
||||
* hide__* → feature is ON by default; true = turn it off (default: false = visible)
|
||||
* show__* → feature is OFF by default; true = turn it on (default: false = hidden)
|
||||
* Never use both hide__foo and show__foo for the same concept.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Remote config — shape of event.mod_pres_mgmt_json
|
||||
// This is the admin-controlled, server-side config for an event.
|
||||
// lock_config: true forces every field below to sync into local state on load.
|
||||
// ---------------------------------------------------------------------------
|
||||
export interface PressMgmtRemoteCfg {
|
||||
// System
|
||||
lock_config: boolean; // true = force all fields below into local state
|
||||
|
||||
// Labels — event-specific terminology overrides
|
||||
label__person_external_id: string | null; // default: 'External ID'
|
||||
label__presenter_external_id: string | null; // default: 'External ID'
|
||||
label__session_poc_type: string | null; // e.g. 'champion', 'poc'
|
||||
label__session_poc_name: string | null; // e.g. 'Champion', 'Point of Contact'
|
||||
|
||||
// Code visibility (visible by default)
|
||||
hide__location_code: boolean;
|
||||
hide__presentation_code: boolean;
|
||||
hide__presenter_code: boolean;
|
||||
hide__session_code: boolean;
|
||||
|
||||
// Session field visibility (visible by default)
|
||||
hide__session_description: boolean;
|
||||
hide__session_location: boolean;
|
||||
hide__session_msg: boolean;
|
||||
hide__session_poc: boolean;
|
||||
hide__session_poc_biography: boolean;
|
||||
hide__session_poc_profile: boolean;
|
||||
hide__session_poc_profile_pic: boolean;
|
||||
|
||||
// Presenter field visibility
|
||||
hide__presenter_biography: boolean;
|
||||
|
||||
// Presentation field visibility
|
||||
hide__presentation_datetime: boolean;
|
||||
hide__presentation_description: boolean; // replaces show_content__presentation_description
|
||||
|
||||
// Opt-in features (hidden by default — set true to enable)
|
||||
show__copy_access_link: boolean;
|
||||
show__email_access_link: boolean;
|
||||
show__launcher_link: boolean;
|
||||
show__launcher_link_legacy: boolean;
|
||||
|
||||
// Requirements
|
||||
require__presenter_agree: boolean;
|
||||
require__session_agree: boolean;
|
||||
|
||||
// Navigation / UI constraints
|
||||
limit__navigation: boolean;
|
||||
limit__options: boolean;
|
||||
|
||||
// File upload options (null = use system default)
|
||||
file_purpose_option_kv: Record<
|
||||
string,
|
||||
{ name: string; disabled?: boolean; hidden?: boolean }
|
||||
> | null;
|
||||
|
||||
// Report section visibility (key = report slug, true = hide that report)
|
||||
hide__report_kv: Record<string, boolean>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Local state — persisted to localStorage via PersistedState ('ae_pres_mgmt_loc')
|
||||
// Contains both user preferences AND fields synced from PressMgmtRemoteCfg.
|
||||
// Fields synced from remote are overwritten on every event load when lock_config=true.
|
||||
// ---------------------------------------------------------------------------
|
||||
export interface PresMgmtLocState {
|
||||
// --- System / lock state (mirrored from remote for display) ---
|
||||
sync_local_config: boolean;
|
||||
lock_config: boolean;
|
||||
|
||||
// --- Query / search preferences ---
|
||||
datetime_format: string;
|
||||
time_format: string;
|
||||
time_hours: 12 | 24;
|
||||
qry_enabled: string; // 'all' | 'disabled' | 'enabled'
|
||||
qry_hidden: string; // 'all' | 'hidden' | 'not_hidden'
|
||||
qry_enabled: 'all' | 'not_enabled' | 'enabled';
|
||||
qry_hidden: 'all' | 'hidden' | 'not_hidden';
|
||||
qry_limit__files: number;
|
||||
qry_limit__presentations: number;
|
||||
qry_limit__presenters: number;
|
||||
@@ -26,11 +102,29 @@ export interface PresMgmtLocState {
|
||||
qry_and__file_count: boolean;
|
||||
save_search_text: boolean;
|
||||
saved_search__session: string | null;
|
||||
require__presenter_agree: boolean;
|
||||
require__session_agree: boolean;
|
||||
saved_search__session_location_name: string | null;
|
||||
fulltext_search_qry_str: string | null; // persisted search text (when save_search_text=true)
|
||||
location_name_qry_str: string | null; // persisted location filter text
|
||||
refresh_interval: number; // auto-refresh interval in seconds (0 = disabled)
|
||||
|
||||
// --- Report display preferences (user-controlled, persisted) ---
|
||||
rpt__session_no_files: boolean; // show "sessions with no files" report section
|
||||
rpt__session_poc_agree: boolean; // show "session POC agreement" report section
|
||||
rpt__session_no_bio: boolean; // show "sessions with no bio" report section
|
||||
rpt__presenter_agree: boolean; // show "presenter agreement" report section
|
||||
qry__file_purpose: string | null; // filter report files by purpose slug
|
||||
qry__files_min_size: number | null; // filter report files by minimum size (bytes)
|
||||
qry__session_sort: string; // sort order for session report
|
||||
qry__presenter_sort: string; // sort order for presenter report
|
||||
|
||||
// --- Content / panel visibility (user preferences) ---
|
||||
expand__menu_opts: boolean;
|
||||
show_content__device_description: boolean;
|
||||
show_content__event_view: string | null;
|
||||
show_content__location_description: boolean;
|
||||
show_content__location_devices_sessions: 'sessions' | 'devices' | null;
|
||||
show_content__location_qr: boolean;
|
||||
show_content__presentation_description: boolean;
|
||||
show_content__presentation_description: boolean; // per-presentation expand toggle
|
||||
show_content__presenter_page_help: boolean;
|
||||
show_content__presenter_view: string | null;
|
||||
show_content__presenter_qr: boolean;
|
||||
@@ -43,34 +137,77 @@ export interface PresMgmtLocState {
|
||||
show_content__session_search_room_name: boolean;
|
||||
show_content__session_view: string | null;
|
||||
show_content__session_qr: boolean;
|
||||
hide__session_code: boolean;
|
||||
hide__session_msg: boolean;
|
||||
hide__session_poc: boolean;
|
||||
hide__session_poc_biography: boolean;
|
||||
hide__presenter_biography: boolean;
|
||||
hide__session_li_location_field: boolean;
|
||||
show__session_li_poc_field: boolean;
|
||||
hide__launcher_link_legacy: boolean;
|
||||
hide__launcher_link: boolean;
|
||||
hide__location_link: boolean;
|
||||
show_content__disabled_files: boolean;
|
||||
show_content__hidden_files: boolean;
|
||||
show_content__hidden_presentations: boolean;
|
||||
show_content__hidden_presenters: boolean;
|
||||
show_content__hidden_sessions: boolean;
|
||||
|
||||
// --- List/table column visibility (user preferences) ---
|
||||
hide__device_code: boolean;
|
||||
hide__locations_msg: boolean;
|
||||
hide__session_li_location_field: boolean;
|
||||
show__session_li_poc_field: boolean;
|
||||
// Launcher/location links in session list
|
||||
hide__launcher_link_legacy: boolean; // Flask/legacy launcher
|
||||
hide__launcher_link: boolean; // SvelteKit launcher
|
||||
hide__location_link: boolean;
|
||||
show__direct_download: boolean;
|
||||
// null = use server-side default.
|
||||
|
||||
// --- Menu visibility (null = use server-side default) ---
|
||||
show_menu__presenter: boolean | null;
|
||||
show_menu__session: boolean | null;
|
||||
show_menu__session_search: boolean | null;
|
||||
show_menu__event_reports: boolean | null;
|
||||
show_report: string | null;
|
||||
|
||||
// --- Opt-out toggles ---
|
||||
disable_submit__opt_out: boolean;
|
||||
submit_status__opt_out: string | null;
|
||||
|
||||
// --- Device/location scratch space ---
|
||||
device_kv: Record<string, any>;
|
||||
location_kv: Record<string, any>;
|
||||
|
||||
// --- Synced from PressMgmtRemoteCfg (overwritten by sync_config__event_pres_mgmt) ---
|
||||
// These mirror PressMgmtRemoteCfg fields and are written during event load.
|
||||
// Do not set these manually — they will be overridden when lock_config=true.
|
||||
label__person_external_id: string;
|
||||
label__presenter_external_id: string;
|
||||
label__session_poc_type: string;
|
||||
label__session_poc_name: string;
|
||||
hide__location_code: boolean;
|
||||
hide__presentation_code: boolean;
|
||||
hide__presentation_datetime: boolean;
|
||||
hide__presentation_description: boolean;
|
||||
hide__presenter_code: boolean;
|
||||
hide__presenter_biography: boolean;
|
||||
hide__session_code: boolean;
|
||||
hide__session_description: boolean;
|
||||
hide__session_location: boolean;
|
||||
hide__session_msg: boolean;
|
||||
hide__session_poc: boolean;
|
||||
hide__session_poc_biography: boolean;
|
||||
hide__session_poc_profile: boolean;
|
||||
hide__session_poc_profile_pic: boolean;
|
||||
show__copy_access_link: boolean;
|
||||
show__email_access_link: boolean;
|
||||
show__launcher_link: boolean;
|
||||
show__launcher_link_legacy: boolean;
|
||||
require__presenter_agree: boolean;
|
||||
require__session_agree: boolean;
|
||||
limit__navigation: boolean;
|
||||
limit__options: boolean;
|
||||
file_purpose_option_kv: Record<
|
||||
string,
|
||||
{ name: string; disabled?: boolean; hidden?: boolean }
|
||||
> | null;
|
||||
hide__report_kv: Record<string, boolean>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// In-memory session state — resets on page load (not persisted)
|
||||
// ---------------------------------------------------------------------------
|
||||
export interface PresMgmtSessState {
|
||||
presenter__updated_on: string | null;
|
||||
session_updated_on: string | null;
|
||||
@@ -114,40 +251,57 @@ export interface PresMgmtSessState {
|
||||
tmp_val__filename_no_ext: string | null;
|
||||
}
|
||||
|
||||
// Persisted pres_mgmt config — survives browser sessions.
|
||||
export const pres_mgmt_loc_defaults: PresMgmtLocState = {
|
||||
sync_local_config: false,
|
||||
lock_config: true,
|
||||
// ---------------------------------------------------------------------------
|
||||
// Defaults
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Persisted pres_mgmt local config — survives browser sessions.
|
||||
export const pres_mgmt_loc_defaults: PresMgmtLocState = {
|
||||
// System / lock state
|
||||
sync_local_config: false,
|
||||
lock_config: false,
|
||||
|
||||
// Query / search
|
||||
datetime_format: 'datetime_12_long',
|
||||
time_format: 'time_12_short',
|
||||
time_hours: 12, // 12 or 24
|
||||
|
||||
qry_enabled: 'enabled', // 'all' | 'disabled' | 'enabled'
|
||||
qry_hidden: 'not_hidden', // 'all' | 'hidden' | 'not_hidden'
|
||||
time_hours: 12,
|
||||
qry_enabled: 'enabled',
|
||||
qry_hidden: 'not_hidden',
|
||||
qry_limit__files: 75,
|
||||
qry_limit__presentations: 25,
|
||||
qry_limit__presenters: 500,
|
||||
qry_limit__sessions: 100,
|
||||
qry_max: 500, // Maximum value the limit is allowed to be set to.
|
||||
qry_max: 500,
|
||||
qry__files_offset_seconds: null,
|
||||
qry__files_sort: 'created_on',
|
||||
|
||||
// Search stabilization — version bump clears cache and re-runs (Standardized Pattern 2026-01-27).
|
||||
search_version: 0,
|
||||
qry__remote_first: false,
|
||||
|
||||
qry_and__file_count: true, // When true, only sessions with at least 1 file are returned.
|
||||
|
||||
qry_and__file_count: true,
|
||||
save_search_text: true,
|
||||
saved_search__session: null,
|
||||
saved_search__session_location_name: null,
|
||||
fulltext_search_qry_str: null,
|
||||
location_name_qry_str: null,
|
||||
refresh_interval: 0,
|
||||
|
||||
require__presenter_agree: false,
|
||||
require__session_agree: false,
|
||||
// Report display preferences
|
||||
rpt__session_no_files: true,
|
||||
rpt__session_poc_agree: false,
|
||||
rpt__session_no_bio: true,
|
||||
rpt__presenter_agree: true,
|
||||
qry__file_purpose: null,
|
||||
qry__files_min_size: null,
|
||||
qry__session_sort: 'name',
|
||||
qry__presenter_sort: 'name',
|
||||
|
||||
// Content / panel visibility
|
||||
expand__menu_opts: false,
|
||||
show_content__device_description: false,
|
||||
show_content__location_description: false,
|
||||
show_content__location_devices_sessions: null,
|
||||
show_content__event_view: null,
|
||||
show_content__location_qr: false,
|
||||
show_content__presentation_description: false, // Global toggle — applies to all presentations.
|
||||
show_content__presentation_description: false,
|
||||
show_content__presenter_page_help: true,
|
||||
show_content__presenter_view: null,
|
||||
show_content__presenter_qr: false,
|
||||
@@ -160,100 +314,108 @@ export const pres_mgmt_loc_defaults: PresMgmtLocState = {
|
||||
show_content__session_search_room_name: false,
|
||||
show_content__session_view: null,
|
||||
show_content__session_qr: false,
|
||||
hide__session_code: false, // Default visible; toggle in ae_comp__events_menu_opts to hide
|
||||
hide__session_msg: true,
|
||||
hide__session_poc: true,
|
||||
hide__session_poc_biography: true,
|
||||
hide__presenter_biography: true,
|
||||
|
||||
// List/table-specific visibility.
|
||||
hide__session_li_location_field: false,
|
||||
show__session_li_poc_field: false,
|
||||
hide__launcher_link_legacy: true, // Flask version.
|
||||
hide__launcher_link: true, // SvelteKit version.
|
||||
hide__location_link: true,
|
||||
|
||||
show_content__disabled_files: false,
|
||||
show_content__hidden_files: false,
|
||||
show_content__hidden_presentations: false,
|
||||
show_content__hidden_presenters: false,
|
||||
show_content__hidden_sessions: false,
|
||||
|
||||
// List/table column visibility
|
||||
hide__device_code: false,
|
||||
hide__locations_msg: false,
|
||||
hide__session_li_location_field: false,
|
||||
show__session_li_poc_field: false,
|
||||
hide__launcher_link_legacy: true,
|
||||
hide__launcher_link: true,
|
||||
hide__location_link: true,
|
||||
show__direct_download: false,
|
||||
|
||||
// Menu visibility — null means "use server-side default".
|
||||
// Use "hide" prefix for any new additions here.
|
||||
// Menu visibility
|
||||
show_menu__presenter: null,
|
||||
show_menu__session: null,
|
||||
show_menu__session_search: null,
|
||||
show_menu__event_reports: null,
|
||||
|
||||
show_report: null,
|
||||
|
||||
// Opt-out
|
||||
disable_submit__opt_out: true,
|
||||
submit_status__opt_out: null,
|
||||
|
||||
// Scratch space
|
||||
device_kv: {},
|
||||
location_kv: {}
|
||||
location_kv: {},
|
||||
|
||||
// Synced from remote (defaults apply until first event load)
|
||||
label__person_external_id: 'External ID',
|
||||
label__presenter_external_id: 'External ID',
|
||||
label__session_poc_type: 'poc',
|
||||
label__session_poc_name: 'Point of Contact',
|
||||
hide__location_code: false,
|
||||
hide__presentation_code: false,
|
||||
hide__presentation_datetime: false,
|
||||
hide__presentation_description: false,
|
||||
hide__presenter_code: false,
|
||||
hide__presenter_biography: true,
|
||||
hide__session_code: false,
|
||||
hide__session_description: false,
|
||||
hide__session_location: false,
|
||||
hide__session_msg: true,
|
||||
hide__session_poc: true,
|
||||
hide__session_poc_biography: true,
|
||||
hide__session_poc_profile: false,
|
||||
hide__session_poc_profile_pic: false,
|
||||
show__copy_access_link: false,
|
||||
show__email_access_link: false,
|
||||
show__launcher_link: false,
|
||||
show__launcher_link_legacy: false,
|
||||
require__presenter_agree: false,
|
||||
require__session_agree: false,
|
||||
limit__navigation: false,
|
||||
limit__options: false,
|
||||
file_purpose_option_kv: null,
|
||||
hide__report_kv: {}
|
||||
};
|
||||
|
||||
// In-memory pres_mgmt state — resets on page load.
|
||||
export const pres_mgmt_sess_defaults: PresMgmtSessState = {
|
||||
presenter__updated_on: null,
|
||||
session_updated_on: null,
|
||||
|
||||
location_name_qry_str: null,
|
||||
fulltext_search_qry_str: null,
|
||||
status_qry__search: null,
|
||||
|
||||
disable_submit__event_file_obj: true,
|
||||
|
||||
show_form__search: true,
|
||||
show_form__search_results: true,
|
||||
|
||||
show_content__agree_text: false,
|
||||
show_content__presenter_start: false,
|
||||
show_content__presentation_description: false, // Per-presentation (keyed by event_presentation_id_random).
|
||||
|
||||
show_content__presentation_description: false,
|
||||
show_report: null,
|
||||
|
||||
show_field_edit__filename: false, // For file rename.
|
||||
|
||||
show_field_edit__filename: false,
|
||||
new_upload_list: null,
|
||||
files_uploading_count: null,
|
||||
|
||||
qry_limit__files: 75,
|
||||
qry_limit__presentations: 25,
|
||||
qry_limit__presenters: 500,
|
||||
qry_limit__sessions: 100,
|
||||
|
||||
show_fields__presentation: true,
|
||||
show_fields__session: true,
|
||||
|
||||
show_modal__presenter_agree: false,
|
||||
show__session_poc_profile: false,
|
||||
show_modal__session_poc_agree: false,
|
||||
|
||||
show__edit_location: {},
|
||||
show__edit_poc_person: {},
|
||||
|
||||
show__view_alert: {}, // Key-value: show alert by ID.
|
||||
show__edit_alert_msg: {}, // Key-value: show edit alert msg by ID.
|
||||
tmp__alert_msg: {}, // Key-value: temp alert msg content by ID.
|
||||
|
||||
session_qr_url: {}, // Key-value: session_id → URL string.
|
||||
|
||||
show__view_alert: {},
|
||||
show__edit_alert_msg: {},
|
||||
tmp__alert_msg: {},
|
||||
session_qr_url: {},
|
||||
status_rpt: {
|
||||
recent_files: null,
|
||||
presenters_agree: null,
|
||||
presenters_biography: null
|
||||
},
|
||||
|
||||
rpt__session_no_files: true,
|
||||
rpt__session_poc_agree: false, // Default to false for new events.
|
||||
rpt__session_poc_agree: false,
|
||||
rpt__session_no_bio: true,
|
||||
|
||||
rpt__presenter_agree: true,
|
||||
|
||||
tmp_val__filename_no_ext: null // For file rename.
|
||||
tmp_val__filename_no_ext: null
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
export const AE_LOC_VERSION = 2; // Bumped 2026-03-30: force-clear stale site_cfg_json (novi_idaa_api_key missing bug)
|
||||
export const AE_EVENTS_LOC_VERSION = 1;
|
||||
export const AE_IDAA_LOC_VERSION = 1; // Added 2026-03-30: was missing, no wipe mechanism existed
|
||||
export const AE_PRES_MGMT_LOC_VERSION = 1; // Added 2026-04-02: new standalone PersistedState store
|
||||
|
||||
// Version check side-effect: runs on import, before any persisted() call.
|
||||
// Guard presence of `localStorage` and its functions for safety (SSR, Node flags).
|
||||
@@ -44,6 +45,10 @@ if (
|
||||
_check_and_wipe('ae_loc', AE_LOC_VERSION);
|
||||
_check_and_wipe('ae_events_loc', AE_EVENTS_LOC_VERSION);
|
||||
_check_and_wipe('ae_idaa_loc', AE_IDAA_LOC_VERSION);
|
||||
// ae_pres_mgmt_loc uses PersistedState (runed) which stores raw JSON without a __version
|
||||
// field. The _check_and_wipe mechanism requires __version in the stored data — do NOT
|
||||
// add it here until pres_mgmt_loc_defaults includes __version. For now the key is new
|
||||
// (no stale data exists) so no wipe is needed.
|
||||
}
|
||||
|
||||
function _check_and_wipe(key: string, expected_version: number): void {
|
||||
|
||||
Reference in New Issue
Block a user