Last round of prettier: npx prettier --write src/
This commit is contained in:
@@ -43,7 +43,9 @@ export const delete_object = async function delete_object({
|
||||
// Construct the URL with query parameters
|
||||
const url = new URL(endpoint, api_cfg['base_url']);
|
||||
if (params) {
|
||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
||||
Object.keys(params).forEach((key) =>
|
||||
url.searchParams.append(key, params[key])
|
||||
);
|
||||
}
|
||||
|
||||
// Clean and merge headers without mutating the original api_cfg
|
||||
@@ -70,8 +72,13 @@ export const delete_object = async function delete_object({
|
||||
}
|
||||
|
||||
// Auto-inject Authorization header if JWT is present but header is missing
|
||||
const jwt = headers_cleaned['jwt'] || headers_cleaned['JWT'] || api_cfg['jwt'];
|
||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
||||
const jwt =
|
||||
headers_cleaned['jwt'] || headers_cleaned['JWT'] || api_cfg['jwt'];
|
||||
if (
|
||||
jwt &&
|
||||
!headers_cleaned['Authorization'] &&
|
||||
!headers_cleaned['authorization']
|
||||
) {
|
||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||
}
|
||||
|
||||
@@ -93,20 +100,26 @@ export const delete_object = async function delete_object({
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.error(`API DELETE request timed out after ${timeout}ms.`);
|
||||
console.error(
|
||||
`API DELETE request timed out after ${timeout}ms.`
|
||||
);
|
||||
controller.abort();
|
||||
}, timeout);
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
method: 'DELETE',
|
||||
headers: headers_cleaned,
|
||||
body: Object.keys(data).length > 0 ? JSON.stringify(data) : undefined,
|
||||
body:
|
||||
Object.keys(data).length > 0
|
||||
? JSON.stringify(data)
|
||||
: undefined,
|
||||
signal: controller.signal
|
||||
};
|
||||
|
||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
||||
error: any
|
||||
) {
|
||||
const response = await fetch_method(
|
||||
url.toString(),
|
||||
fetchOptions
|
||||
).catch(function (error: any) {
|
||||
console.log(
|
||||
'API DELETE Object *fetch* request was aborted or failed in an unexpected way.',
|
||||
error
|
||||
@@ -121,7 +134,9 @@ export const delete_object = async function delete_object({
|
||||
}
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Response: status=${response.status} attempt=${attempt}`);
|
||||
console.log(
|
||||
`Response: status=${response.status} attempt=${attempt}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -129,15 +144,20 @@ export const delete_object = async function delete_object({
|
||||
console.warn('404 Not Found. Returning null.');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const errorBody = await response.text();
|
||||
console.error(`HTTP error! status: ${response.status}`, errorBody);
|
||||
console.error(
|
||||
`HTTP error! status: ${response.status}`,
|
||||
errorBody
|
||||
);
|
||||
|
||||
if (response.status >= 400 && response.status < 404) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new Error(`HTTP error! status: ${response.status} - ${errorBody}`);
|
||||
throw new Error(
|
||||
`HTTP error! status: ${response.status} - ${errorBody}`
|
||||
);
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
@@ -148,7 +168,11 @@ export const delete_object = async function delete_object({
|
||||
|
||||
// Return the response data or metadata
|
||||
// Robustly handle V3 response envelopes
|
||||
return return_meta ? json : (json.data !== undefined ? json.data : json);
|
||||
return return_meta
|
||||
? json
|
||||
: json.data !== undefined
|
||||
? json.data
|
||||
: json;
|
||||
} catch (error) {
|
||||
console.error(`API DELETE error on attempt ${attempt}:`, error);
|
||||
|
||||
|
||||
@@ -44,7 +44,9 @@ export async function get_ae_obj_id_crud({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** get_ae_obj_id_crud() *** Type: ${obj_type} ID: ${obj_id}`);
|
||||
console.log(
|
||||
`*** get_ae_obj_id_crud() *** Type: ${obj_type} ID: ${obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
// V3 Standard: Unified endpoint for all objects
|
||||
@@ -77,7 +79,10 @@ export async function get_ae_obj_id_crud({
|
||||
log_lvl: log_lvl,
|
||||
return_meta: return_meta
|
||||
}).catch(function (error: any) {
|
||||
console.error(`API GET CRUD object ID request failed for ${obj_type}/${obj_id}`, error);
|
||||
console.error(
|
||||
`API GET CRUD object ID request failed for ${obj_type}/${obj_id}`,
|
||||
error
|
||||
);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -86,4 +91,4 @@ export async function get_ae_obj_id_crud({
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,10 @@ interface GetAeObjLiV3Params {
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
||||
order_by_li?:
|
||||
| Record<string, 'ASC' | 'DESC'>
|
||||
| Record<string, 'ASC' | 'DESC'>[]
|
||||
| null;
|
||||
delay_ms?: number;
|
||||
params?: key_val;
|
||||
headers?: key_val;
|
||||
@@ -162,7 +165,10 @@ interface GetNestedObjLiV3Params {
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
||||
order_by_li?:
|
||||
| Record<string, 'ASC' | 'DESC'>
|
||||
| Record<string, 'ASC' | 'DESC'>[]
|
||||
| null;
|
||||
delay_ms?: number;
|
||||
log_lvl?: number;
|
||||
}
|
||||
@@ -206,4 +212,4 @@ export async function get_nested_obj_li({
|
||||
params,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ export async function get_data_store({
|
||||
log_lvl = 0
|
||||
}: GetDataStoreV3Params): Promise<any> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** get_data_store() *** code=${code} no_account_id=${no_account_id}`);
|
||||
console.log(
|
||||
`*** get_data_store() *** code=${code} no_account_id=${no_account_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const endpoint = `/v3/data_store/code/${code}`;
|
||||
|
||||
@@ -41,7 +41,9 @@ export const get_object = async function get_object({
|
||||
retry_count?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`);
|
||||
console.log(
|
||||
`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`
|
||||
);
|
||||
console.log('Params:', params);
|
||||
if (log_lvl > 1) {
|
||||
console.log('Data:', data);
|
||||
@@ -55,7 +57,10 @@ export const get_object = async function get_object({
|
||||
|
||||
// FAIL FAST: Check if we are explicitly offline to avoid long browser timeouts
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||
if (log_lvl) console.log('get_object: Browser is offline. Failing fast to allow cache fallback.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'get_object: Browser is offline. Failing fast to allow cache fallback.'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -64,7 +69,9 @@ export const get_object = async function get_object({
|
||||
}
|
||||
|
||||
const url = new URL(endpoint, api_cfg['base_url']);
|
||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
||||
Object.keys(params).forEach((key) =>
|
||||
url.searchParams.append(key, params[key])
|
||||
);
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
@@ -96,14 +103,19 @@ export const get_object = async function get_object({
|
||||
}
|
||||
|
||||
// Handle "Bootstrap Paradox" for unauthenticated requests
|
||||
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||
const is_valid_bypass = bypass_val === 'bypass' ||
|
||||
bypass_val === 'Nothing to See Here' ||
|
||||
params['key'] ||
|
||||
bypass_val === 'direct-download';
|
||||
const bypass_val =
|
||||
merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||
const is_valid_bypass =
|
||||
bypass_val === 'bypass' ||
|
||||
bypass_val === 'Nothing to See Here' ||
|
||||
params['key'] ||
|
||||
bypass_val === 'direct-download';
|
||||
|
||||
if (is_valid_bypass) {
|
||||
if (log_lvl > 1) console.log('api_get_object: Valid bypass detected. Stripping account ID context.');
|
||||
if (log_lvl > 1)
|
||||
console.log(
|
||||
'api_get_object: Valid bypass detected. Stripping account ID context.'
|
||||
);
|
||||
delete merged_headers['x-account-id'];
|
||||
delete merged_headers['x_account_id'];
|
||||
} else {
|
||||
@@ -126,11 +138,12 @@ export const get_object = async function get_object({
|
||||
}
|
||||
|
||||
// Auto-inject Authorization header if JWT is present but header is missing
|
||||
let jwt = headers_cleaned['jwt'] ||
|
||||
headers_cleaned['JWT'] ||
|
||||
api_cfg['jwt'] ||
|
||||
api_cfg['headers']?.['jwt'] ||
|
||||
api_cfg['headers']?.['JWT'];
|
||||
let jwt =
|
||||
headers_cleaned['jwt'] ||
|
||||
headers_cleaned['JWT'] ||
|
||||
api_cfg['jwt'] ||
|
||||
api_cfg['headers']?.['jwt'] ||
|
||||
api_cfg['headers']?.['JWT'];
|
||||
|
||||
// Final Fallback: Direct check of primary ae_loc key
|
||||
if (!jwt && typeof localStorage !== 'undefined') {
|
||||
@@ -145,7 +158,11 @@ export const get_object = async function get_object({
|
||||
}
|
||||
}
|
||||
|
||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
||||
if (
|
||||
jwt &&
|
||||
!headers_cleaned['Authorization'] &&
|
||||
!headers_cleaned['authorization']
|
||||
) {
|
||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||
}
|
||||
|
||||
@@ -174,18 +191,29 @@ export const get_object = async function get_object({
|
||||
for (let attempt = 1; attempt <= retry_count; attempt++) {
|
||||
// FAIL FAST: Check if we are explicitly offline to avoid long browser timeouts
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||
if (log_lvl) console.log(`get_object: Browser is offline (attempt ${attempt}). Failing fast to allow cache fallback.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`get_object: Browser is offline (attempt ${attempt}). Failing fast to allow cache fallback.`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
||||
error: any
|
||||
) {
|
||||
const response = await fetch_method(
|
||||
url.toString(),
|
||||
fetchOptions
|
||||
).catch(function (error: any) {
|
||||
// SILENCE NOISE: Aborted requests (common in SWR/Background loads) shouldn't spam logs
|
||||
if (error.name === 'AbortError' || error.message?.includes('aborted') || error.name === 'TypeError') {
|
||||
if (
|
||||
error.name === 'AbortError' ||
|
||||
error.message?.includes('aborted') ||
|
||||
error.name === 'TypeError'
|
||||
) {
|
||||
if (log_lvl > 1) {
|
||||
console.log('API GET: Request was aborted or terminated by browser. This is expected during navigation.', error);
|
||||
console.log(
|
||||
'API GET: Request was aborted or terminated by browser. This is expected during navigation.',
|
||||
error
|
||||
);
|
||||
}
|
||||
return error; // Return error to be handled below
|
||||
}
|
||||
@@ -199,11 +227,19 @@ export const get_object = async function get_object({
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// Check if we should stop due to abort or network failure
|
||||
if (response instanceof Error || (response && (response.name === 'TypeError' || response.name === 'AbortError'))) {
|
||||
if (
|
||||
response instanceof Error ||
|
||||
(response &&
|
||||
(response.name === 'TypeError' ||
|
||||
response.name === 'AbortError'))
|
||||
) {
|
||||
// If it was an explicit abort, definitely stop
|
||||
if (response.name === 'AbortError') return false;
|
||||
|
||||
if (log_lvl > 1) console.log('API GET Object: Detected NetworkError or TypeError. Failing fast.');
|
||||
if (log_lvl > 1)
|
||||
console.log(
|
||||
'API GET Object: Detected NetworkError or TypeError. Failing fast.'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -231,24 +267,45 @@ export const get_object = async function get_object({
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
if (log_lvl) {
|
||||
console.log('The response was a 404 not found "error". Returning null.');
|
||||
console.log(
|
||||
'The response was a 404 not found "error". Returning null.'
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
||||
if (response.status === 400 || response.status === 401 || response.status === 403 || response.status === 422) {
|
||||
if (log_lvl) console.error(`API Client Failure (${response.status}). Failing fast.`);
|
||||
if (
|
||||
response.status === 400 ||
|
||||
response.status === 401 ||
|
||||
response.status === 403 ||
|
||||
response.status === 422
|
||||
) {
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`API Client Failure (${response.status}). Failing fast.`
|
||||
);
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
console.warn(`AUTH DIAGNOSTICS: Headers sent for ${endpoint}:`, {
|
||||
has_auth: !!headers_cleaned['Authorization'],
|
||||
has_api_key: !!headers_cleaned['x-aether-api-key'],
|
||||
has_account_id: !!headers_cleaned['x-account-id'],
|
||||
jwt_preview: jwt ? `${jwt.slice(0, 8)}...` : 'MISSING'
|
||||
});
|
||||
console.warn(
|
||||
`AUTH DIAGNOSTICS: Headers sent for ${endpoint}:`,
|
||||
{
|
||||
has_auth: !!headers_cleaned['Authorization'],
|
||||
has_api_key:
|
||||
!!headers_cleaned['x-aether-api-key'],
|
||||
has_account_id:
|
||||
!!headers_cleaned['x-account-id'],
|
||||
jwt_preview: jwt
|
||||
? `${jwt.slice(0, 8)}...`
|
||||
: 'MISSING'
|
||||
}
|
||||
);
|
||||
// Signal the root layout to show the session-expired banner.
|
||||
if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
||||
if (browser)
|
||||
ae_auth_error.set({
|
||||
type: 'expired',
|
||||
ts: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// Structured Error Handling (V3): Attempt to get rich error metadata
|
||||
@@ -259,7 +316,11 @@ export const get_object = async function get_object({
|
||||
// Not JSON
|
||||
}
|
||||
|
||||
if (log_lvl) console.log('The response was not ok. Structured Error Check:', error_json);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'The response was not ok. Structured Error Check:',
|
||||
error_json
|
||||
);
|
||||
|
||||
if (error_json?.meta?.details) {
|
||||
return error_json;
|
||||
@@ -273,7 +334,10 @@ export const get_object = async function get_object({
|
||||
status_code: response.status,
|
||||
details: {
|
||||
category: 'validation',
|
||||
message: typeof error_json.detail === 'string' ? error_json.detail : JSON.stringify(error_json.detail),
|
||||
message:
|
||||
typeof error_json.detail === 'string'
|
||||
? error_json.detail
|
||||
: JSON.stringify(error_json.detail),
|
||||
raw: error_json.detail
|
||||
}
|
||||
}
|
||||
@@ -307,7 +371,9 @@ export const get_object = async function get_object({
|
||||
chunks.push(value);
|
||||
receivedLength += value.length;
|
||||
|
||||
const percent_completed = Math.round((receivedLength * 100) / contentLength);
|
||||
const percent_completed = Math.round(
|
||||
(receivedLength * 100) / contentLength
|
||||
);
|
||||
if (log_lvl > 1) {
|
||||
console.log(
|
||||
'GET Blob Progress:',
|
||||
@@ -359,7 +425,10 @@ export const get_object = async function get_object({
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`API GET object request *fetch* error on attempt ${attempt}:`, error);
|
||||
console.log(
|
||||
`API GET object request *fetch* error on attempt ${attempt}:`,
|
||||
error
|
||||
);
|
||||
|
||||
if (attempt === retry_count) {
|
||||
console.log('Max retry attempts reached. Returning false.');
|
||||
|
||||
@@ -45,7 +45,9 @@ export const patch_object = async function patch_object({
|
||||
// Construct the URL with query parameters
|
||||
const url = new URL(endpoint, api_cfg['base_url']);
|
||||
if (params) {
|
||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
||||
Object.keys(params).forEach((key) =>
|
||||
url.searchParams.append(key, params[key])
|
||||
);
|
||||
}
|
||||
|
||||
// Clean and merge headers without mutating the original api_cfg
|
||||
@@ -75,14 +77,19 @@ export const patch_object = async function patch_object({
|
||||
}
|
||||
|
||||
// Handle "Bootstrap Paradox" for unauthenticated requests
|
||||
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||
const is_valid_bypass = bypass_val === 'bypass' ||
|
||||
bypass_val === 'Nothing to See Here' ||
|
||||
params['key'] ||
|
||||
bypass_val === 'direct-download';
|
||||
const bypass_val =
|
||||
merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||
const is_valid_bypass =
|
||||
bypass_val === 'bypass' ||
|
||||
bypass_val === 'Nothing to See Here' ||
|
||||
params['key'] ||
|
||||
bypass_val === 'direct-download';
|
||||
|
||||
if (is_valid_bypass) {
|
||||
if (log_lvl > 1) console.log('api_patch_object: Valid bypass detected. Stripping account ID context.');
|
||||
if (log_lvl > 1)
|
||||
console.log(
|
||||
'api_patch_object: Valid bypass detected. Stripping account ID context.'
|
||||
);
|
||||
delete merged_headers['x-account-id'];
|
||||
delete merged_headers['x_account_id'];
|
||||
} else {
|
||||
@@ -104,11 +111,12 @@ export const patch_object = async function patch_object({
|
||||
}
|
||||
|
||||
// Auto-inject Authorization header if JWT is present but header is missing
|
||||
let jwt = headers_cleaned['jwt'] ||
|
||||
headers_cleaned['JWT'] ||
|
||||
api_cfg['jwt'] ||
|
||||
api_cfg['headers']?.['jwt'] ||
|
||||
api_cfg['headers']?.['JWT'];
|
||||
let jwt =
|
||||
headers_cleaned['jwt'] ||
|
||||
headers_cleaned['JWT'] ||
|
||||
api_cfg['jwt'] ||
|
||||
api_cfg['headers']?.['jwt'] ||
|
||||
api_cfg['headers']?.['JWT'];
|
||||
|
||||
// Final Fallback: Direct check of primary ae_loc key
|
||||
if (!jwt && typeof localStorage !== 'undefined') {
|
||||
@@ -123,7 +131,11 @@ export const patch_object = async function patch_object({
|
||||
}
|
||||
}
|
||||
|
||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
||||
if (
|
||||
jwt &&
|
||||
!headers_cleaned['Authorization'] &&
|
||||
!headers_cleaned['authorization']
|
||||
) {
|
||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||
}
|
||||
|
||||
@@ -145,7 +157,9 @@ export const patch_object = async function patch_object({
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.error(`API PATCH request timed out after ${timeout}ms.`);
|
||||
console.error(
|
||||
`API PATCH request timed out after ${timeout}ms.`
|
||||
);
|
||||
controller.abort();
|
||||
}, timeout);
|
||||
|
||||
@@ -156,9 +170,10 @@ export const patch_object = async function patch_object({
|
||||
signal: controller.signal
|
||||
};
|
||||
|
||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
||||
error: any
|
||||
) {
|
||||
const response = await fetch_method(
|
||||
url.toString(),
|
||||
fetchOptions
|
||||
).catch(function (error: any) {
|
||||
console.log(
|
||||
'API PATCH Object *fetch* request was aborted or failed in an unexpected way.',
|
||||
error
|
||||
@@ -173,30 +188,53 @@ export const patch_object = async function patch_object({
|
||||
}
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Response: status=${response.status} attempt=${attempt}`);
|
||||
console.log(
|
||||
`Response: status=${response.status} attempt=${attempt}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
if (log_lvl) {
|
||||
console.log('The response was a 404 not found "error". Returning null.');
|
||||
console.log(
|
||||
'The response was a 404 not found "error". Returning null.'
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
||||
if (response.status === 400 || response.status === 401 || response.status === 403 || response.status === 422) {
|
||||
if (log_lvl) console.error(`API Client Failure (${response.status}). Failing fast.`);
|
||||
if (
|
||||
response.status === 400 ||
|
||||
response.status === 401 ||
|
||||
response.status === 403 ||
|
||||
response.status === 422
|
||||
) {
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`API Client Failure (${response.status}). Failing fast.`
|
||||
);
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
console.warn(`AUTH DIAGNOSTICS (PATCH): Headers sent for ${endpoint}:`, {
|
||||
has_auth: !!headers_cleaned['Authorization'],
|
||||
has_api_key: !!headers_cleaned['x-aether-api-key'],
|
||||
has_account_id: !!headers_cleaned['x-account-id'],
|
||||
jwt_preview: jwt ? `${jwt.slice(0, 8)}...` : 'MISSING'
|
||||
});
|
||||
console.warn(
|
||||
`AUTH DIAGNOSTICS (PATCH): Headers sent for ${endpoint}:`,
|
||||
{
|
||||
has_auth: !!headers_cleaned['Authorization'],
|
||||
has_api_key:
|
||||
!!headers_cleaned['x-aether-api-key'],
|
||||
has_account_id:
|
||||
!!headers_cleaned['x-account-id'],
|
||||
jwt_preview: jwt
|
||||
? `${jwt.slice(0, 8)}...`
|
||||
: 'MISSING'
|
||||
}
|
||||
);
|
||||
// Signal the root layout to show the session-expired banner.
|
||||
if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
||||
if (browser)
|
||||
ae_auth_error.set({
|
||||
type: 'expired',
|
||||
ts: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// Structured Error Handling (V3): Attempt to get rich error metadata
|
||||
@@ -207,7 +245,11 @@ export const patch_object = async function patch_object({
|
||||
// Not JSON
|
||||
}
|
||||
|
||||
if (log_lvl) console.log('The response was not ok. Structured Error Check:', error_json);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'The response was not ok. Structured Error Check:',
|
||||
error_json
|
||||
);
|
||||
|
||||
if (error_json?.meta?.details) {
|
||||
return error_json;
|
||||
@@ -221,7 +263,10 @@ export const patch_object = async function patch_object({
|
||||
status_code: response.status,
|
||||
details: {
|
||||
category: 'validation',
|
||||
message: typeof error_json.detail === 'string' ? error_json.detail : JSON.stringify(error_json.detail),
|
||||
message:
|
||||
typeof error_json.detail === 'string'
|
||||
? error_json.detail
|
||||
: JSON.stringify(error_json.detail),
|
||||
raw: error_json.detail
|
||||
}
|
||||
}
|
||||
@@ -242,7 +287,11 @@ export const patch_object = async function patch_object({
|
||||
|
||||
// Return the response data or metadata
|
||||
// Robustly handle V3 response envelopes
|
||||
return return_meta ? json : (json.data !== undefined ? json.data : json);
|
||||
return return_meta
|
||||
? json
|
||||
: json.data !== undefined
|
||||
? json.data
|
||||
: json;
|
||||
} catch (error) {
|
||||
console.error(`API PATCH error on attempt ${attempt}:`, error);
|
||||
|
||||
|
||||
@@ -33,7 +33,11 @@ export async function create_ae_obj({
|
||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||
const cleaned_fields = { ...fields };
|
||||
for (const key in cleaned_fields) {
|
||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
||||
if (
|
||||
key.endsWith('_json') &&
|
||||
cleaned_fields[key] !== null &&
|
||||
typeof cleaned_fields[key] === 'object'
|
||||
) {
|
||||
if (log_lvl) console.log(`Auto-serializing field: ${key}`);
|
||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||
}
|
||||
@@ -94,7 +98,11 @@ export async function create_nested_obj({
|
||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||
const cleaned_fields = { ...fields };
|
||||
for (const key in cleaned_fields) {
|
||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
||||
if (
|
||||
key.endsWith('_json') &&
|
||||
cleaned_fields[key] !== null &&
|
||||
typeof cleaned_fields[key] === 'object'
|
||||
) {
|
||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||
}
|
||||
}
|
||||
@@ -140,7 +148,11 @@ export async function update_ae_obj({
|
||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||
const cleaned_fields = { ...fields };
|
||||
for (const key in cleaned_fields) {
|
||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
||||
if (
|
||||
key.endsWith('_json') &&
|
||||
cleaned_fields[key] !== null &&
|
||||
typeof cleaned_fields[key] === 'object'
|
||||
) {
|
||||
if (log_lvl > 1) console.log(`Auto-serializing field: ${key}`);
|
||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||
}
|
||||
@@ -202,7 +214,11 @@ export async function update_nested_obj({
|
||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||
const cleaned_fields = { ...fields };
|
||||
for (const key in cleaned_fields) {
|
||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
||||
if (
|
||||
key.endsWith('_json') &&
|
||||
cleaned_fields[key] !== null &&
|
||||
typeof cleaned_fields[key] === 'object'
|
||||
) {
|
||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@ interface SearchAeObjV3Params {
|
||||
view?: string;
|
||||
for_obj_type?: string;
|
||||
for_obj_id?: string;
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
||||
order_by_li?:
|
||||
| Record<string, 'ASC' | 'DESC'>
|
||||
| Record<string, 'ASC' | 'DESC'>[]
|
||||
| null;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
delay_ms?: number;
|
||||
@@ -55,7 +58,10 @@ export async function search_ae_obj({
|
||||
|
||||
// Serialize any complex objects in the query params (e.g. ft_qry, lk_qry)
|
||||
for (const key in query_params) {
|
||||
if (typeof query_params[key] === 'object' && query_params[key] !== null) {
|
||||
if (
|
||||
typeof query_params[key] === 'object' &&
|
||||
query_params[key] !== null
|
||||
) {
|
||||
query_params[key] = JSON.stringify(query_params[key]);
|
||||
}
|
||||
}
|
||||
@@ -76,4 +82,4 @@ export async function search_ae_obj({
|
||||
data: search_query,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ export const post_object = async function post_object({
|
||||
retry_count?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`);
|
||||
console.log(
|
||||
`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`
|
||||
);
|
||||
console.log('Params:', params);
|
||||
if (log_lvl > 1) {
|
||||
console.log('Data:', data);
|
||||
@@ -65,7 +67,9 @@ export const post_object = async function post_object({
|
||||
// Construct the URL with query parameters
|
||||
const url = new URL(endpoint, api_cfg['base_url']);
|
||||
if (params) {
|
||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
||||
Object.keys(params).forEach((key) =>
|
||||
url.searchParams.append(key, params[key])
|
||||
);
|
||||
}
|
||||
|
||||
// Clean and merge headers
|
||||
@@ -95,14 +99,19 @@ export const post_object = async function post_object({
|
||||
}
|
||||
|
||||
// Handle "Bootstrap Paradox" for unauthenticated requests
|
||||
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||
const is_valid_bypass = bypass_val === 'bypass' ||
|
||||
bypass_val === 'Nothing to See Here' ||
|
||||
params['key'] ||
|
||||
bypass_val === 'direct-download';
|
||||
const bypass_val =
|
||||
merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||
const is_valid_bypass =
|
||||
bypass_val === 'bypass' ||
|
||||
bypass_val === 'Nothing to See Here' ||
|
||||
params['key'] ||
|
||||
bypass_val === 'direct-download';
|
||||
|
||||
if (is_valid_bypass) {
|
||||
if (log_lvl > 1) console.log('api_post_object: Valid bypass detected. Stripping account ID context.');
|
||||
if (log_lvl > 1)
|
||||
console.log(
|
||||
'api_post_object: Valid bypass detected. Stripping account ID context.'
|
||||
);
|
||||
delete merged_headers['x-account-id'];
|
||||
delete merged_headers['x_account_id'];
|
||||
} else {
|
||||
@@ -124,11 +133,12 @@ export const post_object = async function post_object({
|
||||
}
|
||||
|
||||
// Auto-inject Authorization header if JWT is present but header is missing
|
||||
let jwt = headers_cleaned['jwt'] ||
|
||||
headers_cleaned['JWT'] ||
|
||||
api_cfg['jwt'] ||
|
||||
api_cfg['headers']?.['jwt'] ||
|
||||
api_cfg['headers']?.['JWT'];
|
||||
let jwt =
|
||||
headers_cleaned['jwt'] ||
|
||||
headers_cleaned['JWT'] ||
|
||||
api_cfg['jwt'] ||
|
||||
api_cfg['headers']?.['jwt'] ||
|
||||
api_cfg['headers']?.['JWT'];
|
||||
|
||||
// Final Fallback: Direct check of primary ae_loc key
|
||||
if (!jwt && typeof localStorage !== 'undefined') {
|
||||
@@ -143,7 +153,11 @@ export const post_object = async function post_object({
|
||||
}
|
||||
}
|
||||
|
||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
||||
if (
|
||||
jwt &&
|
||||
!headers_cleaned['Authorization'] &&
|
||||
!headers_cleaned['authorization']
|
||||
) {
|
||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||
}
|
||||
|
||||
@@ -186,13 +200,21 @@ export const post_object = async function post_object({
|
||||
console.log('Fetch Options:', fetchOptions);
|
||||
}
|
||||
|
||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
||||
error: any
|
||||
) {
|
||||
const response = await fetch_method(
|
||||
url.toString(),
|
||||
fetchOptions
|
||||
).catch(function (error: any) {
|
||||
// SILENCE NOISE: Aborted requests shouldn't spam logs at log_lvl 0
|
||||
if (error.name === 'AbortError' || error.message?.includes('aborted') || error.name === 'TypeError') {
|
||||
if (
|
||||
error.name === 'AbortError' ||
|
||||
error.message?.includes('aborted') ||
|
||||
error.name === 'TypeError'
|
||||
) {
|
||||
if (log_lvl > 1) {
|
||||
console.log('API POST: Request was aborted or terminated by browser. Expected during navigation.', error);
|
||||
console.log(
|
||||
'API POST: Request was aborted or terminated by browser. Expected during navigation.',
|
||||
error
|
||||
);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@@ -206,9 +228,17 @@ export const post_object = async function post_object({
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// Check if we should stop due to abort or network failure
|
||||
if (response instanceof Error || (response && (response.name === 'TypeError' || response.name === 'AbortError'))) {
|
||||
if (
|
||||
response instanceof Error ||
|
||||
(response &&
|
||||
(response.name === 'TypeError' ||
|
||||
response.name === 'AbortError'))
|
||||
) {
|
||||
if (response.name === 'AbortError') return false;
|
||||
if (log_lvl > 1) console.log('API POST Object: Detected NetworkError or TypeError. Failing fast.');
|
||||
if (log_lvl > 1)
|
||||
console.log(
|
||||
'API POST Object: Detected NetworkError or TypeError. Failing fast.'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -219,30 +249,53 @@ export const post_object = async function post_object({
|
||||
}
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Response: status=${response.status} attempt=${attempt}`);
|
||||
console.log(
|
||||
`Response: status=${response.status} attempt=${attempt}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
if (log_lvl) {
|
||||
console.log('The response was a 404 not found "error". Returning null.');
|
||||
console.log(
|
||||
'The response was a 404 not found "error". Returning null.'
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
||||
if (response.status === 400 || response.status === 401 || response.status === 403 || response.status === 422) {
|
||||
if (log_lvl) console.error(`API Client Failure (${response.status}). Failing fast.`);
|
||||
if (
|
||||
response.status === 400 ||
|
||||
response.status === 401 ||
|
||||
response.status === 403 ||
|
||||
response.status === 422
|
||||
) {
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`API Client Failure (${response.status}). Failing fast.`
|
||||
);
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
console.warn(`AUTH DIAGNOSTICS (POST): Headers sent for ${endpoint}:`, {
|
||||
has_auth: !!headers_cleaned['Authorization'],
|
||||
has_api_key: !!headers_cleaned['x-aether-api-key'],
|
||||
has_account_id: !!headers_cleaned['x-account-id'],
|
||||
jwt_preview: jwt ? `${jwt.slice(0, 8)}...` : 'MISSING'
|
||||
});
|
||||
console.warn(
|
||||
`AUTH DIAGNOSTICS (POST): Headers sent for ${endpoint}:`,
|
||||
{
|
||||
has_auth: !!headers_cleaned['Authorization'],
|
||||
has_api_key:
|
||||
!!headers_cleaned['x-aether-api-key'],
|
||||
has_account_id:
|
||||
!!headers_cleaned['x-account-id'],
|
||||
jwt_preview: jwt
|
||||
? `${jwt.slice(0, 8)}...`
|
||||
: 'MISSING'
|
||||
}
|
||||
);
|
||||
// Signal the root layout to show the session-expired banner.
|
||||
if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
||||
if (browser)
|
||||
ae_auth_error.set({
|
||||
type: 'expired',
|
||||
ts: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// Structured Error Handling (V3): Attempt to get rich error metadata
|
||||
@@ -253,7 +306,11 @@ export const post_object = async function post_object({
|
||||
// Not JSON
|
||||
}
|
||||
|
||||
if (log_lvl) console.log('The response was not ok. Structured Error Check:', error_json);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'The response was not ok. Structured Error Check:',
|
||||
error_json
|
||||
);
|
||||
|
||||
if (error_json?.meta?.details) {
|
||||
return error_json;
|
||||
@@ -267,7 +324,10 @@ export const post_object = async function post_object({
|
||||
status_code: response.status,
|
||||
details: {
|
||||
category: 'validation',
|
||||
message: typeof error_json.detail === 'string' ? error_json.detail : JSON.stringify(error_json.detail),
|
||||
message:
|
||||
typeof error_json.detail === 'string'
|
||||
? error_json.detail
|
||||
: JSON.stringify(error_json.detail),
|
||||
raw: error_json.detail
|
||||
}
|
||||
}
|
||||
@@ -311,7 +371,11 @@ export const post_object = async function post_object({
|
||||
|
||||
// Return the response data or metadata
|
||||
// Robustly handle V3 response envelopes
|
||||
return return_meta ? json : (json.data !== undefined ? json.data : json);
|
||||
return return_meta
|
||||
? json
|
||||
: json.data !== undefined
|
||||
? json.data
|
||||
: json;
|
||||
} else {
|
||||
const blob = await response.blob();
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ export async function load_ae_obj_id__archive({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Archive | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__archive() *** archive_id=${archive_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__archive() *** archive_id=${archive_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.load__archive_obj = await api
|
||||
@@ -52,10 +54,11 @@ export async function load_ae_obj_id__archive({
|
||||
.then(async function (archive_obj_get_result) {
|
||||
if (archive_obj_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__archive_props({
|
||||
obj_li: [archive_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__archive_props({
|
||||
obj_li: [archive_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_archives,
|
||||
table_name: 'archive',
|
||||
@@ -76,19 +79,21 @@ export async function load_ae_obj_id__archive({
|
||||
|
||||
if (inc_content_li && ae_promises.load__archive_obj) {
|
||||
// Load the contents for the archive
|
||||
const load_archive_content_obj_li = await load_ae_obj_li__archive_content({
|
||||
api_cfg: api_cfg,
|
||||
for_obj_type: 'archive',
|
||||
for_obj_id: archive_id,
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
params: params,
|
||||
try_cache: try_cache,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
ae_promises.load__archive_obj.archive_content_li = load_archive_content_obj_li;
|
||||
const load_archive_content_obj_li =
|
||||
await load_ae_obj_li__archive_content({
|
||||
api_cfg: api_cfg,
|
||||
for_obj_type: 'archive',
|
||||
for_obj_id: archive_id,
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
params: params,
|
||||
try_cache: try_cache,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
ae_promises.load__archive_obj.archive_content_li =
|
||||
load_archive_content_obj_li;
|
||||
}
|
||||
|
||||
return ae_promises.load__archive_obj;
|
||||
@@ -125,7 +130,9 @@ export async function load_ae_obj_li__archive({
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[];
|
||||
order_by_li?:
|
||||
| Record<string, 'ASC' | 'DESC'>
|
||||
| Record<string, 'ASC' | 'DESC'>[];
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
@@ -138,7 +145,9 @@ export async function load_ae_obj_li__archive({
|
||||
|
||||
// DEBUG: Trace massive content loads
|
||||
if (inc_content_li) {
|
||||
console.warn(`load_ae_obj_li__archive: Loading content for ALL archives in list! Limit: ${limit}`);
|
||||
console.warn(
|
||||
`load_ae_obj_li__archive: Loading content for ALL archives in list! Limit: ${limit}`
|
||||
);
|
||||
// console.trace();
|
||||
}
|
||||
|
||||
@@ -159,10 +168,11 @@ export async function load_ae_obj_li__archive({
|
||||
.then(async function (archive_obj_li_get_result) {
|
||||
if (archive_obj_li_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__archive_props({
|
||||
obj_li: archive_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__archive_props({
|
||||
obj_li: archive_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_archives,
|
||||
table_name: 'archive',
|
||||
@@ -220,7 +230,9 @@ export async function create_ae_obj__archive({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Archive | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** create_ae_obj__archive() *** account_id=${account_id}`);
|
||||
console.log(
|
||||
`*** create_ae_obj__archive() *** account_id=${account_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.create_ae_obj({
|
||||
@@ -268,7 +280,9 @@ export async function delete_ae_obj_id__archive({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__archive() *** archive_id=${archive_id}`);
|
||||
console.log(
|
||||
`*** delete_ae_obj_id__archive() *** archive_id=${archive_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.delete_ae_obj({
|
||||
@@ -304,7 +318,10 @@ export async function update_ae_obj__archive({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Archive | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__archive() *** archive_id=${archive_id}`, data_kv);
|
||||
console.log(
|
||||
`*** update_ae_obj__archive() *** archive_id=${archive_id}`,
|
||||
data_kv
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.update_ae_obj({
|
||||
@@ -366,7 +383,11 @@ export async function qry__archive({
|
||||
const search_query: any = { and: [] };
|
||||
|
||||
if (account_id) {
|
||||
search_query.and.push({ field: 'account_id_random', op: 'eq', value: account_id });
|
||||
search_query.and.push({
|
||||
field: 'account_id_random',
|
||||
op: 'eq',
|
||||
value: account_id
|
||||
});
|
||||
}
|
||||
|
||||
if (qry_str) {
|
||||
@@ -452,11 +473,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -489,4 +514,4 @@ export async function process_ae_obj__archive_props({
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,11 @@ export async function load_ae_obj_id__archive_content({
|
||||
.then(async function (archive_content_obj_get_result) {
|
||||
if (archive_content_obj_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__archive_content_props({
|
||||
obj_li: [archive_content_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__archive_content_props({
|
||||
obj_li: [archive_content_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_archives,
|
||||
table_name: 'content',
|
||||
@@ -96,7 +97,9 @@ export async function load_ae_obj_li__archive_content({
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[];
|
||||
order_by_li?:
|
||||
| Record<string, 'ASC' | 'DESC'>
|
||||
| Record<string, 'ASC' | 'DESC'>[];
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
@@ -124,10 +127,11 @@ export async function load_ae_obj_li__archive_content({
|
||||
.then(async function (archive_content_obj_li_get_result) {
|
||||
if (archive_content_obj_li_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__archive_content_props({
|
||||
obj_li: archive_content_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__archive_content_props({
|
||||
obj_li: archive_content_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_archives,
|
||||
table_name: 'content',
|
||||
@@ -162,11 +166,15 @@ export async function create_ae_obj__archive_content({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_ArchiveContent | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** create_ae_obj__archive_content() *** archive_id=${archive_id}`);
|
||||
console.log(
|
||||
`*** create_ae_obj__archive_content() *** archive_id=${archive_id}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!archive_id) {
|
||||
console.log(`ERROR: Archives - Content - archive_id required to create`);
|
||||
console.log(
|
||||
`ERROR: Archives - Content - archive_id required to create`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -357,11 +365,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -399,4 +411,4 @@ export async function process_ae_obj__archive_content_props({
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,188 +1,191 @@
|
||||
<script lang="ts">
|
||||
// Imports
|
||||
// Import components and elements
|
||||
// import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
|
||||
// Imports
|
||||
// Import components and elements
|
||||
// import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
|
||||
|
||||
// Import storage, functions, and libraries
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// Import storage, functions, and libraries
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
|
||||
import { api } from '$lib/api/api';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
|
||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||
import { Check, Download, LoaderCircle, MinusCircle, Scissors } from '@lucide/svelte';
|
||||
// Exports
|
||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||
import {
|
||||
Check,
|
||||
Download,
|
||||
LoaderCircle,
|
||||
MinusCircle,
|
||||
Scissors
|
||||
} from '@lucide/svelte';
|
||||
// Exports
|
||||
|
||||
// export let input_name = 'file_list';
|
||||
// export let multiple: boolean = true;
|
||||
// export let required: boolean = true;
|
||||
// export let input_name = 'file_list';
|
||||
// export let multiple: boolean = true;
|
||||
// export let required: boolean = true;
|
||||
|
||||
// export let input_class_li: string[] = ['file_drop_area'];
|
||||
// export let input_class_li: string[] = ['file_drop_area'];
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
// export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
// export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
|
||||
clip_complete?: boolean;
|
||||
// export let upload_complete: boolean = false;
|
||||
submit_status?: null | string;
|
||||
// hosted_file_id_li?: string[];
|
||||
// hosted_file_obj_li?: any[];
|
||||
hosted_file_obj_kv?: key_val;
|
||||
video_clip_file_kv?: key_val;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
// export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
// export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
|
||||
clip_complete?: boolean;
|
||||
// export let upload_complete: boolean = false;
|
||||
submit_status?: null | string;
|
||||
// hosted_file_id_li?: string[];
|
||||
// hosted_file_obj_li?: any[];
|
||||
hosted_file_obj_kv?: key_val;
|
||||
video_clip_file_kv?: key_val;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
link_to_type = $bindable(),
|
||||
link_to_id = $bindable(),
|
||||
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
|
||||
class_li = $bindable(''),
|
||||
clip_complete = $bindable(false),
|
||||
submit_status = $bindable(null),
|
||||
// hosted_file_id_li = [],
|
||||
// hosted_file_obj_li = [],
|
||||
hosted_file_obj_kv = $bindable({}),
|
||||
video_clip_file_kv = $bindable({})
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
link_to_type = $bindable(),
|
||||
link_to_id = $bindable(),
|
||||
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
|
||||
class_li = $bindable(''),
|
||||
clip_complete = $bindable(false),
|
||||
submit_status = $bindable(null),
|
||||
// hosted_file_id_li = [],
|
||||
// hosted_file_obj_li = [],
|
||||
hosted_file_obj_kv = $bindable({}),
|
||||
video_clip_file_kv = $bindable({})
|
||||
}: Props = $props();
|
||||
|
||||
// Local Variables
|
||||
let task_id = link_to_id;
|
||||
// let input_file_list: any = null;
|
||||
let ae_promises: key_val = $state({});
|
||||
// let ae_promises_clipping: key_val = {};
|
||||
// let ae_triggers: key_val = {};
|
||||
// Local Variables
|
||||
let task_id = link_to_id;
|
||||
// let input_file_list: any = null;
|
||||
let ae_promises: key_val = $state({});
|
||||
// let ae_promises_clipping: key_val = {};
|
||||
// let ae_triggers: key_val = {};
|
||||
|
||||
// let input_element_id = 'ae_comp__hosted_files_upload__input';
|
||||
// let input_element_id = 'ae_comp__hosted_files_upload__input';
|
||||
|
||||
// let form_kv: key_val = {
|
||||
// start_time: null,
|
||||
// end_time: null,
|
||||
// reencode: null,
|
||||
// video_file: null,
|
||||
// };
|
||||
// let download_clip_src: string;
|
||||
// let download_clip_filename: string;
|
||||
// let form_kv: key_val = {
|
||||
// start_time: null,
|
||||
// end_time: null,
|
||||
// reencode: null,
|
||||
// video_file: null,
|
||||
// };
|
||||
// let download_clip_src: string;
|
||||
// let download_clip_filename: string;
|
||||
|
||||
$ae_sess.files.obj = {
|
||||
obj: null
|
||||
$ae_sess.files.obj = {
|
||||
obj: null
|
||||
};
|
||||
|
||||
// *** Functions and Logic
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
fn(event);
|
||||
};
|
||||
}
|
||||
|
||||
function handle_clip_video(event: Event) {
|
||||
console.log('*** handle_clip_video() ***');
|
||||
|
||||
submit_status = 'clipping';
|
||||
clip_complete = false;
|
||||
|
||||
const form = event.target as HTMLFormElement;
|
||||
const formData = new FormData(form);
|
||||
|
||||
let hosted_file_id = formData.get('hosted_file_id') as string;
|
||||
let start_time = formData.get('start_time') as string;
|
||||
let end_time = formData.get('end_time') as string;
|
||||
let reencode = formData.get('reencode') as string;
|
||||
let scale_down = formData.get('scale_down') as string;
|
||||
let new_filename = formData.get('new_filename') as string;
|
||||
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id] = {};
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status = 'clipping';
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
||||
|
||||
// $ae_sess.files.disable_submit__hosted_file_obj = true;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id] = {};
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status = 'clipping';
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].start_time = start_time;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].end_time = end_time;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].reencode = reencode;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].scale_down = scale_down;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].new_filename = new_filename;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
||||
|
||||
let endpoint = `/hosted_file/${hosted_file_id}/clip_video`;
|
||||
|
||||
let params = {
|
||||
link_to_type: link_to_type,
|
||||
link_to_id: link_to_id,
|
||||
filename_no_ext: new_filename.replace('.mp4', ''),
|
||||
from_type: 'mp4', // Video file type being converted
|
||||
to_type: 'mp4', // Video file type to convert to
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
reencode: reencode,
|
||||
scale_down: scale_down
|
||||
};
|
||||
|
||||
// *** Functions and Logic
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
fn(event);
|
||||
};
|
||||
}
|
||||
ae_promises[hosted_file_id] = {};
|
||||
// .convert__hosted_file_obj
|
||||
ae_promises[hosted_file_id] = api
|
||||
.get_object({
|
||||
api_cfg: $ae_api,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
timeout: 300000, // 5 minutes
|
||||
// return_blob: true,
|
||||
// filename: event.target.new_filename.value,
|
||||
// auto_download: false,
|
||||
task_id: task_id,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (result) {
|
||||
console.log(result);
|
||||
|
||||
function handle_clip_video(event: Event) {
|
||||
console.log('*** handle_clip_video() ***');
|
||||
video_clip_file_kv[result.hosted_file_id] = {};
|
||||
video_clip_file_kv[result.hosted_file_id] = result;
|
||||
|
||||
submit_status = 'clipping';
|
||||
clip_complete = false;
|
||||
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = {};
|
||||
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = result;
|
||||
|
||||
const form = event.target as HTMLFormElement;
|
||||
const formData = new FormData(form);
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
|
||||
'clipped';
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete =
|
||||
true;
|
||||
|
||||
let hosted_file_id = formData.get('hosted_file_id') as string;
|
||||
let start_time = formData.get('start_time') as string;
|
||||
let end_time = formData.get('end_time') as string;
|
||||
let reencode = formData.get('reencode') as string;
|
||||
let scale_down = formData.get('scale_down') as string;
|
||||
let new_filename = formData.get('new_filename') as string;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status =
|
||||
'clipped';
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete =
|
||||
true;
|
||||
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id] = {};
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
|
||||
'clipping';
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
||||
submit_status = 'clipped';
|
||||
clip_complete = true;
|
||||
|
||||
// $ae_sess.files.disable_submit__hosted_file_obj = true;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id] = {};
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status =
|
||||
'clipping';
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].start_time = start_time;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].end_time = end_time;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].reencode = reencode;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].scale_down = scale_down;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].new_filename =
|
||||
new_filename;
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
||||
// let file_blob = new Blob([result.data]);
|
||||
// // console.log(file_blob);
|
||||
// let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
|
||||
// // const url = window.URL.createObjectURL(new Blob([result.data]));
|
||||
// download_clip_src = file_obj_url;
|
||||
// // download_filename = file_obj_url;
|
||||
|
||||
let endpoint = `/hosted_file/${hosted_file_id}/clip_video`;
|
||||
|
||||
let params = {
|
||||
link_to_type: link_to_type,
|
||||
link_to_id: link_to_id,
|
||||
filename_no_ext: new_filename.replace('.mp4', ''),
|
||||
from_type: 'mp4', // Video file type being converted
|
||||
to_type: 'mp4', // Video file type to convert to
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
reencode: reencode,
|
||||
scale_down: scale_down
|
||||
};
|
||||
|
||||
ae_promises[hosted_file_id] = {};
|
||||
// .convert__hosted_file_obj
|
||||
ae_promises[hosted_file_id] = api
|
||||
.get_object({
|
||||
api_cfg: $ae_api,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
timeout: 300000, // 5 minutes
|
||||
// return_blob: true,
|
||||
// filename: event.target.new_filename.value,
|
||||
// auto_download: false,
|
||||
task_id: task_id,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (result) {
|
||||
console.log(result);
|
||||
|
||||
video_clip_file_kv[result.hosted_file_id] = {};
|
||||
video_clip_file_kv[result.hosted_file_id] = result;
|
||||
|
||||
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = {};
|
||||
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = result;
|
||||
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
|
||||
'clipped';
|
||||
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete =
|
||||
true;
|
||||
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status =
|
||||
'clipped';
|
||||
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete =
|
||||
true;
|
||||
|
||||
submit_status = 'clipped';
|
||||
clip_complete = true;
|
||||
|
||||
// let file_blob = new Blob([result.data]);
|
||||
// // console.log(file_blob);
|
||||
// let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
|
||||
// // const url = window.URL.createObjectURL(new Blob([result.data]));
|
||||
// download_clip_src = file_obj_url;
|
||||
// // download_filename = file_obj_url;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="{class_li_default} {class_li}">
|
||||
@@ -191,11 +194,11 @@
|
||||
</h3>
|
||||
|
||||
{#each Object.entries(hosted_file_obj_kv) as [hosted_file_id, hosted_file_obj] (hosted_file_id)}
|
||||
<div class="border border-surface-500/20 rounded-lg p-2 m-2 preset-tonal-surface">
|
||||
<div
|
||||
class="border-surface-500/20 preset-tonal-surface m-2 rounded-lg border p-2">
|
||||
<!-- Download Button (Standardized) -->
|
||||
<div
|
||||
class="flex flex-row flex-wrap gap-1 justify-center items-center w-full"
|
||||
>
|
||||
class="flex w-full flex-row flex-wrap items-center justify-center gap-1">
|
||||
<!-- Remove from uploaded file kv list -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -219,8 +222,7 @@
|
||||
);
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500"
|
||||
title={`Remove this file from list of videos:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id}`}
|
||||
>
|
||||
title={`Remove this file from list of videos:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id}`}>
|
||||
<MinusCircle size="1em" class="m-1" />
|
||||
<span class="">Remove</span>
|
||||
</button>
|
||||
@@ -234,60 +236,49 @@
|
||||
variant="tonal"
|
||||
classes="novi_btn btn-sm lg:btn-md min-w-72 lg:min-w-96 !justify-start"
|
||||
show_divider={true}
|
||||
max_filename={30}
|
||||
/>
|
||||
max_filename={30} />
|
||||
</div>
|
||||
<span
|
||||
>{ae_util.shorten_filename({
|
||||
filename: hosted_file_obj?.filename,
|
||||
max_length: 30
|
||||
})}</span
|
||||
>
|
||||
})}</span>
|
||||
<span>
|
||||
<span class="text-sm font-bold"> File ID: </span>
|
||||
{hosted_file_obj.hosted_file_id}</span
|
||||
>
|
||||
{hosted_file_obj.hosted_file_id}</span>
|
||||
<span>
|
||||
<span class="text-sm font-bold"> Type: </span>
|
||||
{hosted_file_obj.extension}</span
|
||||
>
|
||||
{hosted_file_obj.extension}</span>
|
||||
<!-- <span>{hosted_file_obj.filename}</span> -->
|
||||
</div>
|
||||
|
||||
<form
|
||||
onsubmit={prevent_default(handle_clip_video)}
|
||||
class="{class_li_default} {class_li}"
|
||||
>
|
||||
class="{class_li_default} {class_li}">
|
||||
<!-- {$ae_sess?.files[hosted_file_obj?.hosted_file_id ?? 'obj'].submit_status ?? 'not set'} -->
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name="hosted_file_id"
|
||||
value={hosted_file_obj.hosted_file_id}
|
||||
/>
|
||||
value={hosted_file_obj.hosted_file_id} />
|
||||
|
||||
<div
|
||||
class="flex flex-row gap-1 justify-center items-center w-full"
|
||||
>
|
||||
<span class="text-xs font-bold w-32">New Filename:</span>
|
||||
class="flex w-full flex-row items-center justify-center gap-1">
|
||||
<span class="w-32 text-xs font-bold">New Filename:</span>
|
||||
<input
|
||||
type="text"
|
||||
class="input w-full text-sm variant-filled-surface"
|
||||
class="input variant-filled-surface w-full text-sm"
|
||||
name="new_filename"
|
||||
value={hosted_file_obj.filename}
|
||||
/>
|
||||
value={hosted_file_obj.filename} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="max-w-(--breakpoint-sm) flex flex-row gap-1 justify-center items-center w-full"
|
||||
>
|
||||
class="flex w-full max-w-(--breakpoint-sm) flex-row items-center justify-center gap-1">
|
||||
<label
|
||||
class="label w-48"
|
||||
title="The start time of the clip. This is the time in the video where the clip will start. You may need to subtract a few seconds to get the exact start time."
|
||||
>
|
||||
title="The start time of the clip. This is the time in the video where the clip will start. You may need to subtract a few seconds to get the exact start time.">
|
||||
<span class="text-xs font-bold"
|
||||
>Start time (HH:MM:SS)</span
|
||||
>
|
||||
>Start time (HH:MM:SS)</span>
|
||||
<input
|
||||
type="text"
|
||||
name="start_time"
|
||||
@@ -300,17 +291,14 @@
|
||||
].start_time
|
||||
: '00:00:00'}
|
||||
placeholder="HH:MM:SS (00:01:30)"
|
||||
class="input w-32 variant-filled-surface"
|
||||
/>
|
||||
class="input variant-filled-surface w-32" />
|
||||
</label>
|
||||
|
||||
<label
|
||||
class="label w-48"
|
||||
title="The end time of the clip. This is the time in the video where the clip will end. You may need to add a few seconds to get the exact end time."
|
||||
>
|
||||
title="The end time of the clip. This is the time in the video where the clip will end. You may need to add a few seconds to get the exact end time.">
|
||||
<span class="text-xs font-bold"
|
||||
>End time (HH:MM:SS)</span
|
||||
>
|
||||
>End time (HH:MM:SS)</span>
|
||||
<input
|
||||
type="text"
|
||||
name="end_time"
|
||||
@@ -323,14 +311,12 @@
|
||||
].end_time
|
||||
: '00:45:59'}
|
||||
placeholder="HH:MM:SS (01:05:25)"
|
||||
class="input w-32 variant-filled-surface"
|
||||
/>
|
||||
class="input variant-filled-surface w-32" />
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="flex flex-col gap-1 items-center justify-center"
|
||||
title="Re-encode the video file? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files."
|
||||
>
|
||||
class="flex flex-col items-center justify-center gap-1"
|
||||
title="Re-encode the video file? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files.">
|
||||
<span class="text-xs font-bold"> Re-encode? </span>
|
||||
<label class="inline-block">
|
||||
<input
|
||||
@@ -338,8 +324,7 @@
|
||||
name="reencode"
|
||||
value="true"
|
||||
class="radio"
|
||||
checked
|
||||
/>
|
||||
checked />
|
||||
True
|
||||
</label>
|
||||
<label class="inline-block">
|
||||
@@ -347,16 +332,14 @@
|
||||
type="radio"
|
||||
name="reencode"
|
||||
value="false"
|
||||
class="radio"
|
||||
/>
|
||||
class="radio" />
|
||||
False
|
||||
</label>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="flex flex-col gap-1 items-center justify-center"
|
||||
title="Scale the video file down to 1920x1080? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files."
|
||||
>
|
||||
class="flex flex-col items-center justify-center gap-1"
|
||||
title="Scale the video file down to 1920x1080? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files.">
|
||||
<span class="text-xs font-bold"> Scale down? </span>
|
||||
<label class="inline-block">
|
||||
<input
|
||||
@@ -364,8 +347,7 @@
|
||||
name="scale_down"
|
||||
value="true"
|
||||
class="radio"
|
||||
checked
|
||||
/>
|
||||
checked />
|
||||
True
|
||||
</label>
|
||||
<label class="inline-block">
|
||||
@@ -373,8 +355,7 @@
|
||||
type="radio"
|
||||
name="scale_down"
|
||||
value="false"
|
||||
class="radio"
|
||||
/>
|
||||
class="radio" />
|
||||
False
|
||||
</label>
|
||||
</span>
|
||||
@@ -382,9 +363,8 @@
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-filled-primary-500 transition-colors"
|
||||
disabled={submit_status == 'clipping'}
|
||||
>
|
||||
class="btn btn-lg btn-primary preset-tonal-primary border-primary-500 hover:preset-filled-primary-500 border transition-colors"
|
||||
disabled={submit_status == 'clipping'}>
|
||||
<!-- {#await ae_promises[hosted_file_id]} -->
|
||||
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipping'}
|
||||
<LoaderCircle size="1em" class="m-1 animate-spin" />
|
||||
@@ -407,8 +387,7 @@
|
||||
{#await ae_promises[hosted_file_id]}
|
||||
<LoaderCircle size="1em" class="m-1 animate-spin" />
|
||||
<span class="highlight"
|
||||
>Processing... This may take a few minutes.</span
|
||||
>
|
||||
>Processing... This may take a few minutes.</span>
|
||||
{:then}
|
||||
{#if ae_promises[hosted_file_id]}
|
||||
<Download size="1em" /> Ready to download below!
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
<script lang="ts">
|
||||
// Imports
|
||||
// Import components and elements
|
||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||
// Imports
|
||||
// Import components and elements
|
||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||
|
||||
// Import storage, functions, and libraries
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// Import storage, functions, and libraries
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
|
||||
import { api } from '$lib/api/api';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
|
||||
// Exports
|
||||
// Exports
|
||||
|
||||
// export let hosted_file_id_li: string[] = [];
|
||||
// export let hosted_file_obj_li: any[] = [];
|
||||
// export let hosted_file_id_li: string[] = [];
|
||||
// export let hosted_file_obj_li: any[] = [];
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// export let hosted_file_obj_kv: key_val = {};
|
||||
video_clip_file_kv?: key_val;
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// export let hosted_file_obj_kv: key_val = {};
|
||||
video_clip_file_kv?: key_val;
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
video_clip_file_kv = $bindable({}),
|
||||
class_li_default = 'flex flex-row flex-wrap gap-2 items-center justify-center w-full max-w-2xl p-2 mx-auto my-1 border border-surface-500/20 rounded-lg preset-tonal-surface',
|
||||
class_li = '',
|
||||
link_to_type,
|
||||
link_to_id
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = 0,
|
||||
video_clip_file_kv = $bindable({}),
|
||||
class_li_default = 'flex flex-row flex-wrap gap-2 items-center justify-center w-full max-w-2xl p-2 mx-auto my-1 border border-surface-500/20 rounded-lg preset-tonal-surface',
|
||||
class_li = '',
|
||||
link_to_type,
|
||||
link_to_id
|
||||
}: Props = $props();
|
||||
|
||||
let ae_promises: key_val = $state({});
|
||||
let ae_promises: key_val = $state({});
|
||||
</script>
|
||||
|
||||
<h3 class="h3">{Object.entries(video_clip_file_kv).length}× files clipped</h3>
|
||||
@@ -54,7 +54,6 @@
|
||||
max_filename={30}
|
||||
classes="btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
|
||||
linked_to_type={link_to_type}
|
||||
linked_to_id={link_to_id}
|
||||
/>
|
||||
linked_to_id={link_to_id} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -1,243 +1,275 @@
|
||||
<script lang="ts">
|
||||
// *** Import Svelte specific
|
||||
import * as Lucide from 'lucide-svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
// *** Import Svelte specific
|
||||
import * as Lucide from 'lucide-svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { download_ae_obj_id__hosted_file } from '$lib/ae_core/core__hosted_files';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api
|
||||
} from '$lib/stores/ae_stores';
|
||||
// *** Import Aether specific variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { download_ae_obj_id__hosted_file } from '$lib/ae_core/core__hosted_files';
|
||||
import { ae_loc, ae_sess, ae_api } from '$lib/stores/ae_stores';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hosted_file_id: null | string;
|
||||
hosted_file_obj: null | key_val;
|
||||
filename?: null | string;
|
||||
max_filename?: number;
|
||||
auto_download?: boolean;
|
||||
linked_to_type?: null | string;
|
||||
linked_to_id?: null | string;
|
||||
download_complete?: null | boolean;
|
||||
download_percent?: number;
|
||||
download_status_msg?: string;
|
||||
variant?: 'tonal' | 'filled' | 'outline' | 'ghost';
|
||||
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'error' | 'surface';
|
||||
show_divider?: boolean;
|
||||
show_direct_download?: boolean;
|
||||
require_auth?: boolean;
|
||||
classes?: string;
|
||||
click?: () => void | Promise<any>;
|
||||
label?: import('svelte').Snippet;
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hosted_file_id: null | string;
|
||||
hosted_file_obj: null | key_val;
|
||||
filename?: null | string;
|
||||
max_filename?: number;
|
||||
auto_download?: boolean;
|
||||
linked_to_type?: null | string;
|
||||
linked_to_id?: null | string;
|
||||
download_complete?: null | boolean;
|
||||
download_percent?: number;
|
||||
download_status_msg?: string;
|
||||
variant?: 'tonal' | 'filled' | 'outline' | 'ghost';
|
||||
color?:
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'tertiary'
|
||||
| 'success'
|
||||
| 'warning'
|
||||
| 'error'
|
||||
| 'surface';
|
||||
show_divider?: boolean;
|
||||
show_direct_download?: boolean;
|
||||
require_auth?: boolean;
|
||||
classes?: string;
|
||||
click?: () => void | Promise<any>;
|
||||
label?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
hosted_file_id,
|
||||
hosted_file_obj,
|
||||
filename = $bindable(null),
|
||||
max_filename = $bindable(30),
|
||||
auto_download = true,
|
||||
linked_to_type = $bindable(null),
|
||||
linked_to_id = $bindable(null),
|
||||
download_complete = $bindable(),
|
||||
download_percent = $bindable(),
|
||||
download_status_msg = $bindable('Not started'),
|
||||
variant = 'tonal',
|
||||
color = 'primary',
|
||||
show_divider = true,
|
||||
show_direct_download = false,
|
||||
require_auth = true,
|
||||
classes = '',
|
||||
click,
|
||||
label
|
||||
}: Props = $props();
|
||||
|
||||
// Map variant/color to classes using literal strings so Tailwind can find them
|
||||
const color_map: Record<string, Record<string, string>> = {
|
||||
primary: {
|
||||
tonal: 'preset-tonal-primary border border-primary-500/30 hover:preset-filled-primary-500',
|
||||
filled: 'preset-filled-primary-500 hover:preset-filled-primary-600',
|
||||
outline: 'border border-primary-500 hover:preset-tonal-primary',
|
||||
ghost: 'hover:preset-tonal-primary'
|
||||
},
|
||||
secondary: {
|
||||
tonal: 'preset-tonal-secondary border border-secondary-500/30 hover:preset-filled-secondary-500',
|
||||
filled: 'preset-filled-secondary-500 hover:preset-filled-secondary-600',
|
||||
outline: 'border border-secondary-500 hover:preset-tonal-secondary',
|
||||
ghost: 'hover:preset-tonal-secondary'
|
||||
},
|
||||
tertiary: {
|
||||
tonal: 'preset-tonal-tertiary border border-tertiary-500/30 hover:preset-filled-tertiary-500',
|
||||
filled: 'preset-filled-tertiary-500 hover:preset-filled-tertiary-600',
|
||||
outline: 'border border-tertiary-500 hover:preset-tonal-tertiary',
|
||||
ghost: 'hover:preset-tonal-tertiary'
|
||||
},
|
||||
success: {
|
||||
tonal: 'preset-tonal-success border border-success-500/30 hover:preset-filled-success-500',
|
||||
filled: 'preset-filled-success-500 hover:preset-filled-success-600',
|
||||
outline: 'border border-success-500 hover:preset-tonal-success',
|
||||
ghost: 'hover:preset-tonal-success'
|
||||
},
|
||||
warning: {
|
||||
tonal: 'preset-tonal-warning border border-warning-500/30 hover:preset-filled-warning-500',
|
||||
filled: 'preset-filled-warning-500 hover:preset-filled-warning-600',
|
||||
outline: 'border border-warning-500 hover:preset-tonal-warning',
|
||||
ghost: 'hover:preset-tonal-warning'
|
||||
},
|
||||
error: {
|
||||
tonal: 'preset-tonal-error border border-error-500/30 hover:preset-filled-error-500',
|
||||
filled: 'preset-filled-error-500 hover:preset-filled-error-600',
|
||||
outline: 'border border-error-500 hover:preset-tonal-error',
|
||||
ghost: 'hover:preset-tonal-error'
|
||||
},
|
||||
surface: {
|
||||
tonal: 'preset-tonal-surface border border-surface-500/30 hover:preset-filled-surface-500',
|
||||
filled: 'preset-filled-surface-500 hover:preset-filled-surface-600',
|
||||
outline: 'border border-surface-500 hover:preset-tonal-surface',
|
||||
ghost: 'hover:preset-tonal-surface'
|
||||
}
|
||||
};
|
||||
|
||||
let variant_classes = $derived.by(() => {
|
||||
const base =
|
||||
'btn btn-sm lg:btn-md min-w-48 transition-all overflow-hidden px-3';
|
||||
const style = color_map[color]?.[variant] || color_map.primary.tonal;
|
||||
return `${base} ${style} ${classes}`.trim();
|
||||
});
|
||||
|
||||
let show_filename_view = $state(true);
|
||||
let status_interval: any;
|
||||
|
||||
$effect(() => {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`ae_comp__hosted_files_download_button.svelte hosted_file_id=${hosted_file_id}`,
|
||||
hosted_file_obj
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let ae_promises: key_val = $state({});
|
||||
|
||||
$effect(() => {
|
||||
const file_id =
|
||||
hosted_file_obj?.id ||
|
||||
hosted_file_obj?.hosted_file_id ||
|
||||
hosted_file_id;
|
||||
if (file_id && $ae_sess?.api_download_kv[file_id]?.percent_completed) {
|
||||
download_percent = $ae_sess.api_download_kv[file_id].percent_completed;
|
||||
}
|
||||
});
|
||||
|
||||
// Reactive timer to alternate views during active download
|
||||
$effect(() => {
|
||||
const file_id =
|
||||
hosted_file_obj?.id ||
|
||||
hosted_file_obj?.hosted_file_id ||
|
||||
hosted_file_id;
|
||||
const is_actively_downloading =
|
||||
ae_promises[file_id] && download_complete === undefined;
|
||||
|
||||
if (is_actively_downloading) {
|
||||
if (!status_interval) {
|
||||
status_interval = setInterval(() => {
|
||||
show_filename_view = !show_filename_view;
|
||||
}, 3000);
|
||||
}
|
||||
} else {
|
||||
if (status_interval) {
|
||||
clearInterval(status_interval);
|
||||
status_interval = null;
|
||||
}
|
||||
show_filename_view = true; // Default view when not downloading
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
hosted_file_id,
|
||||
hosted_file_obj,
|
||||
filename = $bindable(null),
|
||||
max_filename = $bindable(30),
|
||||
auto_download = true,
|
||||
linked_to_type = $bindable(null),
|
||||
linked_to_id = $bindable(null),
|
||||
download_complete = $bindable(),
|
||||
download_percent = $bindable(),
|
||||
download_status_msg = $bindable('Not started'),
|
||||
variant = 'tonal',
|
||||
color = 'primary',
|
||||
show_divider = true,
|
||||
show_direct_download = false,
|
||||
require_auth = true,
|
||||
classes = '',
|
||||
click,
|
||||
label
|
||||
}: Props = $props();
|
||||
|
||||
// Map variant/color to classes using literal strings so Tailwind can find them
|
||||
const color_map: Record<string, Record<string, string>> = {
|
||||
primary: {
|
||||
tonal: 'preset-tonal-primary border border-primary-500/30 hover:preset-filled-primary-500',
|
||||
filled: 'preset-filled-primary-500 hover:preset-filled-primary-600',
|
||||
outline: 'border border-primary-500 hover:preset-tonal-primary',
|
||||
ghost: 'hover:preset-tonal-primary'
|
||||
},
|
||||
secondary: {
|
||||
tonal: 'preset-tonal-secondary border border-secondary-500/30 hover:preset-filled-secondary-500',
|
||||
filled: 'preset-filled-secondary-500 hover:preset-filled-secondary-600',
|
||||
outline: 'border border-secondary-500 hover:preset-tonal-secondary',
|
||||
ghost: 'hover:preset-tonal-secondary'
|
||||
},
|
||||
tertiary: {
|
||||
tonal: 'preset-tonal-tertiary border border-tertiary-500/30 hover:preset-filled-tertiary-500',
|
||||
filled: 'preset-filled-tertiary-500 hover:preset-filled-tertiary-600',
|
||||
outline: 'border border-tertiary-500 hover:preset-tonal-tertiary',
|
||||
ghost: 'hover:preset-tonal-tertiary'
|
||||
},
|
||||
success: {
|
||||
tonal: 'preset-tonal-success border border-success-500/30 hover:preset-filled-success-500',
|
||||
filled: 'preset-filled-success-500 hover:preset-filled-success-600',
|
||||
outline: 'border border-success-500 hover:preset-tonal-success',
|
||||
ghost: 'hover:preset-tonal-success'
|
||||
},
|
||||
warning: {
|
||||
tonal: 'preset-tonal-warning border border-warning-500/30 hover:preset-filled-warning-500',
|
||||
filled: 'preset-filled-warning-500 hover:preset-filled-warning-600',
|
||||
outline: 'border border-warning-500 hover:preset-tonal-warning',
|
||||
ghost: 'hover:preset-tonal-warning'
|
||||
},
|
||||
error: {
|
||||
tonal: 'preset-tonal-error border border-error-500/30 hover:preset-filled-error-500',
|
||||
filled: 'preset-filled-error-500 hover:preset-filled-error-600',
|
||||
outline: 'border border-error-500 hover:preset-tonal-error',
|
||||
ghost: 'hover:preset-tonal-error'
|
||||
},
|
||||
surface: {
|
||||
tonal: 'preset-tonal-surface border border-surface-500/30 hover:preset-filled-surface-500',
|
||||
filled: 'preset-filled-surface-500 hover:preset-filled-surface-600',
|
||||
outline: 'border border-surface-500 hover:preset-tonal-surface',
|
||||
ghost: 'hover:preset-tonal-surface'
|
||||
return () => {
|
||||
if (status_interval) {
|
||||
clearInterval(status_interval);
|
||||
status_interval = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let variant_classes = $derived.by(() => {
|
||||
const base = 'btn btn-sm lg:btn-md min-w-48 transition-all overflow-hidden px-3';
|
||||
const style = color_map[color]?.[variant] || color_map.primary.tonal;
|
||||
return `${base} ${style} ${classes}`.trim();
|
||||
});
|
||||
|
||||
let show_filename_view = $state(true);
|
||||
let status_interval: any;
|
||||
|
||||
$effect(() => {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`ae_comp__hosted_files_download_button.svelte hosted_file_id=${hosted_file_id}`,
|
||||
hosted_file_obj
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let ae_promises: key_val = $state({});
|
||||
|
||||
$effect(() => {
|
||||
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
|
||||
if (file_id && $ae_sess?.api_download_kv[file_id]?.percent_completed) {
|
||||
download_percent =
|
||||
$ae_sess.api_download_kv[file_id].percent_completed;
|
||||
}
|
||||
});
|
||||
|
||||
// Reactive timer to alternate views during active download
|
||||
$effect(() => {
|
||||
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
|
||||
const is_actively_downloading = ae_promises[file_id] && download_complete === undefined;
|
||||
|
||||
if (is_actively_downloading) {
|
||||
if (!status_interval) {
|
||||
status_interval = setInterval(() => {
|
||||
show_filename_view = !show_filename_view;
|
||||
}, 3000);
|
||||
}
|
||||
} else {
|
||||
if (status_interval) {
|
||||
clearInterval(status_interval);
|
||||
status_interval = null;
|
||||
}
|
||||
show_filename_view = true; // Default view when not downloading
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (status_interval) {
|
||||
clearInterval(status_interval);
|
||||
status_interval = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let final_filename = $derived(filename ?? hosted_file_obj?.filename ?? 'unknown');
|
||||
let shortened_filename = $derived(ae_util.shorten_filename({
|
||||
let final_filename = $derived(
|
||||
filename ?? hosted_file_obj?.filename ?? 'unknown'
|
||||
);
|
||||
let shortened_filename = $derived(
|
||||
ae_util.shorten_filename({
|
||||
filename: final_filename,
|
||||
max_length: max_filename
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
let direct_download_url = $derived.by(() => {
|
||||
if (!show_direct_download || !hosted_file_obj) return '';
|
||||
// IMPORTANT: For Direct Link Mode, we MUST use the V3 Action endpoint to support Random String IDs.
|
||||
// Legacy endpoints often expect integer IDs and will return 404 for string IDs.
|
||||
const file_id = hosted_file_obj.event_file_id || hosted_file_obj.hosted_file_id || hosted_file_id;
|
||||
const obj_type_path = hosted_file_obj.event_file_id ? 'event_file' : 'hosted_file';
|
||||
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&key=${$ae_api.account_id}`;
|
||||
});
|
||||
let direct_download_url = $derived.by(() => {
|
||||
if (!show_direct_download || !hosted_file_obj) return '';
|
||||
// IMPORTANT: For Direct Link Mode, we MUST use the V3 Action endpoint to support Random String IDs.
|
||||
// Legacy endpoints often expect integer IDs and will return 404 for string IDs.
|
||||
const file_id =
|
||||
hosted_file_obj.event_file_id ||
|
||||
hosted_file_obj.hosted_file_id ||
|
||||
hosted_file_id;
|
||||
const obj_type_path = hosted_file_obj.event_file_id
|
||||
? 'event_file'
|
||||
: 'hosted_file';
|
||||
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&key=${$ae_api.account_id}`;
|
||||
});
|
||||
|
||||
async function handle_click() {
|
||||
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
|
||||
download_complete = undefined;
|
||||
download_status_msg = 'Downloading...';
|
||||
async function handle_click() {
|
||||
const file_id =
|
||||
hosted_file_obj?.id ||
|
||||
hosted_file_obj?.hosted_file_id ||
|
||||
hosted_file_id;
|
||||
download_complete = undefined;
|
||||
download_status_msg = 'Downloading...';
|
||||
|
||||
if (click) {
|
||||
const result = click();
|
||||
// If the override returns a promise, track it so the UI shows progress
|
||||
if (result instanceof Promise) {
|
||||
ae_promises[file_id] = result;
|
||||
}
|
||||
return;
|
||||
if (click) {
|
||||
const result = click();
|
||||
// If the override returns a promise, track it so the UI shows progress
|
||||
if (result instanceof Promise) {
|
||||
ae_promises[file_id] = result;
|
||||
}
|
||||
|
||||
ae_promises[file_id] = download_ae_obj_id__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: file_id,
|
||||
return_file: true,
|
||||
filename: final_filename,
|
||||
auto_download: auto_download,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then((result) => {
|
||||
if (result === null) {
|
||||
console.log('File not found (404)');
|
||||
download_complete = null;
|
||||
download_status_msg = 'File not found';
|
||||
} else if (result === false) {
|
||||
console.log(
|
||||
'Possible error with API server (check network and server status)'
|
||||
);
|
||||
download_complete = false;
|
||||
download_status_msg = 'Failed to download';
|
||||
} else {
|
||||
// console.log('File found and downloaded');
|
||||
download_complete = true;
|
||||
download_status_msg = 'File downloaded';
|
||||
}
|
||||
return result;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
ae_promises[file_id] = download_ae_obj_id__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: file_id,
|
||||
return_file: true,
|
||||
filename: final_filename,
|
||||
auto_download: auto_download,
|
||||
log_lvl: log_lvl
|
||||
}).then((result) => {
|
||||
if (result === null) {
|
||||
console.log('File not found (404)');
|
||||
download_complete = null;
|
||||
download_status_msg = 'File not found';
|
||||
} else if (result === false) {
|
||||
console.log(
|
||||
'Possible error with API server (check network and server status)'
|
||||
);
|
||||
download_complete = false;
|
||||
download_status_msg = 'Failed to download';
|
||||
} else {
|
||||
// console.log('File found and downloaded');
|
||||
download_complete = true;
|
||||
download_status_msg = 'File downloaded';
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#snippet content()}
|
||||
{@const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id}
|
||||
{@const file_id =
|
||||
hosted_file_obj?.id ||
|
||||
hosted_file_obj?.hosted_file_id ||
|
||||
hosted_file_id}
|
||||
{#await ae_promises[file_id]}
|
||||
<div class="flex items-center w-full min-h-[1.5rem]">
|
||||
<div class="flex min-h-[1.5rem] w-full items-center">
|
||||
<div
|
||||
class="flex items-center pr-2 shrink-0 {show_divider ? 'border-r border-surface-500/30 mr-2' : ''}"
|
||||
>
|
||||
class="flex shrink-0 items-center pr-2 {show_divider
|
||||
? 'border-surface-500/30 mr-2 border-r'
|
||||
: ''}">
|
||||
<Lucide.LoaderCircle class="animate-spin" size={18} />
|
||||
</div>
|
||||
<div class="grow relative text-left h-full">
|
||||
<div class="relative h-full grow text-left">
|
||||
{#if show_filename_view}
|
||||
<div in:fade={{ duration: 250 }} out:fade={{ duration: 250 }} class="flex items-center h-full">
|
||||
<div
|
||||
in:fade={{ duration: 250 }}
|
||||
out:fade={{ duration: 250 }}
|
||||
class="flex h-full items-center">
|
||||
<span class="truncate">
|
||||
{shortened_filename}
|
||||
</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div in:fade={{ duration: 250 }} out:fade={{ duration: 250 }} class="absolute inset-0 flex items-center h-full">
|
||||
<div
|
||||
in:fade={{ duration: 250 }}
|
||||
out:fade={{ duration: 250 }}
|
||||
class="absolute inset-0 flex h-full items-center">
|
||||
<span class="font-bold whitespace-nowrap">
|
||||
Downloading:
|
||||
{#if $ae_sess.api_download_kv[file_id]}
|
||||
{$ae_sess.api_download_kv[file_id].percent_completed}%
|
||||
{$ae_sess.api_download_kv[file_id]
|
||||
.percent_completed}%
|
||||
{:else}
|
||||
...
|
||||
{/if}
|
||||
@@ -250,18 +282,22 @@
|
||||
{#if label}
|
||||
{@render label()}
|
||||
{:else}
|
||||
{@const IconComp = ae_util.file_extension_icon_lucide(hosted_file_obj?.extension)}
|
||||
<div class="flex items-center w-full">
|
||||
{@const IconComp = ae_util.file_extension_icon_lucide(
|
||||
hosted_file_obj?.extension
|
||||
)}
|
||||
<div class="flex w-full items-center">
|
||||
<div
|
||||
class="flex items-center pr-2 shrink-0 {show_divider ? 'border-r border-surface-500/30 mr-2' : ''}"
|
||||
>
|
||||
class="flex shrink-0 items-center pr-2 {show_divider
|
||||
? 'border-surface-500/30 mr-2 border-r'
|
||||
: ''}">
|
||||
<IconComp size={18} />
|
||||
</div>
|
||||
<span class="grow truncate text-left">
|
||||
{shortened_filename}
|
||||
</span>
|
||||
{#if hosted_file_obj?.file_purpose || hosted_file_obj?.group}
|
||||
<span class="badge preset-tonal-success ml-2 text-[10px] uppercase font-bold shrink-0">
|
||||
<span
|
||||
class="badge preset-tonal-success ml-2 shrink-0 text-[10px] font-bold uppercase">
|
||||
{hosted_file_obj.file_purpose || hosted_file_obj.group}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -270,22 +306,25 @@
|
||||
{/await}
|
||||
|
||||
{#if download_complete === null}
|
||||
<span class="text-red-800 dark:text-red-200 ml-2 whitespace-nowrap">File not found</span>
|
||||
<span class="ml-2 whitespace-nowrap text-red-800 dark:text-red-200"
|
||||
>File not found</span>
|
||||
{:else if download_complete === false}
|
||||
<span class="text-red-800 dark:text-red-200 ml-2 whitespace-nowrap text-xs">Failed!</span>
|
||||
<span
|
||||
class="ml-2 text-xs whitespace-nowrap text-red-800 dark:text-red-200"
|
||||
>Failed!</span>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
{#if hosted_file_id && hosted_file_obj}
|
||||
{@const file_id = hosted_file_obj.id || hosted_file_obj.hosted_file_id || hosted_file_id}
|
||||
{@const file_id =
|
||||
hosted_file_obj.id || hosted_file_obj.hosted_file_id || hosted_file_id}
|
||||
|
||||
{#if show_direct_download}
|
||||
<a
|
||||
href={direct_download_url}
|
||||
download={ae_util.clean_filename(final_filename)}
|
||||
class={variant_classes}
|
||||
title={`Direct download (V3 Action):\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}`}
|
||||
>
|
||||
title={`Direct download (V3 Action):\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}`}>
|
||||
{@render content()}
|
||||
</a>
|
||||
{:else}
|
||||
@@ -294,20 +333,24 @@
|
||||
disabled={require_auth && !$ae_loc.authenticated_access}
|
||||
class={variant_classes}
|
||||
onclick={handle_click}
|
||||
title={`Download this file:\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}
|
||||
>
|
||||
title={`Download this file:\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}>
|
||||
{@render content()}
|
||||
</button>
|
||||
{/if}
|
||||
{:else}
|
||||
<button type="button" disabled class={variant_classes} title="No file selected">
|
||||
<div class="flex items-center w-full">
|
||||
<button
|
||||
type="button"
|
||||
disabled
|
||||
class={variant_classes}
|
||||
title="No file selected">
|
||||
<div class="flex w-full items-center">
|
||||
<div
|
||||
class="flex items-center pr-2 shrink-0 {show_divider ? 'border-r border-surface-500/30 mr-2' : ''}"
|
||||
>
|
||||
class="flex shrink-0 items-center pr-2 {show_divider
|
||||
? 'border-surface-500/30 mr-2 border-r'
|
||||
: ''}">
|
||||
<Lucide.FileX size={18} />
|
||||
</div>
|
||||
<span class="grow text-left"> No file info </span>
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -1,281 +1,286 @@
|
||||
<script lang="ts">
|
||||
// untrack import removed — task_id sync now uses direct $effect (no untrack needed)
|
||||
// Imports
|
||||
// Import components and elements
|
||||
import * as Lucide from 'lucide-svelte';
|
||||
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
|
||||
// untrack import removed — task_id sync now uses direct $effect (no untrack needed)
|
||||
// Imports
|
||||
// Import components and elements
|
||||
import * as Lucide from 'lucide-svelte';
|
||||
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
|
||||
|
||||
// Import storage, functions, and libraries
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// Import storage, functions, and libraries
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
|
||||
import { api } from '$lib/api/api';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
|
||||
// Exports
|
||||
// Exports
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
input_name?: string;
|
||||
multiple?: boolean;
|
||||
required?: boolean;
|
||||
accept?: string;
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
input_class_li?: string[];
|
||||
table_class_li?: string[];
|
||||
upload_complete?: boolean;
|
||||
submit_status?: null | string;
|
||||
hosted_file_id_li?: string[];
|
||||
hosted_file_obj_li?: any[];
|
||||
hosted_file_obj_kv?: key_val;
|
||||
label?: import('svelte').Snippet;
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
input_name?: string;
|
||||
multiple?: boolean;
|
||||
required?: boolean;
|
||||
accept?: string;
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
input_class_li?: string[];
|
||||
table_class_li?: string[];
|
||||
upload_complete?: boolean;
|
||||
submit_status?: null | string;
|
||||
hosted_file_id_li?: string[];
|
||||
hosted_file_obj_li?: any[];
|
||||
hosted_file_obj_kv?: key_val;
|
||||
label?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
input_name = 'file_list',
|
||||
multiple = true,
|
||||
required = true,
|
||||
accept = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh',
|
||||
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
|
||||
class_li = '',
|
||||
input_class_li = ['file_drop_area'],
|
||||
table_class_li = ['table', 'table-sm', 'table-striped', '', 'text-sm'],
|
||||
upload_complete = $bindable(false),
|
||||
submit_status = $bindable(null),
|
||||
hosted_file_id_li = $bindable([]),
|
||||
hosted_file_obj_li = $bindable([]),
|
||||
hosted_file_obj_kv = $bindable({}),
|
||||
label
|
||||
}: Props = $props();
|
||||
|
||||
// Local Variables
|
||||
let task_id: string = $state('');
|
||||
let input_file_list: any = $state(null);
|
||||
let ae_promises: key_val = $state({}); // Promise<any>;
|
||||
let ae_triggers: key_val = {};
|
||||
|
||||
let input_element_id = 'ae_comp__hosted_files_upload__input';
|
||||
|
||||
$effect(() => {
|
||||
if (log_lvl) {
|
||||
console.log(`*** ae_comp__hosted_files_upload.svelte ***`);
|
||||
console.log(`link_to_type: ${link_to_type} link_to_id: ${link_to_id}`);
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
// Sync task_id with link_to_id prop so it resets when navigating to a different object.
|
||||
task_id = link_to_id;
|
||||
});
|
||||
|
||||
// *** Functions and Logic
|
||||
async function handle_submit_form_files(event: SubmitEvent) {
|
||||
console.log('*** handle_submit_form() ***');
|
||||
event.preventDefault();
|
||||
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
input_name = 'file_list',
|
||||
multiple = true,
|
||||
required = true,
|
||||
accept = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh',
|
||||
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
|
||||
class_li = '',
|
||||
input_class_li = ['file_drop_area'],
|
||||
table_class_li = ['table', 'table-sm', 'table-striped', '', 'text-sm'],
|
||||
upload_complete = $bindable(false),
|
||||
submit_status = $bindable(null),
|
||||
hosted_file_id_li = $bindable([]),
|
||||
hosted_file_obj_li = $bindable([]),
|
||||
hosted_file_obj_kv = $bindable({}),
|
||||
label
|
||||
}: Props = $props();
|
||||
$ae_sess.files.disable_submit__hosted_file_obj = true;
|
||||
$ae_sess.files.submit_status = 'saving';
|
||||
submit_status = 'saving';
|
||||
upload_complete = false;
|
||||
|
||||
// Local Variables
|
||||
let task_id: string = $state('');
|
||||
let input_file_list: any = $state(null);
|
||||
let ae_promises: key_val = $state({}); // Promise<any>;
|
||||
let ae_triggers: key_val = {};
|
||||
hosted_file_id_li = [];
|
||||
hosted_file_obj_li = [];
|
||||
hosted_file_obj_kv = {};
|
||||
|
||||
let input_element_id = 'ae_comp__hosted_files_upload__input';
|
||||
let hosted_file_results;
|
||||
|
||||
$effect(() => {
|
||||
if (log_lvl) {
|
||||
console.log(`*** ae_comp__hosted_files_upload.svelte ***`);
|
||||
console.log(`link_to_type: ${link_to_type} link_to_id: ${link_to_id}`);
|
||||
}
|
||||
});
|
||||
const target = event.currentTarget as HTMLFormElement;
|
||||
const file_input = target
|
||||
? (target[input_element_id] as HTMLInputElement)
|
||||
: null;
|
||||
|
||||
$effect(() => {
|
||||
// Sync task_id with link_to_id prop so it resets when navigating to a different object.
|
||||
task_id = link_to_id;
|
||||
});
|
||||
if (
|
||||
target &&
|
||||
file_input &&
|
||||
file_input.files &&
|
||||
file_input.files.length > 0
|
||||
) {
|
||||
task_id = link_to_id; // Ideally this should be the file hash, but we may be uploading multiple files at once. This should be done with a loop instead?
|
||||
|
||||
// *** Functions and Logic
|
||||
async function handle_submit_form_files(event: SubmitEvent) {
|
||||
console.log('*** handle_submit_form() ***');
|
||||
event.preventDefault();
|
||||
// Loop through each file and upload them individually in event.target[input_element_id].files
|
||||
// The task_id should be the file hash.
|
||||
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
|
||||
for (let i = 0; i < file_input.files.length; i++) {
|
||||
let tmp_file = file_input.files[i];
|
||||
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
|
||||
|
||||
$ae_sess.files.disable_submit__hosted_file_obj = true;
|
||||
$ae_sess.files.submit_status = 'saving';
|
||||
submit_status = 'saving';
|
||||
upload_complete = false;
|
||||
|
||||
hosted_file_id_li = [];
|
||||
hosted_file_obj_li = [];
|
||||
hosted_file_obj_kv = {};
|
||||
|
||||
let hosted_file_results;
|
||||
|
||||
const target = event.currentTarget as HTMLFormElement;
|
||||
const file_input = target ? (target[input_element_id] as HTMLInputElement) : null;
|
||||
|
||||
if (
|
||||
target &&
|
||||
file_input &&
|
||||
file_input.files &&
|
||||
file_input.files.length > 0
|
||||
) {
|
||||
task_id = link_to_id; // Ideally this should be the file hash, but we may be uploading multiple files at once. This should be done with a loop instead?
|
||||
|
||||
// Loop through each file and upload them individually in event.target[input_element_id].files
|
||||
// The task_id should be the file hash.
|
||||
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
|
||||
for (let i = 0; i < file_input.files.length; i++) {
|
||||
let tmp_file = file_input.files[i];
|
||||
|
||||
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
|
||||
|
||||
// hosted_file_results = await handle_input_upload_files([tmp_file], task_id);
|
||||
hosted_file_results = await handle_input_upload_files({
|
||||
input_upload_files: [tmp_file],
|
||||
task_id: task_id
|
||||
});
|
||||
|
||||
if (hosted_file_results) {
|
||||
console.log(`hosted_file_results:`, hosted_file_results);
|
||||
} else {
|
||||
console.log(`hosted_file_results:`, hosted_file_results);
|
||||
}
|
||||
}
|
||||
// hosted_file_results = await handle_input_upload_files(event.target[input_element_id].files, task_id);
|
||||
$ae_sess.files.processed_file_list = [];
|
||||
$ae_sess = $ae_sess; // Is this needed? 2025-03-17
|
||||
target.reset();
|
||||
// await tick();
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`hosted_file_id_li: ${hosted_file_id_li}`, hosted_file_id_li);
|
||||
} else if (log_lvl > 1) {
|
||||
console.log('hosted_file_results:', hosted_file_results);
|
||||
}
|
||||
}
|
||||
|
||||
$ae_sess.files.disable_submit__hosted_file_obj = false;
|
||||
$ae_sess.files.submit_status = 'saved';
|
||||
submit_status = 'saved';
|
||||
upload_complete = true;
|
||||
}
|
||||
|
||||
async function handle_input_upload_files({
|
||||
input_upload_files,
|
||||
task_id
|
||||
}: {
|
||||
input_upload_files: any[];
|
||||
task_id: string;
|
||||
}) {
|
||||
console.log('*** handle_input_upload_files() ***');
|
||||
|
||||
const form_data = new FormData();
|
||||
|
||||
form_data.append('account_id', $ae_loc.account_id);
|
||||
form_data.append('link_to_type', link_to_type);
|
||||
form_data.append('link_to_id', link_to_id);
|
||||
|
||||
for (let i = 0; i < input_upload_files.length; i++) {
|
||||
form_data.append(`file_list`, input_upload_files[i]);
|
||||
}
|
||||
|
||||
// hash_sha256, uploaded, uploaded_bytes
|
||||
// $ae_sess.files.processed_file_list[i] = {
|
||||
// ...$ae_sess.files.processed_file_list[i],
|
||||
// uploaded: $ae_sess.api_upload_kv[link_to_id].percent_completed,
|
||||
// uploaded_bytes: $ae_sess.api_upload_kv[link_to_id].uploaded_bytes,
|
||||
// };
|
||||
|
||||
let params = null;
|
||||
|
||||
let endpoint = '/hosted_file/upload_files';
|
||||
|
||||
console.log(form_data);
|
||||
|
||||
params = null;
|
||||
|
||||
// Uncomment and the post_promise is not seen by the "await" below
|
||||
// post_promise = await api.post_object({api_cfg: $cfg.api, endpoint: endpoint, params: params, data:form_data});
|
||||
// Uncomment so that the post_promise is not seen by the "await" below
|
||||
ae_promises.upload__hosted_file_obj = api
|
||||
.post_object({
|
||||
api_cfg: $ae_api,
|
||||
endpoint: endpoint,
|
||||
// params: params,
|
||||
form_data: form_data,
|
||||
task_id: task_id,
|
||||
log_lvl: log_lvl
|
||||
// retry_count: 1,
|
||||
})
|
||||
.then(async function (result) {
|
||||
// WARNING!!!! ONLY ONE FILE IS EXPECTED TO BE UPLOADED AT A TIME!!!
|
||||
// NOTE: The /hosted_file/upload_files endpoint will always return a list of successful files uploaded. In this case we are only uploading one file and expecting a list of one item.
|
||||
let x = 0;
|
||||
console.log(result[x]);
|
||||
let hosted_file_obj = result[x];
|
||||
|
||||
let hosted_file_id = hosted_file_obj.hosted_file_id;
|
||||
|
||||
hosted_file_id_li.push(hosted_file_id);
|
||||
hosted_file_obj_li.push(hosted_file_obj);
|
||||
|
||||
let hosted_file_data: key_val = {};
|
||||
hosted_file_data['id'] = hosted_file_id; // Same as the hosted_file_id
|
||||
hosted_file_data['hosted_file_id'] = hosted_file_id;
|
||||
hosted_file_data['for_type'] = link_to_type;
|
||||
hosted_file_data['for_id'] = link_to_id;
|
||||
hosted_file_data['hash_sha256'] = hosted_file_obj.hash_sha256;
|
||||
hosted_file_data['filename'] = hosted_file_obj.filename;
|
||||
hosted_file_data['extension'] = hosted_file_obj.extension;
|
||||
hosted_file_data['content_type'] = hosted_file_obj.content_type;
|
||||
hosted_file_data['size'] = hosted_file_obj.size;
|
||||
hosted_file_data['enable'] = true;
|
||||
hosted_file_data['created_on'] = hosted_file_obj.created_on;
|
||||
hosted_file_data['updated_on'] = hosted_file_obj.updated_on;
|
||||
console.log(hosted_file_data);
|
||||
|
||||
hosted_file_obj_kv[hosted_file_id] = hosted_file_data;
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`hosted_file_data:`, hosted_file_data);
|
||||
}
|
||||
|
||||
return hosted_file_data;
|
||||
|
||||
// $ae_sess.files.new_upload_list[i].uploaded_bytes = 10; // fake 10 bytes at least...
|
||||
|
||||
// let event_file_id = await events_func.create_hosted_file_obj_from_hosted_file_async({
|
||||
// api_cfg: $ae_api,
|
||||
// hosted_file_id: hosted_file_id,
|
||||
// data: event_file_data,
|
||||
// log_lvl: log_lvl
|
||||
// })
|
||||
// .then(function (create_result) {
|
||||
// console.log(create_result); // NOTE: This should be the event_file_id string
|
||||
// // let event_file_id = create_result;
|
||||
// return create_result;
|
||||
// });
|
||||
|
||||
// return event_file_id;
|
||||
})
|
||||
// .then(function (hosted_file_data) {
|
||||
// return hosted_file_data;
|
||||
// })
|
||||
.catch(function (error: any) {
|
||||
console.log('Something went wrong.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(function () {
|
||||
$slct_trigger = 'load__hosted_file_obj_li';
|
||||
// hosted_file_results = await handle_input_upload_files([tmp_file], task_id);
|
||||
hosted_file_results = await handle_input_upload_files({
|
||||
input_upload_files: [tmp_file],
|
||||
task_id: task_id
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Waiting for upload__hosted_file_obj promise...`);
|
||||
if (hosted_file_results) {
|
||||
console.log(`hosted_file_results:`, hosted_file_results);
|
||||
} else {
|
||||
console.log(`hosted_file_results:`, hosted_file_results);
|
||||
}
|
||||
}
|
||||
let hosted_file_result = ae_promises.upload__hosted_file_obj;
|
||||
// hosted_file_results = await handle_input_upload_files(event.target[input_element_id].files, task_id);
|
||||
$ae_sess.files.processed_file_list = [];
|
||||
$ae_sess = $ae_sess; // Is this needed? 2025-03-17
|
||||
target.reset();
|
||||
// await tick();
|
||||
|
||||
return hosted_file_result;
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`hosted_file_id_li: ${hosted_file_id_li}`,
|
||||
hosted_file_id_li
|
||||
);
|
||||
} else if (log_lvl > 1) {
|
||||
console.log('hosted_file_results:', hosted_file_results);
|
||||
}
|
||||
}
|
||||
|
||||
$ae_sess.files.disable_submit__hosted_file_obj = false;
|
||||
$ae_sess.files.submit_status = 'saved';
|
||||
submit_status = 'saved';
|
||||
upload_complete = true;
|
||||
}
|
||||
|
||||
async function handle_input_upload_files({
|
||||
input_upload_files,
|
||||
task_id
|
||||
}: {
|
||||
input_upload_files: any[];
|
||||
task_id: string;
|
||||
}) {
|
||||
console.log('*** handle_input_upload_files() ***');
|
||||
|
||||
const form_data = new FormData();
|
||||
|
||||
form_data.append('account_id', $ae_loc.account_id);
|
||||
form_data.append('link_to_type', link_to_type);
|
||||
form_data.append('link_to_id', link_to_id);
|
||||
|
||||
for (let i = 0; i < input_upload_files.length; i++) {
|
||||
form_data.append(`file_list`, input_upload_files[i]);
|
||||
}
|
||||
|
||||
// hash_sha256, uploaded, uploaded_bytes
|
||||
// $ae_sess.files.processed_file_list[i] = {
|
||||
// ...$ae_sess.files.processed_file_list[i],
|
||||
// uploaded: $ae_sess.api_upload_kv[link_to_id].percent_completed,
|
||||
// uploaded_bytes: $ae_sess.api_upload_kv[link_to_id].uploaded_bytes,
|
||||
// };
|
||||
|
||||
let params = null;
|
||||
|
||||
let endpoint = '/hosted_file/upload_files';
|
||||
|
||||
console.log(form_data);
|
||||
|
||||
params = null;
|
||||
|
||||
// Uncomment and the post_promise is not seen by the "await" below
|
||||
// post_promise = await api.post_object({api_cfg: $cfg.api, endpoint: endpoint, params: params, data:form_data});
|
||||
// Uncomment so that the post_promise is not seen by the "await" below
|
||||
ae_promises.upload__hosted_file_obj = api
|
||||
.post_object({
|
||||
api_cfg: $ae_api,
|
||||
endpoint: endpoint,
|
||||
// params: params,
|
||||
form_data: form_data,
|
||||
task_id: task_id,
|
||||
log_lvl: log_lvl
|
||||
// retry_count: 1,
|
||||
})
|
||||
.then(async function (result) {
|
||||
// WARNING!!!! ONLY ONE FILE IS EXPECTED TO BE UPLOADED AT A TIME!!!
|
||||
// NOTE: The /hosted_file/upload_files endpoint will always return a list of successful files uploaded. In this case we are only uploading one file and expecting a list of one item.
|
||||
let x = 0;
|
||||
console.log(result[x]);
|
||||
let hosted_file_obj = result[x];
|
||||
|
||||
let hosted_file_id = hosted_file_obj.hosted_file_id;
|
||||
|
||||
hosted_file_id_li.push(hosted_file_id);
|
||||
hosted_file_obj_li.push(hosted_file_obj);
|
||||
|
||||
let hosted_file_data: key_val = {};
|
||||
hosted_file_data['id'] = hosted_file_id; // Same as the hosted_file_id
|
||||
hosted_file_data['hosted_file_id'] = hosted_file_id;
|
||||
hosted_file_data['for_type'] = link_to_type;
|
||||
hosted_file_data['for_id'] = link_to_id;
|
||||
hosted_file_data['hash_sha256'] = hosted_file_obj.hash_sha256;
|
||||
hosted_file_data['filename'] = hosted_file_obj.filename;
|
||||
hosted_file_data['extension'] = hosted_file_obj.extension;
|
||||
hosted_file_data['content_type'] = hosted_file_obj.content_type;
|
||||
hosted_file_data['size'] = hosted_file_obj.size;
|
||||
hosted_file_data['enable'] = true;
|
||||
hosted_file_data['created_on'] = hosted_file_obj.created_on;
|
||||
hosted_file_data['updated_on'] = hosted_file_obj.updated_on;
|
||||
console.log(hosted_file_data);
|
||||
|
||||
hosted_file_obj_kv[hosted_file_id] = hosted_file_data;
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`hosted_file_data:`, hosted_file_data);
|
||||
}
|
||||
|
||||
return hosted_file_data;
|
||||
|
||||
// $ae_sess.files.new_upload_list[i].uploaded_bytes = 10; // fake 10 bytes at least...
|
||||
|
||||
// let event_file_id = await events_func.create_hosted_file_obj_from_hosted_file_async({
|
||||
// api_cfg: $ae_api,
|
||||
// hosted_file_id: hosted_file_id,
|
||||
// data: event_file_data,
|
||||
// log_lvl: log_lvl
|
||||
// })
|
||||
// .then(function (create_result) {
|
||||
// console.log(create_result); // NOTE: This should be the event_file_id string
|
||||
// // let event_file_id = create_result;
|
||||
// return create_result;
|
||||
// });
|
||||
|
||||
// return event_file_id;
|
||||
})
|
||||
// .then(function (hosted_file_data) {
|
||||
// return hosted_file_data;
|
||||
// })
|
||||
.catch(function (error: any) {
|
||||
console.log('Something went wrong.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(function () {
|
||||
$slct_trigger = 'load__hosted_file_obj_li';
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Waiting for upload__hosted_file_obj promise...`);
|
||||
}
|
||||
let hosted_file_result = ae_promises.upload__hosted_file_obj;
|
||||
|
||||
return hosted_file_result;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- class:hidden={!$ae_loc.trusted_access} -->
|
||||
<form onsubmit={handle_submit_form_files} class="{class_li_default} {class_li}">
|
||||
{#await ae_promises.upload__hosted_file_obj}
|
||||
<div class="text-lg flex flex-row gap-1 items-center justify-center">
|
||||
<Lucide.LoaderCircle class="animate-spin m-1" />
|
||||
<div class="flex flex-row items-center justify-center gap-1 text-lg">
|
||||
<Lucide.LoaderCircle class="m-1 animate-spin" />
|
||||
<span class="">
|
||||
Uploading
|
||||
{#if $ae_sess.api_upload_kv[task_id]}
|
||||
@@ -288,14 +293,14 @@
|
||||
<label
|
||||
for="ae_comp__hosted_files_upload__input"
|
||||
class="svelte_input_file_label text-center"
|
||||
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
|
||||
>
|
||||
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}>
|
||||
{#if label}{@render label()}{:else}
|
||||
<div class="flex items-center justify-center gap-2 mb-2">
|
||||
<div class="mb-2 flex items-center justify-center gap-2">
|
||||
<Lucide.Upload class="text-primary-500" />
|
||||
<strong class="preset-tonal-primary px-3 py-1 rounded-full">Select Files</strong>
|
||||
<strong class="preset-tonal-primary rounded-full px-3 py-1"
|
||||
>Select Files</strong>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
|
||||
<span class="text-sm text-gray-600 italic dark:text-gray-400">
|
||||
<strong>Supported formats</strong><br />
|
||||
(PowerPoint, Keynote, PDF, Media, etc)
|
||||
</span>
|
||||
@@ -313,33 +318,30 @@
|
||||
class="
|
||||
svelte_input_file_element
|
||||
file-dropzone-input
|
||||
px-1
|
||||
block w-full text-lg
|
||||
preset-filled-surface-50-950
|
||||
text-surface-900 dark:text-surface-100
|
||||
border border-surface-300 dark:border-surface-700 rounded-lg
|
||||
cursor-pointer
|
||||
focus:outline-hidden focus:ring-2 focus:ring-primary-500
|
||||
text-surface-900 dark:text-surface-100 border-surface-300
|
||||
dark:border-surface-700
|
||||
focus:ring-primary-500 block
|
||||
w-full cursor-pointer rounded-lg border
|
||||
px-1
|
||||
text-lg focus:ring-2 focus:outline-hidden
|
||||
{input_class_li.join(' ')}
|
||||
"
|
||||
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
|
||||
/>
|
||||
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj} />
|
||||
|
||||
<Element_input_files_tbl
|
||||
bind:input_file_list
|
||||
bind:file_list_status={$ae_sess.files.status__file_list}
|
||||
bind:processed_file_list={$ae_sess.files.processed_file_list}
|
||||
{table_class_li}
|
||||
/>
|
||||
{table_class_li} />
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success hover:border-success-500 w-54"
|
||||
class="btn btn-lg btn-primary preset-tonal-primary border-primary-500 hover:preset-tonal-success hover:border-success-500 w-54 border"
|
||||
disabled={$ae_sess.files.disable_submit__hosted_file_obj ||
|
||||
$ae_sess.files.status__file_list != 'ready'}
|
||||
>
|
||||
$ae_sess.files.status__file_list != 'ready'}>
|
||||
{#await ae_promises.upload__hosted_file_obj}
|
||||
<Lucide.LoaderCircle class="animate-spin m-1" />
|
||||
<Lucide.LoaderCircle class="m-1 animate-spin" />
|
||||
<span class="">
|
||||
{#if $ae_sess.api_upload_kv[task_id]}
|
||||
{$ae_sess.api_upload_kv[task_id].percent_completed}%
|
||||
@@ -350,9 +352,12 @@
|
||||
{:then}
|
||||
<Lucide.UploadCloud class="m-1" size={20} />
|
||||
<span class="text-sm"> Upload </span>
|
||||
<span class="grow font-bold ml-2">
|
||||
<span class="ml-2 grow font-bold">
|
||||
{#if $ae_sess.files.processed_file_list?.length > 0}
|
||||
{$ae_sess.files.processed_file_list.length} { $ae_sess.files.processed_file_list.length === 1 ? 'file' : 'files' }
|
||||
{$ae_sess.files.processed_file_list.length}
|
||||
{$ae_sess.files.processed_file_list.length === 1
|
||||
? 'file'
|
||||
: 'files'}
|
||||
{:else}
|
||||
<span class="text-xs"> 0 </span>
|
||||
{/if}
|
||||
|
||||
@@ -1,235 +1,358 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte';
|
||||
/**
|
||||
* AE_Comp_Site_Config_Editor.svelte
|
||||
* Specialized UI for managing site.cfg_json settings.
|
||||
* Supports General, AI, Performance, and IDAA-specific configurations.
|
||||
*/
|
||||
import { Modal } from 'flowbite-svelte';
|
||||
import { Brain, CodeXml, ExternalLink, Globe, Mail, Minus, Palette, Plus, Save, ShieldCheck, Timer } from '@lucide/svelte';
|
||||
import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { untrack } from 'svelte';
|
||||
/**
|
||||
* AE_Comp_Site_Config_Editor.svelte
|
||||
* Specialized UI for managing site.cfg_json settings.
|
||||
* Supports General, AI, Performance, and IDAA-specific configurations.
|
||||
*/
|
||||
import { Modal } from 'flowbite-svelte';
|
||||
import {
|
||||
Brain,
|
||||
CodeXml,
|
||||
ExternalLink,
|
||||
Globe,
|
||||
Mail,
|
||||
Minus,
|
||||
Palette,
|
||||
Plus,
|
||||
Save,
|
||||
ShieldCheck,
|
||||
Timer
|
||||
} from '@lucide/svelte';
|
||||
import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
|
||||
interface Props {
|
||||
cfg_json: any;
|
||||
on_save?: () => void;
|
||||
}
|
||||
interface Props {
|
||||
cfg_json: any;
|
||||
on_save?: () => void;
|
||||
}
|
||||
|
||||
let { cfg_json = $bindable({}), on_save }: Props = $props();
|
||||
let { cfg_json = $bindable({}), on_save }: Props = $props();
|
||||
|
||||
// Ensure we have a valid object (handle strings/nulls)
|
||||
$effect(() => {
|
||||
if (typeof cfg_json === 'string') {
|
||||
try {
|
||||
cfg_json = JSON.parse(cfg_json);
|
||||
} catch (e) {
|
||||
cfg_json = {};
|
||||
}
|
||||
// Ensure we have a valid object (handle strings/nulls)
|
||||
$effect(() => {
|
||||
if (typeof cfg_json === 'string') {
|
||||
try {
|
||||
cfg_json = JSON.parse(cfg_json);
|
||||
} catch (e) {
|
||||
cfg_json = {};
|
||||
}
|
||||
if (!cfg_json) cfg_json = {};
|
||||
});
|
||||
|
||||
// Internal State
|
||||
let active_tab: 'visuals' | 'email' | 'ai' | 'refresh' | 'idaa' | 'raw' = $state('visuals');
|
||||
let raw_json_str = $state('');
|
||||
|
||||
// Ensure we have a valid object
|
||||
}
|
||||
if (!cfg_json) cfg_json = {};
|
||||
});
|
||||
|
||||
function add_to_list(key: string) {
|
||||
if (!cfg_json[key]) cfg_json[key] = [];
|
||||
const val = prompt('Enter Novi UUID:');
|
||||
if (val) cfg_json[key].push(val);
|
||||
// Internal State
|
||||
let active_tab: 'visuals' | 'email' | 'ai' | 'refresh' | 'idaa' | 'raw' =
|
||||
$state('visuals');
|
||||
let raw_json_str = $state('');
|
||||
|
||||
// Ensure we have a valid object
|
||||
if (!cfg_json) cfg_json = {};
|
||||
|
||||
function add_to_list(key: string) {
|
||||
if (!cfg_json[key]) cfg_json[key] = [];
|
||||
const val = prompt('Enter Novi UUID:');
|
||||
if (val) cfg_json[key].push(val);
|
||||
}
|
||||
|
||||
function remove_from_list(key: string, index: number) {
|
||||
cfg_json[key].splice(index, 1);
|
||||
}
|
||||
|
||||
// Sync Raw JSON string when entering the tab
|
||||
$effect(() => {
|
||||
if (active_tab === 'raw') {
|
||||
untrack(() => {
|
||||
raw_json_str = JSON.stringify(cfg_json, null, 2);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function remove_from_list(key: string, index: number) {
|
||||
cfg_json[key].splice(index, 1);
|
||||
// Update cfg_json when raw string changes
|
||||
$effect(() => {
|
||||
if (active_tab === 'raw' && raw_json_str) {
|
||||
try {
|
||||
const parsed = JSON.parse(raw_json_str);
|
||||
cfg_json = parsed;
|
||||
} catch (e) {
|
||||
// Ignore invalid JSON while typing
|
||||
}
|
||||
}
|
||||
|
||||
// Sync Raw JSON string when entering the tab
|
||||
$effect(() => {
|
||||
if (active_tab === 'raw') {
|
||||
untrack(() => {
|
||||
raw_json_str = JSON.stringify(cfg_json, null, 2);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Update cfg_json when raw string changes
|
||||
$effect(() => {
|
||||
if (active_tab === 'raw' && raw_json_str) {
|
||||
try {
|
||||
const parsed = JSON.parse(raw_json_str);
|
||||
cfg_json = parsed;
|
||||
} catch (e) {
|
||||
// Ignore invalid JSON while typing
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="ae-site-config-editor flex flex-col h-full space-y-4">
|
||||
<div class="ae-site-config-editor flex h-full flex-col space-y-4">
|
||||
<!-- Tab Navigation -->
|
||||
<div class="flex flex-wrap gap-1 p-1 bg-surface-500/10 rounded-lg max-w-fit">
|
||||
<button class="btn btn-sm transition-all {active_tab === 'visuals' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'visuals'}>
|
||||
<div
|
||||
class="bg-surface-500/10 flex max-w-fit flex-wrap gap-1 rounded-lg p-1">
|
||||
<button
|
||||
class="btn btn-sm transition-all {active_tab === 'visuals'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'visuals')}>
|
||||
<Palette size="1.1em" class="mr-1" /> Visuals
|
||||
</button>
|
||||
<button class="btn btn-sm transition-all {active_tab === 'email' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'email'}>
|
||||
<button
|
||||
class="btn btn-sm transition-all {active_tab === 'email'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'email')}>
|
||||
<Mail size="1.1em" class="mr-1" /> Email
|
||||
</button>
|
||||
<button class="btn btn-sm transition-all {active_tab === 'ai' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'ai'}>
|
||||
<button
|
||||
class="btn btn-sm transition-all {active_tab === 'ai'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'ai')}>
|
||||
<Brain size="1.1em" class="mr-1" /> AI/LLM
|
||||
</button>
|
||||
<button class="btn btn-sm transition-all {active_tab === 'refresh' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'refresh'}>
|
||||
<button
|
||||
class="btn btn-sm transition-all {active_tab === 'refresh'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'refresh')}>
|
||||
<Timer size="1.1em" class="mr-1" /> Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm transition-all {active_tab === 'idaa' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'idaa'}>
|
||||
<button
|
||||
class="btn btn-sm transition-all {active_tab === 'idaa'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'idaa')}>
|
||||
<ShieldCheck size="1.1em" class="mr-1" /> IDAA
|
||||
</button>
|
||||
<button class="btn btn-sm transition-all {active_tab === 'raw' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'raw'}>
|
||||
<button
|
||||
class="btn btn-sm transition-all {active_tab === 'raw'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'raw')}>
|
||||
<CodeXml size="1.1em" class="mr-1" /> Raw JSON
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Scrollable Content Area -->
|
||||
<div class="grow overflow-y-auto p-1 pr-2 space-y-6 max-h-[60vh]">
|
||||
|
||||
<div class="max-h-[60vh] grow space-y-6 overflow-y-auto p-1 pr-2">
|
||||
{#if active_tab === 'visuals'}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in duration-200">
|
||||
<div
|
||||
class="animate-in fade-in grid grid-cols-1 gap-4 duration-200 md:grid-cols-2">
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Theme Name</span>
|
||||
<input type="text" bind:value={cfg_json.theme_name} class="input variant-form-material" placeholder="e.g. AE_OSIT_default" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Theme Name</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.theme_name}
|
||||
class="input variant-form-material"
|
||||
placeholder="e.g. AE_OSIT_default" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Theme Mode</span>
|
||||
<select bind:value={cfg_json.theme_mode} class="select variant-form-material">
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Theme Mode</span>
|
||||
<select
|
||||
bind:value={cfg_json.theme_mode}
|
||||
class="select variant-form-material">
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="auto">Auto (System)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="label md:col-span-2">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Header Image Path (URL)</span>
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Header Image Path (URL)</span>
|
||||
<div class="flex gap-2">
|
||||
<input type="text" bind:value={cfg_json.header_image_path} class="input variant-form-material grow" placeholder="https://..." />
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.header_image_path}
|
||||
class="input variant-form-material grow"
|
||||
placeholder="https://..." />
|
||||
{#if cfg_json.header_image_path}
|
||||
<a href={cfg_json.header_image_path} target="_blank" rel="noopener noreferrer" class="btn-icon variant-soft-surface"><ExternalLink size="1.2em" /></a>
|
||||
<a
|
||||
href={cfg_json.header_image_path}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn-icon variant-soft-surface"
|
||||
><ExternalLink size="1.2em" /></a>
|
||||
{/if}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{:else if active_tab === 'email'}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in duration-200">
|
||||
<section class="space-y-4 border-r border-surface-500/10 pr-4">
|
||||
<h4 class="text-sm font-black text-primary-500">Admin Contact</h4>
|
||||
<div
|
||||
class="animate-in fade-in grid grid-cols-1 gap-4 duration-200 md:grid-cols-2">
|
||||
<section class="border-surface-500/10 space-y-4 border-r pr-4">
|
||||
<h4 class="text-primary-500 text-sm font-black">
|
||||
Admin Contact
|
||||
</h4>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Admin Name</span>
|
||||
<input type="text" bind:value={cfg_json.admin_name} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Admin Name</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.admin_name}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Admin Email</span>
|
||||
<input type="email" bind:value={cfg_json.admin_email} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Admin Email</span>
|
||||
<input
|
||||
type="email"
|
||||
bind:value={cfg_json.admin_email}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
</section>
|
||||
<section class="space-y-4">
|
||||
<h4 class="text-sm font-black text-secondary-500">System (No-Reply)</h4>
|
||||
<h4 class="text-secondary-500 text-sm font-black">
|
||||
System (No-Reply)
|
||||
</h4>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">No-Reply Name</span>
|
||||
<input type="text" bind:value={cfg_json.noreply_name} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>No-Reply Name</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.noreply_name}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">No-Reply Email</span>
|
||||
<input type="email" bind:value={cfg_json.noreply_email} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>No-Reply Email</span>
|
||||
<input
|
||||
type="email"
|
||||
bind:value={cfg_json.noreply_email}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{:else if active_tab === 'ai'}
|
||||
<div class="space-y-4 animate-in fade-in duration-200">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="animate-in fade-in space-y-4 duration-200">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">LLM API Base URL</span>
|
||||
<input type="text" bind:value={cfg_json.llm__api_base_url} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>LLM API Base URL</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.llm__api_base_url}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">LLM Model</span>
|
||||
<input type="text" bind:value={cfg_json.llm__api_model} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>LLM Model</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.llm__api_model}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
</div>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">API Token</span>
|
||||
<input type="password" bind:value={cfg_json.llm__api_token} class="input variant-form-material font-mono" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>API Token</span>
|
||||
<input
|
||||
type="password"
|
||||
bind:value={cfg_json.llm__api_token}
|
||||
class="input variant-form-material font-mono" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">System Prompt</span>
|
||||
<textarea bind:value={cfg_json.llm__system_prompt} class="textarea variant-form-material h-24 text-sm"></textarea>
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>System Prompt</span>
|
||||
<textarea
|
||||
bind:value={cfg_json.llm__system_prompt}
|
||||
class="textarea variant-form-material h-24 text-sm"
|
||||
></textarea>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2">
|
||||
<input type="checkbox" bind:checked={cfg_json.llm__api_dangerous_browser} class="checkbox" />
|
||||
<span class="text-xs font-bold uppercase opacity-50">Allow Browser Fetch (Dangerously)</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={cfg_json.llm__api_dangerous_browser}
|
||||
class="checkbox" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Allow Browser Fetch (Dangerously)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{:else if active_tab === 'refresh'}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in duration-200">
|
||||
<div
|
||||
class="animate-in fade-in grid grid-cols-1 gap-4 duration-200 md:grid-cols-2">
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Default (Minutes)</span>
|
||||
<input type="number" bind:value={cfg_json.default_refresh_minutes} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Default (Minutes)</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={cfg_json.default_refresh_minutes}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Authenticated (Minutes)</span>
|
||||
<input type="number" bind:value={cfg_json.authenticated_refresh_time} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Authenticated (Minutes)</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={cfg_json.authenticated_refresh_time}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Trusted (Minutes)</span>
|
||||
<input type="number" bind:value={cfg_json.trusted_refresh_minutes} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Trusted (Minutes)</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={cfg_json.trusted_refresh_minutes}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Manager (Minutes)</span>
|
||||
<input type="number" bind:value={cfg_json.manager_refresh_minutes} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Manager (Minutes)</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={cfg_json.manager_refresh_minutes}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{:else if active_tab === 'idaa'}
|
||||
<div class="space-y-6 animate-in fade-in duration-200">
|
||||
<div class="animate-in fade-in space-y-6 duration-200">
|
||||
<!-- Novi API -->
|
||||
<section class="space-y-4 p-4 bg-surface-500/5 rounded-xl border border-surface-500/10">
|
||||
<h4 class="text-sm font-black flex items-center gap-2">
|
||||
<section
|
||||
class="bg-surface-500/5 border-surface-500/10 space-y-4 rounded-xl border p-4">
|
||||
<h4 class="flex items-center gap-2 text-sm font-black">
|
||||
<Globe size="1.1em" class="text-primary-500" /> Novi API Connection
|
||||
</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">Root URL</span>
|
||||
<input type="text" bind:value={cfg_json.novi_api_root_url} class="input variant-form-material" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>Root URL</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={cfg_json.novi_api_root_url}
|
||||
class="input variant-form-material" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="text-xs font-bold uppercase opacity-50">API Key</span>
|
||||
<input type="password" bind:value={cfg_json.novi_idaa_api_key} class="input variant-form-material font-mono" />
|
||||
<span class="text-xs font-bold uppercase opacity-50"
|
||||
>API Key</span>
|
||||
<input
|
||||
type="password"
|
||||
bind:value={cfg_json.novi_idaa_api_key}
|
||||
class="input variant-form-material font-mono" />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- UUID Lists -->
|
||||
<section class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{#each [
|
||||
{ key: 'novi_admin_li', label: 'Novi Admins', color: 'text-error-500' },
|
||||
{ key: 'novi_trusted_li', label: 'Novi Trusted', color: 'text-warning-500' },
|
||||
{ key: 'novi_jitsi_mod_li', label: 'Jitsi Moderators', color: 'text-primary-500' },
|
||||
{ key: 'novi_idaa_group_guid_li', label: 'Member Group GUIDs', color: 'text-secondary-500' }
|
||||
] as list (list.key)}
|
||||
<div class="space-y-2 p-3 bg-surface-500/5 rounded-lg">
|
||||
<header class="flex justify-between items-center">
|
||||
<span class="text-[10px] font-black uppercase tracking-wider {list.color}">{list.label}</span>
|
||||
<button class="btn btn-icon btn-icon-sm variant-soft-primary" onclick={() => add_to_list(list.key)}>
|
||||
<section class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
{#each [{ key: 'novi_admin_li', label: 'Novi Admins', color: 'text-error-500' }, { key: 'novi_trusted_li', label: 'Novi Trusted', color: 'text-warning-500' }, { key: 'novi_jitsi_mod_li', label: 'Jitsi Moderators', color: 'text-primary-500' }, { key: 'novi_idaa_group_guid_li', label: 'Member Group GUIDs', color: 'text-secondary-500' }] as list (list.key)}
|
||||
<div class="bg-surface-500/5 space-y-2 rounded-lg p-3">
|
||||
<header class="flex items-center justify-between">
|
||||
<span
|
||||
class="text-[10px] font-black tracking-wider uppercase {list.color}"
|
||||
>{list.label}</span>
|
||||
<button
|
||||
class="btn btn-icon btn-icon-sm variant-soft-primary"
|
||||
onclick={() => add_to_list(list.key)}>
|
||||
<Plus size="12" />
|
||||
</button>
|
||||
</header>
|
||||
<div class="space-y-1">
|
||||
{#each cfg_json[list.key] ?? [] as uuid, i (uuid)}
|
||||
<div class="flex gap-1 items-center bg-surface-500/10 p-1 rounded font-mono text-[10px]">
|
||||
<span class="grow truncate">{uuid}</span>
|
||||
<button class="text-error-500 hover:scale-110 transition-transform" onclick={() => remove_from_list(list.key, i)}>
|
||||
<div
|
||||
class="bg-surface-500/10 flex items-center gap-1 rounded p-1 font-mono text-[10px]">
|
||||
<span class="grow truncate"
|
||||
>{uuid}</span>
|
||||
<button
|
||||
class="text-error-500 transition-transform hover:scale-110"
|
||||
onclick={() =>
|
||||
remove_from_list(list.key, i)}>
|
||||
<Minus size="12" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -240,62 +363,96 @@
|
||||
</section>
|
||||
|
||||
<!-- Notifications -->
|
||||
<section class="grid grid-cols-1 md:grid-cols-2 gap-4 p-4 bg-surface-500/5 rounded-xl">
|
||||
<section
|
||||
class="bg-surface-500/5 grid grid-cols-1 gap-4 rounded-xl p-4 md:grid-cols-2">
|
||||
<div class="space-y-2">
|
||||
<h4 class="text-[10px] font-black uppercase opacity-50">Bulletin Board</h4>
|
||||
<h4 class="text-[10px] font-black uppercase opacity-50">
|
||||
Bulletin Board
|
||||
</h4>
|
||||
<label class="flex items-center space-x-2 text-xs">
|
||||
<input type="checkbox" bind:checked={cfg_json.bb_send_staff_new_email} class="checkbox checkbox-sm" />
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={cfg_json.bb_send_staff_new_email}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span>Notify Staff (New)</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2 text-xs">
|
||||
<input type="checkbox" bind:checked={cfg_json.bb_send_staff_update_email} class="checkbox checkbox-sm" />
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
cfg_json.bb_send_staff_update_email
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span>Notify Staff (Update)</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2 text-xs">
|
||||
<input type="checkbox" bind:checked={cfg_json.bb_send_poster_email} class="checkbox checkbox-sm" />
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={cfg_json.bb_send_poster_email}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span>Notify Poster</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2 text-xs">
|
||||
<input type="checkbox" bind:checked={cfg_json.bb_send_commenter_email} class="checkbox checkbox-sm" />
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={cfg_json.bb_send_commenter_email}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span>Notify Commenters</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h4 class="text-[10px] font-black uppercase opacity-50">Recovery Meetings</h4>
|
||||
<h4 class="text-[10px] font-black uppercase opacity-50">
|
||||
Recovery Meetings
|
||||
</h4>
|
||||
<label class="flex items-center space-x-2 text-xs">
|
||||
<input type="checkbox" bind:checked={cfg_json.recovery_mtg_send_staff_new_email} class="checkbox checkbox-sm" />
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
cfg_json.recovery_mtg_send_staff_new_email
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span>Notify Staff (New)</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2 text-xs">
|
||||
<input type="checkbox" bind:checked={cfg_json.recovery_mtg_send_staff_update_email} class="checkbox checkbox-sm" />
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={
|
||||
cfg_json.recovery_mtg_send_staff_update_email
|
||||
}
|
||||
class="checkbox checkbox-sm" />
|
||||
<span>Notify Staff (Update)</span>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{:else if active_tab === 'raw'}
|
||||
<div class="h-[50vh] animate-in fade-in duration-200">
|
||||
<div class="animate-in fade-in h-[50vh] duration-200">
|
||||
<AE_Comp_Editor_CodeMirror
|
||||
content={raw_json_str}
|
||||
bind:new_content={raw_json_str}
|
||||
language="json"
|
||||
theme_mode={$ae_loc.theme_mode}
|
||||
class_li="h-full border border-surface-500/20 rounded-lg shadow-inner"
|
||||
/>
|
||||
class_li="h-full border border-surface-500/20 rounded-lg shadow-inner" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Action Bar -->
|
||||
<div class="flex justify-between items-center pt-4 border-t border-surface-500/10">
|
||||
<div
|
||||
class="border-surface-500/10 flex items-center justify-between border-t pt-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="flex items-center space-x-2 cursor-pointer">
|
||||
<input type="checkbox" bind:checked={cfg_json.test} class="checkbox" />
|
||||
<span class="text-xs font-bold uppercase text-warning-500">Test Mode</span>
|
||||
<label class="flex cursor-pointer items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={cfg_json.test}
|
||||
class="checkbox" />
|
||||
<span class="text-warning-500 text-xs font-bold uppercase"
|
||||
>Test Mode</span>
|
||||
</label>
|
||||
</div>
|
||||
<button class="btn btn-sm variant-filled-primary font-bold shadow-lg" onclick={on_save}>
|
||||
<button
|
||||
class="btn btn-sm variant-filled-primary font-bold shadow-lg"
|
||||
onclick={on_save}>
|
||||
<Save size="1.1em" class="mr-2" /> Save Config
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,9 @@ export async function load_ae_obj_id__account({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Account | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__account() *** account_id=${account_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__account() *** account_id=${account_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.load__account_obj = await api
|
||||
@@ -39,10 +41,11 @@ export async function load_ae_obj_id__account({
|
||||
.then(async function (account_obj_get_result) {
|
||||
if (account_obj_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__account_props({
|
||||
obj_li: [account_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__account_props({
|
||||
obj_li: [account_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'account',
|
||||
@@ -114,10 +117,11 @@ export async function load_ae_obj_li__account({
|
||||
.then(async function (account_obj_li_get_result) {
|
||||
if (account_obj_li_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__account_props({
|
||||
obj_li: account_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__account_props({
|
||||
obj_li: account_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'account',
|
||||
@@ -164,10 +168,11 @@ export async function create_ae_obj__account({
|
||||
.then(async function (account_obj_create_result) {
|
||||
if (account_obj_create_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__account_props({
|
||||
obj_li: [account_obj_create_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__account_props({
|
||||
obj_li: [account_obj_create_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'account',
|
||||
@@ -206,7 +211,10 @@ export async function update_ae_obj__account({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Account | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__account() *** account_id=${account_id}`, data_kv);
|
||||
console.log(
|
||||
`*** update_ae_obj__account() *** account_id=${account_id}`,
|
||||
data_kv
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.update_ae_obj({
|
||||
@@ -256,7 +264,9 @@ export async function delete_ae_obj_id__account({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__account() *** account_id=${account_id}`);
|
||||
console.log(
|
||||
`*** delete_ae_obj_id__account() *** account_id=${account_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.delete__account_obj = await api
|
||||
@@ -337,11 +347,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
|
||||
@@ -19,7 +19,9 @@ export async function load_ae_obj_id__activity_log({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_ActivityLog | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__activity_log() *** activity_log_id=${activity_log_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__activity_log() *** activity_log_id=${activity_log_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.load__activity_log_obj = await api.get_ae_obj({
|
||||
@@ -61,7 +63,9 @@ export async function load_ae_obj_li__activity_log({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_ActivityLog[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__activity_log() *** for_obj_id=${for_obj_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__activity_log() *** for_obj_id=${for_obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.load__activity_log_obj_li = await api.get_ae_obj_li({
|
||||
@@ -96,11 +100,15 @@ export async function create_ae_obj__activity_log({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_ActivityLog | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** create_ae_obj__activity_log() *** account_id=${account_id}`);
|
||||
console.log(
|
||||
`*** create_ae_obj__activity_log() *** account_id=${account_id}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!account_id) {
|
||||
console.log(`ERROR: Core - Activity Log - account_id required to create`);
|
||||
console.log(
|
||||
`ERROR: Core - Activity Log - account_id required to create`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -133,7 +141,9 @@ export async function update_ae_obj__activity_log({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_ActivityLog | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__activity_log() *** activity_log_id=${activity_log_id}`);
|
||||
console.log(
|
||||
`*** update_ae_obj__activity_log() *** activity_log_id=${activity_log_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.update__activity_log_obj = await api.update_ae_obj({
|
||||
@@ -151,7 +161,6 @@ export async function update_ae_obj__activity_log({
|
||||
// Updated 2026-01-07
|
||||
|
||||
export async function qry__activity_log({
|
||||
|
||||
api_cfg,
|
||||
|
||||
account_id,
|
||||
@@ -173,9 +182,7 @@ export async function qry__activity_log({
|
||||
order_by_li = { created_on: 'DESC' },
|
||||
|
||||
log_lvl = 0
|
||||
|
||||
}: {
|
||||
|
||||
api_cfg: any;
|
||||
|
||||
account_id: string;
|
||||
@@ -197,49 +204,36 @@ export async function qry__activity_log({
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'>;
|
||||
|
||||
log_lvl?: number;
|
||||
|
||||
}): Promise<ae_ActivityLog[]> {
|
||||
|
||||
const search_query: any = {};
|
||||
|
||||
const filters: any[] = [];
|
||||
|
||||
|
||||
|
||||
if (account_id) {
|
||||
|
||||
filters.push({ field: 'account_id_random', op: 'eq', value: account_id });
|
||||
|
||||
filters.push({
|
||||
field: 'account_id_random',
|
||||
op: 'eq',
|
||||
value: account_id
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (qry_person_id) {
|
||||
|
||||
filters.push({ field: 'person_id_random', op: 'eq', value: qry_person_id });
|
||||
|
||||
filters.push({
|
||||
field: 'person_id_random',
|
||||
op: 'eq',
|
||||
value: qry_person_id
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (filters.length > 0) {
|
||||
|
||||
search_query.and = filters;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (qry_str) {
|
||||
|
||||
search_query.q = qry_str;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
ae_promises.load__activity_log_obj_li = await api.search_ae_obj({
|
||||
|
||||
api_cfg,
|
||||
|
||||
obj_type: 'activity_log',
|
||||
@@ -259,13 +253,9 @@ export async function qry__activity_log({
|
||||
order_by_li,
|
||||
|
||||
log_lvl
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
return ae_promises.load__activity_log_obj_li;
|
||||
|
||||
}
|
||||
|
||||
// Updated 2026-02-16
|
||||
@@ -338,14 +328,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -367,5 +364,3 @@ export async function process_ae_obj__activity_log_props({
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,29 +23,34 @@ export async function load_ae_obj_id__address({
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Address | null> {
|
||||
ae_promises.load__address_obj = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'address',
|
||||
obj_id: address_id,
|
||||
view,
|
||||
params,
|
||||
log_lvl
|
||||
}).then(async (result) => {
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__address_props({ obj_li: [result], log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'address',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__address_obj = await api
|
||||
.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'address',
|
||||
obj_id: address_id,
|
||||
view,
|
||||
params,
|
||||
log_lvl
|
||||
})
|
||||
.then(async (result) => {
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__address_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'address',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
return ae_promises.load__address_obj;
|
||||
}
|
||||
|
||||
@@ -77,34 +82,39 @@ export async function load_ae_obj_li__address({
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Address[]> {
|
||||
ae_promises.load__address_obj_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'address',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
}).then(async (result) => {
|
||||
if (result && Array.isArray(result)) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__address_props({ obj_li: result, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'address',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__address_obj_li = await api
|
||||
.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'address',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
})
|
||||
.then(async (result) => {
|
||||
if (result && Array.isArray(result)) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__address_props({
|
||||
obj_li: result,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'address',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
return [];
|
||||
});
|
||||
return ae_promises.load__address_obj_li;
|
||||
}
|
||||
|
||||
@@ -136,7 +146,10 @@ export async function create_ae_obj__address({
|
||||
});
|
||||
|
||||
if (result && try_cache) {
|
||||
const processed = await process_ae_obj__address_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__address_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'address',
|
||||
@@ -174,7 +187,10 @@ export async function update_ae_obj__address({
|
||||
});
|
||||
|
||||
if (result && try_cache) {
|
||||
const processed = await process_ae_obj__address_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__address_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'address',
|
||||
@@ -269,7 +285,9 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
}
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -290,4 +308,4 @@ export async function process_ae_obj__address_props({
|
||||
obj_type: 'address',
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,29 +23,34 @@ export async function load_ae_obj_id__contact({
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Contact | null> {
|
||||
ae_promises.load__contact_obj = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'contact',
|
||||
obj_id: contact_id,
|
||||
view,
|
||||
params,
|
||||
log_lvl
|
||||
}).then(async (result) => {
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__contact_props({ obj_li: [result], log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'contact',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__contact_obj = await api
|
||||
.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'contact',
|
||||
obj_id: contact_id,
|
||||
view,
|
||||
params,
|
||||
log_lvl
|
||||
})
|
||||
.then(async (result) => {
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__contact_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'contact',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
return ae_promises.load__contact_obj;
|
||||
}
|
||||
|
||||
@@ -75,34 +80,39 @@ export async function load_ae_obj_li__contact({
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Contact[]> {
|
||||
ae_promises.load__contact_obj_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'contact',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
}).then(async (result) => {
|
||||
if (result && Array.isArray(result)) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__contact_props({ obj_li: result, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'contact',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__contact_obj_li = await api
|
||||
.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'contact',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
})
|
||||
.then(async (result) => {
|
||||
if (result && Array.isArray(result)) {
|
||||
if (try_cache) {
|
||||
const processed = await process_ae_obj__contact_props({
|
||||
obj_li: result,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'contact',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
return [];
|
||||
});
|
||||
return ae_promises.load__contact_obj_li;
|
||||
}
|
||||
|
||||
@@ -134,7 +144,10 @@ export async function create_ae_obj__contact({
|
||||
});
|
||||
|
||||
if (result && try_cache) {
|
||||
const processed = await process_ae_obj__contact_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__contact_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'contact',
|
||||
@@ -172,7 +185,10 @@ export async function update_ae_obj__contact({
|
||||
});
|
||||
|
||||
if (result && try_cache) {
|
||||
const processed = await process_ae_obj__contact_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__contact_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'contact',
|
||||
@@ -267,7 +283,9 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
}
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -288,4 +306,4 @@ export async function process_ae_obj__contact_props({
|
||||
obj_type: 'contact',
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,12 @@ export async function load_ae_obj_id__person({
|
||||
.then(async function (result) {
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__person_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj_li = await process_ae_obj__person_props(
|
||||
{
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
}
|
||||
);
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
@@ -98,7 +100,9 @@ export async function load_ae_obj_li__person({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Person[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__person() *** for_obj_id=${for_obj_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__person() *** for_obj_id=${for_obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
let promise;
|
||||
@@ -109,11 +113,19 @@ export async function load_ae_obj_li__person({
|
||||
};
|
||||
|
||||
if (qry_user_id) {
|
||||
search_query.and.push({ field: 'user_id_random', op: 'eq', value: qry_user_id });
|
||||
search_query.and.push({
|
||||
field: 'user_id_random',
|
||||
op: 'eq',
|
||||
value: qry_user_id
|
||||
});
|
||||
}
|
||||
|
||||
if (qry_email) {
|
||||
search_query.and.push({ field: 'primary_email', op: 'eq', value: qry_email });
|
||||
search_query.and.push({
|
||||
field: 'primary_email',
|
||||
op: 'eq',
|
||||
value: qry_email
|
||||
});
|
||||
}
|
||||
|
||||
if (for_obj_id) {
|
||||
@@ -161,26 +173,30 @@ export async function load_ae_obj_li__person({
|
||||
});
|
||||
}
|
||||
|
||||
ae_promises.load__person_obj_li = await promise.then(async function (result_li) {
|
||||
if (result_li) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__person_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__person_obj_li = await promise.then(
|
||||
async function (result_li) {
|
||||
if (result_li) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__person_props(
|
||||
{
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
}
|
||||
);
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result_li;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
return result_li;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
return ae_promises.load__person_obj_li;
|
||||
}
|
||||
@@ -411,11 +427,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.full_name ?? processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
|
||||
@@ -113,10 +113,18 @@ export async function lookup_site_domain({
|
||||
try {
|
||||
cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
||||
if (cached) {
|
||||
if (log_lvl) console.log('BOOTSTRAP: Cache hit. Returning cached site domain immediately.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'BOOTSTRAP: Cache hit. Returning cached site domain immediately.'
|
||||
);
|
||||
|
||||
// Trigger background refresh to keep cache fresh, but don't await it
|
||||
_refresh_site_domain_background({ api_cfg, fqdn, view, log_lvl: 0 });
|
||||
_refresh_site_domain_background({
|
||||
api_cfg,
|
||||
fqdn,
|
||||
view,
|
||||
log_lvl: 0
|
||||
});
|
||||
|
||||
return cached as any;
|
||||
}
|
||||
@@ -125,13 +133,23 @@ export async function lookup_site_domain({
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API if cache is empty
|
||||
return await _refresh_site_domain_background({ api_cfg, fqdn, view, log_lvl });
|
||||
return await _refresh_site_domain_background({
|
||||
api_cfg,
|
||||
fqdn,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper to perform the actual API fetch and cache update
|
||||
*/
|
||||
async function _refresh_site_domain_background({ api_cfg, fqdn, view, log_lvl }: any) {
|
||||
async function _refresh_site_domain_background({
|
||||
api_cfg,
|
||||
fqdn,
|
||||
view,
|
||||
log_lvl
|
||||
}: any) {
|
||||
try {
|
||||
const guest_api_cfg = { ...api_cfg };
|
||||
guest_api_cfg.headers = { ...api_cfg.headers };
|
||||
@@ -144,7 +162,7 @@ async function _refresh_site_domain_background({ api_cfg, fqdn, view, log_lvl }:
|
||||
'JWT'
|
||||
];
|
||||
|
||||
auth_props.forEach(prop => {
|
||||
auth_props.forEach((prop) => {
|
||||
delete guest_api_cfg.headers[prop];
|
||||
delete guest_api_cfg.headers[prop.toLowerCase()];
|
||||
delete guest_api_cfg.headers[prop.replaceAll('-', '_')];
|
||||
@@ -481,11 +499,12 @@ export async function load_ae_obj_li__site_domain({
|
||||
.then(async function (domain_li) {
|
||||
if (domain_li) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__site_domain_props({
|
||||
obj_li: domain_li,
|
||||
site_id,
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__site_domain_props({
|
||||
obj_li: domain_li,
|
||||
site_id,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'site_domain',
|
||||
@@ -729,11 +748,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? processed_obj.fqdn ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
|
||||
@@ -93,7 +93,9 @@ export async function load_ae_obj_li__user({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_User[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__user() *** for_obj_id=${for_obj_id} include_global=${include_global} qry_str=${qry_str}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__user() *** for_obj_id=${for_obj_id} include_global=${include_global} qry_str=${qry_str}`
|
||||
);
|
||||
}
|
||||
|
||||
// SCENARIO A: Text Search
|
||||
@@ -107,9 +109,17 @@ export async function load_ae_obj_li__user({
|
||||
]
|
||||
});
|
||||
} else if (for_obj_id) {
|
||||
search_query.and.push({ field: `account_id_random`, op: 'eq', value: for_obj_id });
|
||||
search_query.and.push({
|
||||
field: `account_id_random`,
|
||||
op: 'eq',
|
||||
value: for_obj_id
|
||||
});
|
||||
} else if (include_global) {
|
||||
search_query.and.push({ field: `account_id_random`, op: 'eq', value: null });
|
||||
search_query.and.push({
|
||||
field: `account_id_random`,
|
||||
op: 'eq',
|
||||
value: null
|
||||
});
|
||||
}
|
||||
|
||||
return await api.search_ae_obj({
|
||||
@@ -130,13 +140,33 @@ export async function load_ae_obj_li__user({
|
||||
if (for_obj_id && include_global) {
|
||||
if (log_lvl) console.log('Strategy: Multi-call (Account + Global)');
|
||||
const [acct_users, global_users] = await Promise.all([
|
||||
load_ae_obj_li__user({ api_cfg, for_obj_id, include_global: false, enabled, hidden, view, limit, log_lvl }),
|
||||
load_ae_obj_li__user({ api_cfg, for_obj_id: null, include_global: true, enabled, hidden, view, limit, log_lvl })
|
||||
load_ae_obj_li__user({
|
||||
api_cfg,
|
||||
for_obj_id,
|
||||
include_global: false,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
log_lvl
|
||||
}),
|
||||
load_ae_obj_li__user({
|
||||
api_cfg,
|
||||
for_obj_id: null,
|
||||
include_global: true,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
log_lvl
|
||||
})
|
||||
]);
|
||||
|
||||
// Merge and unique-ify by ID
|
||||
const merged = [...acct_users, ...global_users];
|
||||
const unique = Array.from(new Map(merged.map(u => [u.user_id_random, u])).values());
|
||||
const unique = Array.from(
|
||||
new Map(merged.map((u) => [u.user_id_random, u])).values()
|
||||
);
|
||||
return unique;
|
||||
}
|
||||
|
||||
@@ -162,7 +192,8 @@ export async function load_ae_obj_li__user({
|
||||
}
|
||||
|
||||
// SCENARIO D: Account Only or Everything (confirmed working List API)
|
||||
if (log_lvl) console.log(`Strategy: Standard List API (for_obj_id=${for_obj_id})`);
|
||||
if (log_lvl)
|
||||
console.log(`Strategy: Standard List API (for_obj_id=${for_obj_id})`);
|
||||
return await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'user',
|
||||
@@ -383,7 +414,10 @@ export async function auth_ae_obj__username_password({
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.auth__username_password:', ae_promises.auth__username_password);
|
||||
console.log(
|
||||
'ae_promises.auth__username_password:',
|
||||
ae_promises.auth__username_password
|
||||
);
|
||||
}
|
||||
return ae_promises.auth__username_password;
|
||||
}
|
||||
@@ -450,7 +484,10 @@ export async function auth_ae_obj__user_id_user_auth_key({
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.auth__user_id_user_key:', ae_promises.auth__user_id_user_key);
|
||||
console.log(
|
||||
'ae_promises.auth__user_id_user_key:',
|
||||
ae_promises.auth__user_id_user_key
|
||||
);
|
||||
}
|
||||
return ae_promises.auth__user_id_user_key;
|
||||
}
|
||||
@@ -525,7 +562,9 @@ export async function qry_ae_obj_li__user_email({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`);
|
||||
console.log(
|
||||
`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`
|
||||
);
|
||||
}
|
||||
|
||||
const endpoint = '/user/lookup_email';
|
||||
@@ -676,11 +715,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.username ?? processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -701,4 +744,4 @@ export async function process_ae_obj__user_props({
|
||||
obj_type: 'user',
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ import {
|
||||
auth_ae_obj__user_id_change_password
|
||||
} from '$lib/ae_core/ae_core__user';
|
||||
|
||||
import { generate_qr_code, js_generate_qr_code } from '$lib/ae_core/core__qr_code';
|
||||
import {
|
||||
generate_qr_code,
|
||||
js_generate_qr_code
|
||||
} from '$lib/ae_core/core__qr_code';
|
||||
|
||||
import { check_hosted_file_obj_w_hash } from '$lib/ae_core/core__check_hosted_file_obj_w_hash';
|
||||
|
||||
@@ -161,7 +164,9 @@ async function load_ae_obj_code__data_store({
|
||||
}
|
||||
|
||||
if (!get_ds_result.data_store_id_random) {
|
||||
console.log('*ae_func* Something went wrong? No data store ID found.');
|
||||
console.log(
|
||||
'*ae_func* Something went wrong? No data store ID found.'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -240,7 +245,10 @@ async function load_ae_obj_code__data_store({
|
||||
get_ds_result
|
||||
);
|
||||
}
|
||||
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
|
||||
localStorage.setItem(
|
||||
`${key_prefix}${code}`,
|
||||
JSON.stringify(get_ds_result)
|
||||
);
|
||||
} else {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
@@ -491,7 +499,10 @@ async function download_export__obj_type({
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
console.log('ae_promises.download__export_file:', ae_promises.download__export_file);
|
||||
console.log(
|
||||
'ae_promises.download__export_file:',
|
||||
ae_promises.download__export_file
|
||||
);
|
||||
return ae_promises.download__export_file;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,17 @@ export function add_url_params({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** add_url_params() *** base_url=${base_url} endpoint=${endpoint}`, params);
|
||||
console.log(
|
||||
`*** add_url_params() *** base_url=${base_url} endpoint=${endpoint}`,
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
const url_obj = new URL(endpoint, base_url);
|
||||
|
||||
Object.keys(params).forEach((key) => url_obj.searchParams.append(key, params[key]));
|
||||
Object.keys(params).forEach((key) =>
|
||||
url_obj.searchParams.append(key, params[key])
|
||||
);
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('New URL:', url_obj.toString());
|
||||
@@ -30,7 +35,13 @@ export function add_url_params({
|
||||
|
||||
// This is used to clean the header property names. Not underscores allowed in the header names.
|
||||
// Updated 2025-01-28
|
||||
export function clean_headers({ headers, log_lvl = 0 }: { headers: any; log_lvl?: number }) {
|
||||
export function clean_headers({
|
||||
headers,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
headers: any;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** clean_headers() ***`, headers);
|
||||
}
|
||||
|
||||
@@ -33,8 +33,14 @@ async function _refresh_lu_country_background({
|
||||
if (result?.length) {
|
||||
await db_lookups.lu_country.clear();
|
||||
await db_lookups.lu_country.bulkPut(result);
|
||||
await db_lookups.lu_cache_meta.put({ lu_type: 'country', refreshed_at: Date.now() });
|
||||
if (log_lvl) console.log(`lu_country: saved ${result.length} records to IDB`);
|
||||
await db_lookups.lu_cache_meta.put({
|
||||
lu_type: 'country',
|
||||
refreshed_at: Date.now()
|
||||
});
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`lu_country: saved ${result.length} records to IDB`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('lu_country refresh failed:', error);
|
||||
@@ -59,6 +65,8 @@ export async function load_ae_obj_li__country({
|
||||
// Fire-and-forget — liveQuery subscribers receive updates when IDB is written
|
||||
_refresh_lu_country_background({ api_cfg, log_lvl });
|
||||
} else if (log_lvl) {
|
||||
console.log(`lu_country: IDB fresh (${count} records), skipping refresh`);
|
||||
console.log(
|
||||
`lu_country: IDB fresh (${count} records), skipping refresh`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ async function _refresh_lu_country_subdivision_background({
|
||||
api_cfg: any;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) console.log('*** _refresh_lu_country_subdivision_background() ***');
|
||||
if (log_lvl)
|
||||
console.log('*** _refresh_lu_country_subdivision_background() ***');
|
||||
try {
|
||||
const result = await api.get_ae_obj_li_for_lu({
|
||||
api_cfg,
|
||||
@@ -37,7 +38,9 @@ async function _refresh_lu_country_subdivision_background({
|
||||
refreshed_at: Date.now()
|
||||
});
|
||||
if (log_lvl)
|
||||
console.log(`lu_country_subdivision: saved ${result.length} records to IDB`);
|
||||
console.log(
|
||||
`lu_country_subdivision: saved ${result.length} records to IDB`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('lu_country_subdivision refresh failed:', error);
|
||||
@@ -61,6 +64,8 @@ export async function load_ae_obj_li__country_subdivision({
|
||||
if (count === 0 || is_stale) {
|
||||
_refresh_lu_country_subdivision_background({ api_cfg, log_lvl });
|
||||
} else if (log_lvl) {
|
||||
console.log(`lu_country_subdivision: IDB fresh (${count} records), skipping refresh`);
|
||||
console.log(
|
||||
`lu_country_subdivision: IDB fresh (${count} records), skipping refresh`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,16 +50,24 @@ export async function load_ae_obj_by_code__data_store({
|
||||
return null;
|
||||
}
|
||||
|
||||
const ds_id = get_ds_result.data_store_id_random || get_ds_result.id_random;
|
||||
const ds_id =
|
||||
get_ds_result.data_store_id_random || get_ds_result.id_random;
|
||||
|
||||
if (!ds_id) {
|
||||
if (log_lvl) console.log('*ae_func* Something went wrong? No data store ID found.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'*ae_func* Something went wrong? No data store ID found.'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Map content fields for convenience
|
||||
const text_val = get_ds_result.text || '';
|
||||
const json_val = get_ds_result.json || (get_ds_result.json_str ? JSON.parse(get_ds_result.json_str) : null);
|
||||
const json_val =
|
||||
get_ds_result.json ||
|
||||
(get_ds_result.json_str
|
||||
? JSON.parse(get_ds_result.json_str)
|
||||
: null);
|
||||
|
||||
const mapped_ds: ae_DataStore = {
|
||||
...get_ds_result,
|
||||
@@ -77,7 +85,6 @@ export async function load_ae_obj_by_code__data_store({
|
||||
if (data_type === 'html') return mapped_ds.html;
|
||||
if (data_type === 'json') return mapped_ds.json;
|
||||
return mapped_ds.text;
|
||||
|
||||
} catch (error) {
|
||||
if (log_lvl) console.error('*ae_func* Fetch failed.', error);
|
||||
return null;
|
||||
|
||||
@@ -22,7 +22,9 @@ export async function load_ae_obj_id__hosted_file({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_HostedFile | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__hosted_file() *** [V3] id=${hosted_file_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__hosted_file() *** [V3] id=${hosted_file_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -36,10 +38,11 @@ export async function load_ae_obj_id__hosted_file({
|
||||
|
||||
if (ae_promises.load__hosted_file_obj) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__hosted_file_props({
|
||||
obj_li: [ae_promises.load__hosted_file_obj],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__hosted_file_props({
|
||||
obj_li: [ae_promises.load__hosted_file_obj],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'file',
|
||||
@@ -49,12 +52,14 @@ export async function load_ae_obj_id__hosted_file({
|
||||
});
|
||||
}
|
||||
} else if (try_cache) {
|
||||
ae_promises.load__hosted_file_obj = await db_core.file.get(hosted_file_id);
|
||||
ae_promises.load__hosted_file_obj =
|
||||
await db_core.file.get(hosted_file_id);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('V3 Request failed.', error);
|
||||
if (try_cache) {
|
||||
ae_promises.load__hosted_file_obj = await db_core.file.get(hosted_file_id);
|
||||
ae_promises.load__hosted_file_obj =
|
||||
await db_core.file.get(hosted_file_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +95,9 @@ export async function load_ae_obj_li__hosted_file({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_HostedFile[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__hosted_file() *** [V3] for=${for_obj_type}:${for_obj_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__hosted_file() *** [V3] for=${for_obj_type}:${for_obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -109,10 +116,11 @@ export async function load_ae_obj_li__hosted_file({
|
||||
|
||||
if (ae_promises.load__hosted_file_obj_li) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__hosted_file_props({
|
||||
obj_li: ae_promises.load__hosted_file_obj_li,
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__hosted_file_props({
|
||||
obj_li: ae_promises.load__hosted_file_obj_li,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'file',
|
||||
@@ -123,14 +131,16 @@ export async function load_ae_obj_li__hosted_file({
|
||||
}
|
||||
} else if (try_cache) {
|
||||
ae_promises.load__hosted_file_obj_li = await db_core.file
|
||||
.where('for_id').equals(for_obj_id)
|
||||
.where('for_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('V3 List Request failed.', error);
|
||||
if (try_cache) {
|
||||
ae_promises.load__hosted_file_obj_li = await db_core.file
|
||||
.where('for_id').equals(for_obj_id)
|
||||
.where('for_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
}
|
||||
}
|
||||
@@ -159,7 +169,9 @@ export async function delete_ae_obj_id__hosted_file({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__hosted_file() *** [Special] id=${hosted_file_id}`);
|
||||
console.log(
|
||||
`*** delete_ae_obj_id__hosted_file() *** [Special] id=${hosted_file_id}`
|
||||
);
|
||||
}
|
||||
|
||||
// Use the specialized hosted file delete endpoint
|
||||
@@ -203,7 +215,9 @@ export async function download_ae_obj_id__hosted_file({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** download_ae_obj_id__hosted_file() *** id=${hosted_file_id}`);
|
||||
console.log(
|
||||
`*** download_ae_obj_id__hosted_file() *** id=${hosted_file_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const task_id = hosted_file_id;
|
||||
@@ -290,11 +304,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -315,4 +333,4 @@ export async function process_ae_obj__hosted_file_props({
|
||||
obj_type: 'hosted_file',
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ function find_object_id(
|
||||
log_lvl: number
|
||||
): string | number | undefined {
|
||||
const potential_keys = [
|
||||
'id',
|
||||
'id_random',
|
||||
`${table_name}_id`,
|
||||
'id',
|
||||
'id_random',
|
||||
`${table_name}_id`,
|
||||
`${table_name}_id_random`,
|
||||
`event_${table_name}_id`,
|
||||
`event_${table_name}_id_random`
|
||||
@@ -115,7 +115,9 @@ export async function db_save_ae_obj_li__ae_obj<T extends Record<string, any>>({
|
||||
|
||||
if (data_to_save.length === 0) {
|
||||
if (log_lvl > 0) {
|
||||
console.warn('All objects were skipped, likely due to missing IDs.');
|
||||
console.warn(
|
||||
'All objects were skipped, likely due to missing IDs.'
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -124,7 +126,9 @@ export async function db_save_ae_obj_li__ae_obj<T extends Record<string, any>>({
|
||||
// bulkPut efficiently handles both inserts and updates.
|
||||
const keys = await db_table.bulkPut(data_to_save);
|
||||
if (log_lvl > 0) {
|
||||
console.log(`Successfully saved ${data_to_save.length} objects to "${table_name}".`);
|
||||
console.log(
|
||||
`Successfully saved ${data_to_save.length} objects to "${table_name}".`
|
||||
);
|
||||
}
|
||||
return keys;
|
||||
} catch (error) {
|
||||
|
||||
@@ -49,7 +49,8 @@ export async function generate_qr_code({
|
||||
|
||||
if (qr_type == 'vcard') {
|
||||
if (qr_data.informal_name) {
|
||||
params['n'] = `${qr_data.family_name};${qr_data.given_name};${qr_data.informal_name}`;
|
||||
params['n'] =
|
||||
`${qr_data.family_name};${qr_data.given_name};${qr_data.informal_name}`;
|
||||
} else {
|
||||
params['n'] = `${qr_data.family_name};${qr_data.given_name}`;
|
||||
}
|
||||
@@ -99,7 +100,8 @@ export async function generate_qr_code({
|
||||
|
||||
// If return_blob is true, ensure we return an object URL for use in <img src=...>
|
||||
if (return_blob) {
|
||||
const data = ae_promises.generate_qr_code.data ?? ae_promises.generate_qr_code;
|
||||
const data =
|
||||
ae_promises.generate_qr_code.data ?? ae_promises.generate_qr_code;
|
||||
|
||||
// If already a Blob, use it directly
|
||||
if (data instanceof Blob) {
|
||||
@@ -133,7 +135,8 @@ export async function generate_qr_code({
|
||||
const blob = new Blob([data as BlobPart], { type: 'image/png' });
|
||||
return URL.createObjectURL(blob);
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error('Could not create QR code image blob:', e, data);
|
||||
if (log_lvl)
|
||||
console.error('Could not create QR code image blob:', e, data);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +158,10 @@ export async function generate_qr_code({
|
||||
* @returns {Promise<string>} A promise that resolves to a Base64 data URL of the QR code image.
|
||||
* @throws {Error} If the qr_type is unknown or data is missing.
|
||||
*/
|
||||
export async function js_generate_qr_code(qr_type: string, params: key_val = {}) {
|
||||
export async function js_generate_qr_code(
|
||||
qr_type: string,
|
||||
params: key_val = {}
|
||||
) {
|
||||
const {
|
||||
n = '',
|
||||
fn = '',
|
||||
@@ -179,7 +185,8 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
||||
log_lvl = 0
|
||||
} = params;
|
||||
|
||||
if (log_lvl >= 2) console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params);
|
||||
if (log_lvl >= 2)
|
||||
console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params);
|
||||
|
||||
let qr_data: string | null = null;
|
||||
|
||||
@@ -211,13 +218,15 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
||||
|
||||
case 'obj':
|
||||
// Custom format: OBJ:ot:obj_type,oi:obj_id
|
||||
if (!obj_type || !obj_id) throw new Error('Missing obj_type or obj_id for type "obj".');
|
||||
if (!obj_type || !obj_id)
|
||||
throw new Error('Missing obj_type or obj_id for type "obj".');
|
||||
qr_data = `OBJ:ot:${obj_type},oi:${obj_id}`;
|
||||
break;
|
||||
|
||||
case 'kv':
|
||||
// Custom format: KV:k:"key",v:"val"
|
||||
if (!key || !val) throw new Error('Missing key or val for type "kv".');
|
||||
if (!key || !val)
|
||||
throw new Error('Missing key or val for type "kv".');
|
||||
qr_data = `KV:k:"${key}",v:"${val}"`;
|
||||
break;
|
||||
|
||||
@@ -229,7 +238,8 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
||||
|
||||
case 'str':
|
||||
// Raw string data
|
||||
if (!str) throw new Error('Missing raw string data for type "str".');
|
||||
if (!str)
|
||||
throw new Error('Missing raw string data for type "str".');
|
||||
qr_data = str;
|
||||
break;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ async function _refresh_lu_time_zone_background({
|
||||
for_lu_type: 'time_zone',
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
only_priority: true, // ~72 priority timezone records
|
||||
only_priority: true, // ~72 priority timezone records
|
||||
limit: 1800,
|
||||
log_lvl
|
||||
});
|
||||
@@ -38,7 +38,10 @@ async function _refresh_lu_time_zone_background({
|
||||
lu_type: 'time_zone',
|
||||
refreshed_at: Date.now()
|
||||
});
|
||||
if (log_lvl) console.log(`lu_time_zone: saved ${result.length} records to IDB`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`lu_time_zone: saved ${result.length} records to IDB`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('lu_time_zone refresh failed:', error);
|
||||
@@ -62,6 +65,8 @@ export async function load_ae_obj_li__time_zone({
|
||||
if (count === 0 || is_stale) {
|
||||
_refresh_lu_time_zone_background({ api_cfg, log_lvl });
|
||||
} else if (log_lvl) {
|
||||
console.log(`lu_time_zone: IDB fresh (${count} records), skipping refresh`);
|
||||
console.log(
|
||||
`lu_time_zone: IDB fresh (${count} records), skipping refresh`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import Dexie, { type Table } from 'dexie';
|
||||
|
||||
export interface LuCountry {
|
||||
id: number;
|
||||
group: string; // dedup key = alpha_2_code (e.g. "US")
|
||||
group: string; // dedup key = alpha_2_code (e.g. "US")
|
||||
alpha_2_code: string;
|
||||
name: string;
|
||||
english_short_name?: string;
|
||||
@@ -22,12 +22,12 @@ export interface LuCountry {
|
||||
priority?: number;
|
||||
sort?: number;
|
||||
account_id?: number | null;
|
||||
[key: string]: unknown; // allow extra fields from API without TS errors
|
||||
[key: string]: unknown; // allow extra fields from API without TS errors
|
||||
}
|
||||
|
||||
export interface LuCountrySubdivision {
|
||||
id: number;
|
||||
group: string; // dedup key = code (e.g. "US-NY")
|
||||
group: string; // dedup key = code (e.g. "US-NY")
|
||||
code: string;
|
||||
name: string;
|
||||
country_alpha_2_code?: string;
|
||||
@@ -42,9 +42,9 @@ export interface LuCountrySubdivision {
|
||||
|
||||
export interface LuTimeZone {
|
||||
id: number;
|
||||
group: string; // dedup key = name (IANA identifier, e.g. "US/Eastern")
|
||||
group: string; // dedup key = name (IANA identifier, e.g. "US/Eastern")
|
||||
name: string;
|
||||
name_override?: string; // display label override; prefer this over name when set
|
||||
name_override?: string; // display label override; prefer this over name when set
|
||||
enable?: number;
|
||||
hide?: number;
|
||||
priority?: number;
|
||||
@@ -55,7 +55,7 @@ export interface LuTimeZone {
|
||||
|
||||
export interface LuCacheMeta {
|
||||
lu_type: 'country' | 'country_subdivision' | 'time_zone';
|
||||
refreshed_at: number; // Unix timestamp ms — used for 24h TTL check
|
||||
refreshed_at: number; // Unix timestamp ms — used for 24h TTL check
|
||||
}
|
||||
|
||||
class LookupsDexie extends Dexie {
|
||||
@@ -67,10 +67,10 @@ class LookupsDexie extends Dexie {
|
||||
constructor() {
|
||||
super('ae_lookups_db');
|
||||
this.version(1).stores({
|
||||
lu_country: 'id, alpha_2_code, group',
|
||||
lu_country: 'id, alpha_2_code, group',
|
||||
lu_country_subdivision: 'id, code, country_alpha_2_code, group',
|
||||
lu_time_zone: 'id, name, group',
|
||||
lu_cache_meta: 'lu_type'
|
||||
lu_time_zone: 'id, name, group',
|
||||
lu_cache_meta: 'lu_type'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,125 +1,140 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* AE_AITools.svelte
|
||||
* GENERIC Aether AI Toolset (Runes/Svelte 5)
|
||||
* Extracted logic from Journals module to be system-wide.
|
||||
*/
|
||||
import OpenAI from 'openai';
|
||||
import { Modal } from 'flowbite-svelte';
|
||||
import {
|
||||
Bot, BotMessageSquare, Loader, FileText,
|
||||
Save, FilePenLine, RotateCcw, Settings,
|
||||
RefreshCcw, Globe, Copy
|
||||
} from '@lucide/svelte';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte';
|
||||
/**
|
||||
* AE_AITools.svelte
|
||||
* GENERIC Aether AI Toolset (Runes/Svelte 5)
|
||||
* Extracted logic from Journals module to be system-wide.
|
||||
*/
|
||||
import OpenAI from 'openai';
|
||||
import { Modal } from 'flowbite-svelte';
|
||||
import {
|
||||
Bot,
|
||||
BotMessageSquare,
|
||||
Loader,
|
||||
FileText,
|
||||
Save,
|
||||
FilePenLine,
|
||||
RotateCcw,
|
||||
Settings,
|
||||
RefreshCcw,
|
||||
Globe,
|
||||
Copy
|
||||
} from '@lucide/svelte';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte';
|
||||
|
||||
interface Props {
|
||||
// Core Props
|
||||
content: string; // The text to summarize/analyze
|
||||
summary: string; // The result (bindable)
|
||||
|
||||
// Configuration (Bindable for global settings persistence)
|
||||
model?: string;
|
||||
baseUrl?: string;
|
||||
token?: string;
|
||||
systemPrompt?: string;
|
||||
maxTokens?: number;
|
||||
temperature?: number;
|
||||
|
||||
// Callbacks
|
||||
onSave?: (newSummary: string) => void;
|
||||
onSyncConfig?: () => void; // Optional: callback to sync from global site config
|
||||
|
||||
// UI Customization
|
||||
buttonClass?: string;
|
||||
log_lvl?: number;
|
||||
interface Props {
|
||||
// Core Props
|
||||
content: string; // The text to summarize/analyze
|
||||
summary: string; // The result (bindable)
|
||||
|
||||
// Configuration (Bindable for global settings persistence)
|
||||
model?: string;
|
||||
baseUrl?: string;
|
||||
token?: string;
|
||||
systemPrompt?: string;
|
||||
maxTokens?: number;
|
||||
temperature?: number;
|
||||
|
||||
// Callbacks
|
||||
onSave?: (newSummary: string) => void;
|
||||
onSyncConfig?: () => void; // Optional: callback to sync from global site config
|
||||
|
||||
// UI Customization
|
||||
buttonClass?: string;
|
||||
log_lvl?: number;
|
||||
}
|
||||
|
||||
let {
|
||||
content,
|
||||
summary = $bindable(),
|
||||
model = $bindable(),
|
||||
baseUrl = $bindable(),
|
||||
token = $bindable(),
|
||||
systemPrompt = $bindable(),
|
||||
maxTokens = $bindable(),
|
||||
temperature = $bindable(),
|
||||
onSave,
|
||||
onSyncConfig,
|
||||
buttonClass = 'btn btn-sm preset-tonal-primary shadow-lg hover:scale-105 transition-all',
|
||||
log_lvl = 0
|
||||
}: Props = $props();
|
||||
|
||||
// Apply defaults if undefined (Safe for Svelte 5 Runes)
|
||||
if (model === undefined) model = 'dgrzone-deepseek-8b-quick';
|
||||
if (baseUrl === undefined) baseUrl = 'https://ai.dgrzone.com/api';
|
||||
if (token === undefined) token = '';
|
||||
if (systemPrompt === undefined) systemPrompt = 'You are a helpful assistant.';
|
||||
if (maxTokens === undefined) maxTokens = 512;
|
||||
if (temperature === undefined) temperature = 0.7;
|
||||
|
||||
// Internal State
|
||||
let ae_promises: any = $state(null);
|
||||
let show_modal = $state(false);
|
||||
let active_tab: 'result' | 'settings' = $state('result');
|
||||
let tmp_summary = $state('');
|
||||
|
||||
async function generate_ai_result() {
|
||||
if (!content) {
|
||||
alert('No content available to analyze.');
|
||||
return;
|
||||
}
|
||||
|
||||
let {
|
||||
content,
|
||||
summary = $bindable(),
|
||||
model = $bindable(),
|
||||
baseUrl = $bindable(),
|
||||
token = $bindable(),
|
||||
systemPrompt = $bindable(),
|
||||
maxTokens = $bindable(),
|
||||
temperature = $bindable(),
|
||||
onSave,
|
||||
onSyncConfig,
|
||||
buttonClass = "btn btn-sm preset-tonal-primary shadow-lg hover:scale-105 transition-all",
|
||||
log_lvl = 0
|
||||
}: Props = $props();
|
||||
active_tab = 'result';
|
||||
|
||||
// Apply defaults if undefined (Safe for Svelte 5 Runes)
|
||||
if (model === undefined) model = 'dgrzone-deepseek-8b-quick';
|
||||
if (baseUrl === undefined) baseUrl = 'https://ai.dgrzone.com/api';
|
||||
if (token === undefined) token = '';
|
||||
if (systemPrompt === undefined) systemPrompt = 'You are a helpful assistant.';
|
||||
if (maxTokens === undefined) maxTokens = 512;
|
||||
if (temperature === undefined) temperature = 0.7;
|
||||
|
||||
// Internal State
|
||||
let ae_promises: any = $state(null);
|
||||
let show_modal = $state(false);
|
||||
let active_tab: 'result' | 'settings' = $state('result');
|
||||
let tmp_summary = $state('');
|
||||
|
||||
async function generate_ai_result() {
|
||||
if (!content) {
|
||||
alert('No content available to analyze.');
|
||||
return;
|
||||
}
|
||||
|
||||
active_tab = 'result';
|
||||
|
||||
// If no token is provided, trigger a "Demo Mode" placeholder after a fake delay
|
||||
if (!token || token === '') {
|
||||
console.log('AE_AITools: No token provided. Entering Demo Mode.');
|
||||
ae_promises = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
tmp_summary = `### AI Summary (DEMO MODE)\n\nThis is a placeholder summary because no API token was provided in the settings. \n\n**Original Content Length:** ${content.length} characters.\n\n**System Prompt:** ${systemPrompt}\n\n**Model:** ${model}`;
|
||||
show_modal = true;
|
||||
resolve(true);
|
||||
}, 1500);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const ai_client = new OpenAI({
|
||||
apiKey: token,
|
||||
baseURL: baseUrl,
|
||||
dangerouslyAllowBrowser: true
|
||||
// If no token is provided, trigger a "Demo Mode" placeholder after a fake delay
|
||||
if (!token || token === '') {
|
||||
console.log('AE_AITools: No token provided. Entering Demo Mode.');
|
||||
ae_promises = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
tmp_summary = `### AI Summary (DEMO MODE)\n\nThis is a placeholder summary because no API token was provided in the settings. \n\n**Original Content Length:** ${content.length} characters.\n\n**System Prompt:** ${systemPrompt}\n\n**Model:** ${model}`;
|
||||
show_modal = true;
|
||||
resolve(true);
|
||||
}, 1500);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ae_promises = ai_client.chat.completions.create({
|
||||
const ai_client = new OpenAI({
|
||||
apiKey: token,
|
||||
baseURL: baseUrl,
|
||||
dangerouslyAllowBrowser: true
|
||||
});
|
||||
|
||||
try {
|
||||
ae_promises = ai_client.chat.completions
|
||||
.create({
|
||||
model: model || 'dgrzone-deepseek-8b-quick',
|
||||
max_tokens: maxTokens,
|
||||
temperature: temperature,
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt || 'You are a helpful assistant.' },
|
||||
{
|
||||
role: 'system',
|
||||
content: systemPrompt || 'You are a helpful assistant.'
|
||||
},
|
||||
{ role: 'user', content: content }
|
||||
]
|
||||
}).then((resp) => {
|
||||
const result = resp?.choices?.[0]?.message?.content || 'No result generated.';
|
||||
})
|
||||
.then((resp) => {
|
||||
const result =
|
||||
resp?.choices?.[0]?.message?.content ||
|
||||
'No result generated.';
|
||||
tmp_summary = result;
|
||||
show_modal = true;
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('AE_AITools: AI Error:', err);
|
||||
// Even on error, show the modal with the error message so the UI can be inspected
|
||||
tmp_summary = `### AI Error\n\nFailed to connect to the AI service.\n\n**Error:** ${err.message}\n\nCheck your Settings tab for Base URL and Token configuration.`;
|
||||
show_modal = true;
|
||||
ae_promises = Promise.resolve();
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('AE_AITools: AI Error:', err);
|
||||
// Even on error, show the modal with the error message so the UI can be inspected
|
||||
tmp_summary = `### AI Error\n\nFailed to connect to the AI service.\n\n**Error:** ${err.message}\n\nCheck your Settings tab for Base URL and Token configuration.`;
|
||||
show_modal = true;
|
||||
ae_promises = Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
function handle_save() {
|
||||
summary = tmp_summary;
|
||||
if (onSave) onSave(tmp_summary);
|
||||
show_modal = false;
|
||||
}
|
||||
function handle_save() {
|
||||
summary = tmp_summary;
|
||||
if (onSave) onSave(tmp_summary);
|
||||
show_modal = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ae-ai-tools-wrapper inline-flex items-center gap-1">
|
||||
@@ -128,13 +143,12 @@
|
||||
type="button"
|
||||
onclick={generate_ai_result}
|
||||
class={buttonClass}
|
||||
title="Generate AI summary/analysis"
|
||||
>
|
||||
title="Generate AI summary/analysis">
|
||||
{#await ae_promises}
|
||||
<Loader class="inline-block mr-1 animate-spin" size="1.2em" />
|
||||
<Loader class="mr-1 inline-block animate-spin" size="1.2em" />
|
||||
<span class="text-sm">Processing...</span>
|
||||
{:then}
|
||||
<BotMessageSquare class="inline-block mr-1" size="1.2em" />
|
||||
<BotMessageSquare class="mr-1 inline-block" size="1.2em" />
|
||||
<span class="text-sm">Summarize</span>
|
||||
{:catch}
|
||||
<span class="text-sm text-red-500">Error</span>
|
||||
@@ -149,8 +163,7 @@
|
||||
show_modal = true;
|
||||
}}
|
||||
class="btn btn-sm variant-soft-surface shadow-md"
|
||||
title="AI Settings"
|
||||
>
|
||||
title="AI Settings">
|
||||
<Settings size="1.2em" />
|
||||
</button>
|
||||
|
||||
@@ -160,32 +173,37 @@
|
||||
title="Aether AI Assistant"
|
||||
bind:open={show_modal}
|
||||
size="lg"
|
||||
class="bg-white dark:bg-gray-800"
|
||||
>
|
||||
class="bg-white dark:bg-gray-800">
|
||||
<div class="space-y-4 p-2">
|
||||
<!-- Tab Navigation -->
|
||||
<div class="flex gap-1 border-b border-surface-500/20 pb-2">
|
||||
<button
|
||||
class="btn btn-sm {active_tab === 'result' ? 'variant-filled-primary' : 'variant-soft-surface'}"
|
||||
onclick={() => active_tab = 'result'}
|
||||
>
|
||||
<div class="border-surface-500/20 flex gap-1 border-b pb-2">
|
||||
<button
|
||||
class="btn btn-sm {active_tab === 'result'
|
||||
? 'variant-filled-primary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'result')}>
|
||||
<Bot size="1.1em" class="mr-1" /> Result
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm {active_tab === 'settings' ? 'variant-filled-secondary' : 'variant-soft-surface'}"
|
||||
onclick={() => active_tab = 'settings'}
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm {active_tab === 'settings'
|
||||
? 'variant-filled-secondary'
|
||||
: 'variant-soft-surface'}"
|
||||
onclick={() => (active_tab = 'settings')}>
|
||||
<Settings size="1.1em" class="mr-1" /> Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if active_tab === 'result'}
|
||||
<div class="space-y-4 animate-in fade-in duration-200">
|
||||
<div class="flex gap-2 justify-start">
|
||||
<button class="btn btn-sm variant-filled-success" onclick={handle_save}>
|
||||
<div class="animate-in fade-in space-y-4 duration-200">
|
||||
<div class="flex justify-start gap-2">
|
||||
<button
|
||||
class="btn btn-sm variant-filled-success"
|
||||
onclick={handle_save}>
|
||||
<Save size="1.1em" class="mr-1" /> Save Result
|
||||
</button>
|
||||
<button class="btn btn-sm variant-ghost-primary" onclick={generate_ai_result}>
|
||||
<button
|
||||
class="btn btn-sm variant-ghost-primary"
|
||||
onclick={generate_ai_result}>
|
||||
<RotateCcw size="1.1em" class="mr-1" /> Re-run
|
||||
</button>
|
||||
</div>
|
||||
@@ -195,57 +213,84 @@
|
||||
bind:new_content={tmp_summary}
|
||||
theme_mode={$ae_loc.theme_mode}
|
||||
placeholder="AI Result will appear here..."
|
||||
class_li="p-2 border rounded-lg h-96 shadow-inner bg-surface-500/5"
|
||||
/>
|
||||
class_li="p-2 border rounded-lg h-96 shadow-inner bg-surface-500/5" />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="space-y-6 animate-in slide-in-from-left-4 duration-200">
|
||||
<div
|
||||
class="animate-in slide-in-from-left-4 space-y-6 duration-200">
|
||||
<!-- Connection Settings -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-sm font-bold uppercase tracking-widest text-surface-500 flex items-center gap-2">
|
||||
<h3
|
||||
class="text-surface-500 flex items-center gap-2 text-sm font-bold tracking-widest uppercase">
|
||||
<Globe size="1.1em" /> API Connection
|
||||
</h3>
|
||||
|
||||
|
||||
{#if onSyncConfig}
|
||||
<button class="btn btn-sm variant-soft-primary" onclick={onSyncConfig}>
|
||||
<Copy size="1.1em" class="mr-1" /> Sync Global Defaults
|
||||
<button
|
||||
class="btn btn-sm variant-soft-primary"
|
||||
onclick={onSyncConfig}>
|
||||
<Copy size="1.1em" class="mr-1" /> Sync Global
|
||||
Defaults
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<label class="label">
|
||||
<span>Base URL</span>
|
||||
<input type="text" bind:value={baseUrl} class="input input-sm" />
|
||||
<input
|
||||
type="text"
|
||||
bind:value={baseUrl}
|
||||
class="input input-sm" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>Model</span>
|
||||
<input type="text" bind:value={model} class="input input-sm" />
|
||||
<input
|
||||
type="text"
|
||||
bind:value={model}
|
||||
class="input input-sm" />
|
||||
</label>
|
||||
</div>
|
||||
<label class="label">
|
||||
<span>API Token</span>
|
||||
<input type="password" bind:value={token} class="input input-sm font-mono" />
|
||||
<input
|
||||
type="password"
|
||||
bind:value={token}
|
||||
class="input input-sm font-mono" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Model Parameters -->
|
||||
<div class="space-y-4 pt-4 border-t border-surface-500/10">
|
||||
<h3 class="text-sm font-bold uppercase tracking-widest text-surface-500 flex items-center gap-2">
|
||||
<div
|
||||
class="border-surface-500/10 space-y-4 border-t pt-4">
|
||||
<h3
|
||||
class="text-surface-500 flex items-center gap-2 text-sm font-bold tracking-widest uppercase">
|
||||
<FilePenLine size="1.1em" /> Inference Parameters
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<label class="label">
|
||||
<span>Temperature ({temperature})</span>
|
||||
<input type="range" bind:value={temperature} min="0" max="1" step="0.1" class="range" />
|
||||
<input
|
||||
type="range"
|
||||
bind:value={temperature}
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.1"
|
||||
class="range" />
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>Max Tokens</span>
|
||||
<input type="number" bind:value={maxTokens} class="input input-sm" />
|
||||
<input
|
||||
type="number"
|
||||
bind:value={maxTokens}
|
||||
class="input input-sm" />
|
||||
</label>
|
||||
</div>
|
||||
<label class="label">
|
||||
<span>System Prompt</span>
|
||||
<textarea bind:value={systemPrompt} class="textarea h-24 text-xs font-mono"></textarea>
|
||||
<textarea
|
||||
bind:value={systemPrompt}
|
||||
class="textarea h-24 font-mono text-xs"
|
||||
></textarea>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -253,4 +298,4 @@
|
||||
</div>
|
||||
</Modal>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,58 +1,64 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* AE_ObjectFlags.svelte
|
||||
* GENERIC Aether Object Flags & Visibility Toggles
|
||||
* Manages: alert, private, public, personal, professional, template
|
||||
*/
|
||||
import {
|
||||
Siren, MessageSquareWarning, Fingerprint,
|
||||
Globe, BookHeart, BriefcaseBusiness, NotepadTextDashed,
|
||||
Settings
|
||||
} from '@lucide/svelte';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
/**
|
||||
* AE_ObjectFlags.svelte
|
||||
* GENERIC Aether Object Flags & Visibility Toggles
|
||||
* Manages: alert, private, public, personal, professional, template
|
||||
*/
|
||||
import {
|
||||
Siren,
|
||||
MessageSquareWarning,
|
||||
Fingerprint,
|
||||
Globe,
|
||||
BookHeart,
|
||||
BriefcaseBusiness,
|
||||
NotepadTextDashed,
|
||||
Settings
|
||||
} from '@lucide/svelte';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
|
||||
interface Props {
|
||||
// The object containing the flags (bindable)
|
||||
obj: any;
|
||||
interface Props {
|
||||
// The object containing the flags (bindable)
|
||||
obj: any;
|
||||
|
||||
// Visibility configuration (optional overrides)
|
||||
show_labels?: boolean;
|
||||
hide_alert?: boolean;
|
||||
hide_private?: boolean;
|
||||
hide_public?: boolean;
|
||||
hide_personal?: boolean;
|
||||
hide_professional?: boolean;
|
||||
hide_template?: boolean;
|
||||
// Visibility configuration (optional overrides)
|
||||
show_labels?: boolean;
|
||||
hide_alert?: boolean;
|
||||
hide_private?: boolean;
|
||||
hide_public?: boolean;
|
||||
hide_personal?: boolean;
|
||||
hide_professional?: boolean;
|
||||
hide_template?: boolean;
|
||||
|
||||
// Callbacks
|
||||
on_toggle?: (prop: string, newValue: boolean) => void;
|
||||
// Callbacks
|
||||
on_toggle?: (prop: string, newValue: boolean) => void;
|
||||
|
||||
// Styling
|
||||
container_class?: string;
|
||||
}
|
||||
// Styling
|
||||
container_class?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
obj = $bindable(),
|
||||
show_labels = true,
|
||||
hide_alert: hide_alert = false,
|
||||
hide_private: hide_private = false,
|
||||
hide_public: hide_public = false,
|
||||
hide_personal: hide_personal = false,
|
||||
hide_professional: hide_professional = false,
|
||||
hide_template: hide_template = false,
|
||||
on_toggle: onToggle,
|
||||
container_class = "flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10"
|
||||
}: Props = $props();
|
||||
let {
|
||||
obj = $bindable(),
|
||||
show_labels = true,
|
||||
hide_alert: hide_alert = false,
|
||||
hide_private: hide_private = false,
|
||||
hide_public: hide_public = false,
|
||||
hide_personal: hide_personal = false,
|
||||
hide_professional: hide_professional = false,
|
||||
hide_template: hide_template = false,
|
||||
on_toggle: onToggle,
|
||||
container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10'
|
||||
}: Props = $props();
|
||||
|
||||
function handle_toggle(prop: string) {
|
||||
obj[prop] = !obj[prop];
|
||||
if (onToggle) onToggle(prop, obj[prop]);
|
||||
}
|
||||
function handle_toggle(prop: string) {
|
||||
obj[prop] = !obj[prop];
|
||||
if (onToggle) onToggle(prop, obj[prop]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={container_class}>
|
||||
{#if show_labels}
|
||||
<span class="text-xs text-surface-500 flex items-center gap-1 uppercase font-bold tracking-wider mr-2">
|
||||
<span
|
||||
class="text-surface-500 mr-2 flex items-center gap-1 text-xs font-bold tracking-wider uppercase">
|
||||
<Settings size="1.1em" /> Flags:
|
||||
</span>
|
||||
{/if}
|
||||
@@ -63,9 +69,10 @@
|
||||
type="button"
|
||||
onclick={() => handle_toggle('alert')}
|
||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||
title="Toggle Alert Status"
|
||||
>
|
||||
<Siren size="1.2em" class={obj?.alert ? 'text-error-500' : 'opacity-40'} />
|
||||
title="Toggle Alert Status">
|
||||
<Siren
|
||||
size="1.2em"
|
||||
class={obj?.alert ? 'text-error-500' : 'opacity-40'} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -75,9 +82,10 @@
|
||||
type="button"
|
||||
onclick={() => handle_toggle('private')}
|
||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||
title="Toggle Private/Encrypted"
|
||||
>
|
||||
<Fingerprint size="1.2em" class={obj?.private ? 'text-success-500' : 'opacity-40'} />
|
||||
title="Toggle Private/Encrypted">
|
||||
<Fingerprint
|
||||
size="1.2em"
|
||||
class={obj?.private ? 'text-success-500' : 'opacity-40'} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -87,9 +95,10 @@
|
||||
type="button"
|
||||
onclick={() => handle_toggle('public')}
|
||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||
title="Toggle Public Visibility"
|
||||
>
|
||||
<Globe size="1.2em" class={obj?.public ? 'text-success-500' : 'opacity-40'} />
|
||||
title="Toggle Public Visibility">
|
||||
<Globe
|
||||
size="1.2em"
|
||||
class={obj?.public ? 'text-success-500' : 'opacity-40'} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -99,9 +108,10 @@
|
||||
type="button"
|
||||
onclick={() => handle_toggle('personal')}
|
||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||
title="Toggle Personal Scope"
|
||||
>
|
||||
<BookHeart size="1.2em" class={obj?.personal ? 'text-success-500' : 'opacity-40'} />
|
||||
title="Toggle Personal Scope">
|
||||
<BookHeart
|
||||
size="1.2em"
|
||||
class={obj?.personal ? 'text-success-500' : 'opacity-40'} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -111,9 +121,10 @@
|
||||
type="button"
|
||||
onclick={() => handle_toggle('professional')}
|
||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||
title="Toggle Professional Scope"
|
||||
>
|
||||
<BriefcaseBusiness size="1.2em" class={obj?.professional ? 'text-success-500' : 'opacity-40'} />
|
||||
title="Toggle Professional Scope">
|
||||
<BriefcaseBusiness
|
||||
size="1.2em"
|
||||
class={obj?.professional ? 'text-success-500' : 'opacity-40'} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -123,9 +134,10 @@
|
||||
type="button"
|
||||
onclick={() => handle_toggle('template')}
|
||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||
title="Toggle Template Mode"
|
||||
>
|
||||
<NotepadTextDashed size="1.2em" class={obj?.template ? 'text-success-500' : 'opacity-40'} />
|
||||
title="Toggle Template Mode">
|
||||
<NotepadTextDashed
|
||||
size="1.2em"
|
||||
class={obj?.template ? 'text-success-500' : 'opacity-40'} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,95 +1,96 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* AE_Record_Controls.svelte
|
||||
* GENERIC Aether Record Management Controls
|
||||
* Manages: priority, hide, enable, alert, delete/disable
|
||||
*
|
||||
* Emits events — NO API calls. Parent is responsible for:
|
||||
* 1. Calling the API (update_ae_obj, delete_ae_obj_id__*)
|
||||
* 2. Refreshing the object from cache/API
|
||||
* 3. Navigating away on delete
|
||||
*
|
||||
* Usage:
|
||||
* <AE_Record_Controls
|
||||
* obj={$lq__event_session_obj}
|
||||
* obj_label="session"
|
||||
* allow_delete={$ae_loc.manager_access}
|
||||
* allow_disable={$ae_loc.administrator_access}
|
||||
* on_toggle={(field, val) => { ... }}
|
||||
* on_delete={(method) => { ... }}
|
||||
* />
|
||||
*/
|
||||
import {
|
||||
Star,
|
||||
Eye,
|
||||
EyeOff,
|
||||
ToggleLeft,
|
||||
ToggleRight,
|
||||
Bell,
|
||||
BellOff,
|
||||
Trash2,
|
||||
CircleMinus,
|
||||
Settings
|
||||
} from '@lucide/svelte';
|
||||
/**
|
||||
* AE_Record_Controls.svelte
|
||||
* GENERIC Aether Record Management Controls
|
||||
* Manages: priority, hide, enable, alert, delete/disable
|
||||
*
|
||||
* Emits events — NO API calls. Parent is responsible for:
|
||||
* 1. Calling the API (update_ae_obj, delete_ae_obj_id__*)
|
||||
* 2. Refreshing the object from cache/API
|
||||
* 3. Navigating away on delete
|
||||
*
|
||||
* Usage:
|
||||
* <AE_Record_Controls
|
||||
* obj={$lq__event_session_obj}
|
||||
* obj_label="session"
|
||||
* allow_delete={$ae_loc.manager_access}
|
||||
* allow_disable={$ae_loc.administrator_access}
|
||||
* on_toggle={(field, val) => { ... }}
|
||||
* on_delete={(method) => { ... }}
|
||||
* />
|
||||
*/
|
||||
import {
|
||||
Star,
|
||||
Eye,
|
||||
EyeOff,
|
||||
ToggleLeft,
|
||||
ToggleRight,
|
||||
Bell,
|
||||
BellOff,
|
||||
Trash2,
|
||||
CircleMinus,
|
||||
Settings
|
||||
} from '@lucide/svelte';
|
||||
|
||||
interface Props {
|
||||
// The object whose flags are being displayed (read-only — parent owns state)
|
||||
obj: any;
|
||||
interface Props {
|
||||
// The object whose flags are being displayed (read-only — parent owns state)
|
||||
obj: any;
|
||||
|
||||
// Human-readable label for confirm dialogs ("session", "presenter", "location", etc.)
|
||||
obj_label?: string;
|
||||
// Human-readable label for confirm dialogs ("session", "presenter", "location", etc.)
|
||||
obj_label?: string;
|
||||
|
||||
// Visibility — hide any control that doesn't apply for this object type
|
||||
show_alert?: boolean;
|
||||
show_priority?: boolean;
|
||||
show_enable?: boolean;
|
||||
show_hide?: boolean;
|
||||
show_labels?: boolean;
|
||||
// Visibility — hide any control that doesn't apply for this object type
|
||||
show_alert?: boolean;
|
||||
show_priority?: boolean;
|
||||
show_enable?: boolean;
|
||||
show_hide?: boolean;
|
||||
show_labels?: boolean;
|
||||
|
||||
// Permission gates — parent passes booleans derived from $ae_loc
|
||||
allow_delete?: boolean; // Hard permanent delete (manager+)
|
||||
allow_disable?: boolean; // Soft disable/remove (administrator+)
|
||||
// Permission gates — parent passes booleans derived from $ae_loc
|
||||
allow_delete?: boolean; // Hard permanent delete (manager+)
|
||||
allow_disable?: boolean; // Soft disable/remove (administrator+)
|
||||
|
||||
// Callbacks — parent handles API + refresh + navigation
|
||||
on_toggle?: (field: string, new_val: boolean) => void;
|
||||
on_delete?: (method: 'delete' | 'disable') => void;
|
||||
// Callbacks — parent handles API + refresh + navigation
|
||||
on_toggle?: (field: string, new_val: boolean) => void;
|
||||
on_delete?: (method: 'delete' | 'disable') => void;
|
||||
|
||||
// Styling
|
||||
container_class?: string;
|
||||
}
|
||||
// Styling
|
||||
container_class?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
obj,
|
||||
obj_label = 'record',
|
||||
show_alert = true,
|
||||
show_priority = true,
|
||||
show_enable = true,
|
||||
show_hide = true,
|
||||
show_labels = true,
|
||||
allow_delete = false,
|
||||
allow_disable = false,
|
||||
on_toggle,
|
||||
on_delete,
|
||||
container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10'
|
||||
}: Props = $props();
|
||||
let {
|
||||
obj,
|
||||
obj_label = 'record',
|
||||
show_alert = true,
|
||||
show_priority = true,
|
||||
show_enable = true,
|
||||
show_hide = true,
|
||||
show_labels = true,
|
||||
allow_delete = false,
|
||||
allow_disable = false,
|
||||
on_toggle,
|
||||
on_delete,
|
||||
container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10'
|
||||
}: Props = $props();
|
||||
|
||||
function toggle(field: string) {
|
||||
if (on_toggle) on_toggle(field, !obj?.[field]);
|
||||
}
|
||||
function toggle(field: string) {
|
||||
if (on_toggle) on_toggle(field, !obj?.[field]);
|
||||
}
|
||||
|
||||
function handle_delete(method: 'delete' | 'disable') {
|
||||
const msg =
|
||||
method === 'delete'
|
||||
? `Permanently delete this ${obj_label}? This cannot be undone.`
|
||||
: `Remove (disable) this ${obj_label}?`;
|
||||
if (!confirm(msg)) return;
|
||||
if (on_delete) on_delete(method);
|
||||
}
|
||||
function handle_delete(method: 'delete' | 'disable') {
|
||||
const msg =
|
||||
method === 'delete'
|
||||
? `Permanently delete this ${obj_label}? This cannot be undone.`
|
||||
: `Remove (disable) this ${obj_label}?`;
|
||||
if (!confirm(msg)) return;
|
||||
if (on_delete) on_delete(method);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={container_class}>
|
||||
{#if show_labels}
|
||||
<span class="text-xs text-surface-500 flex items-center gap-1 uppercase font-bold tracking-wider mr-2">
|
||||
<span
|
||||
class="text-surface-500 mr-2 flex items-center gap-1 text-xs font-bold tracking-wider uppercase">
|
||||
<Settings size="1.1em" /> Controls:
|
||||
</span>
|
||||
{/if}
|
||||
@@ -103,12 +104,10 @@
|
||||
class:preset-filled-warning-500={obj?.priority}
|
||||
class:preset-tonal-secondary={!obj?.priority}
|
||||
class:hover:preset-filled-warning-500={!obj?.priority}
|
||||
title={obj?.priority ? 'Remove priority flag' : 'Mark as priority'}
|
||||
>
|
||||
title={obj?.priority ? 'Remove priority flag' : 'Mark as priority'}>
|
||||
<Star
|
||||
size="1.2em"
|
||||
class={obj?.priority ? 'fill-current' : 'opacity-50'}
|
||||
/>
|
||||
class={obj?.priority ? 'fill-current' : 'opacity-50'} />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -121,8 +120,7 @@
|
||||
class:preset-filled-warning-500={obj?.hide}
|
||||
class:preset-tonal-secondary={!obj?.hide}
|
||||
class:hover:preset-filled-warning-500={!obj?.hide}
|
||||
title={obj?.hide ? 'Unhide this record' : 'Hide this record'}
|
||||
>
|
||||
title={obj?.hide ? 'Unhide this record' : 'Hide this record'}>
|
||||
{#if obj?.hide}
|
||||
<EyeOff size="1.2em" class="text-warning-500" />
|
||||
{:else}
|
||||
@@ -140,8 +138,7 @@
|
||||
class:preset-filled-success-500={obj?.enable}
|
||||
class:preset-filled-error-500={!obj?.enable}
|
||||
class:hover:preset-filled-success-500={!obj?.enable}
|
||||
title={obj?.enable ? 'Disable this record' : 'Enable this record'}
|
||||
>
|
||||
title={obj?.enable ? 'Disable this record' : 'Enable this record'}>
|
||||
{#if obj?.enable}
|
||||
<ToggleRight size="1.2em" class="text-success-300" />
|
||||
{:else}
|
||||
@@ -159,8 +156,7 @@
|
||||
class:preset-filled-error-500={obj?.alert}
|
||||
class:preset-tonal-secondary={!obj?.alert}
|
||||
class:hover:preset-filled-error-500={!obj?.alert}
|
||||
title={obj?.alert ? 'Remove alert status' : 'Mark as alert'}
|
||||
>
|
||||
title={obj?.alert ? 'Remove alert status' : 'Mark as alert'}>
|
||||
{#if obj?.alert}
|
||||
<Bell size="1.2em" class="text-error-300" />
|
||||
{:else}
|
||||
@@ -175,8 +171,7 @@
|
||||
type="button"
|
||||
onclick={() => handle_delete('delete')}
|
||||
class="btn-icon btn-icon-sm preset-filled-error-500 hover:preset-filled-error-600 transition"
|
||||
title="Permanently delete this {obj_label}"
|
||||
>
|
||||
title="Permanently delete this {obj_label}">
|
||||
<Trash2 size="1.2em" />
|
||||
</button>
|
||||
{:else if allow_disable}
|
||||
@@ -184,8 +179,7 @@
|
||||
type="button"
|
||||
onclick={() => handle_delete('disable')}
|
||||
class="btn-icon btn-icon-sm preset-filled-warning-500 hover:preset-filled-warning-600 transition"
|
||||
title="Disable / soft-remove this {obj_label}"
|
||||
>
|
||||
title="Disable / soft-remove this {obj_label}">
|
||||
<CircleMinus size="1.2em" />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -46,7 +46,9 @@ export async function load_ae_obj_id__event({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Event | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event() *** event_id=${event_id} (SWR Optimization)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event() *** event_id=${event_id} (SWR Optimization)`
|
||||
);
|
||||
}
|
||||
|
||||
// Hierarchy Enforcement: Pulling presentations/presenters requires pulling sessions first
|
||||
@@ -57,20 +59,43 @@ export async function load_ae_obj_id__event({
|
||||
try {
|
||||
const cached_event = await db_events.event.get(event_id);
|
||||
if (cached_event) {
|
||||
if (log_lvl) console.log('EVENT LOAD: Cache hit. Returning stale data immediately.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'EVENT LOAD: Cache hit. Returning stale data immediately.'
|
||||
);
|
||||
|
||||
// Trigger background refresh
|
||||
_refresh_event_background({
|
||||
api_cfg, event_id, view, try_cache,
|
||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
||||
enabled, hidden,
|
||||
api_cfg,
|
||||
event_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_device_li,
|
||||
inc_file_li,
|
||||
inc_location_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_template_li,
|
||||
enabled,
|
||||
hidden,
|
||||
log_lvl: 0
|
||||
});
|
||||
|
||||
// Still handle nested loads for the cached version to ensure UI richness
|
||||
return await _handle_nested_loads(cached_event, {
|
||||
api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
||||
enabled, hidden, try_cache, log_lvl
|
||||
api_cfg,
|
||||
inc_device_li,
|
||||
inc_file_li,
|
||||
inc_location_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_template_li,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -80,9 +105,19 @@ export async function load_ae_obj_id__event({
|
||||
|
||||
// 2. SLOW PATH: Wait for API if cache is empty or try_cache is false
|
||||
return await _refresh_event_background({
|
||||
api_cfg, event_id, view, try_cache,
|
||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
||||
enabled, hidden,
|
||||
api_cfg,
|
||||
event_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_device_li,
|
||||
inc_file_li,
|
||||
inc_location_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_template_li,
|
||||
enabled,
|
||||
hidden,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
@@ -91,9 +126,19 @@ export async function load_ae_obj_id__event({
|
||||
* Internal helper to perform the actual API fetch and cache update for events
|
||||
*/
|
||||
async function _refresh_event_background({
|
||||
api_cfg, event_id, view, try_cache,
|
||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
||||
enabled, hidden,
|
||||
api_cfg,
|
||||
event_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_device_li,
|
||||
inc_file_li,
|
||||
inc_location_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_template_li,
|
||||
enabled,
|
||||
hidden,
|
||||
log_lvl
|
||||
}: any) {
|
||||
// Check if offline
|
||||
@@ -129,8 +174,18 @@ async function _refresh_event_background({
|
||||
}
|
||||
|
||||
return await _handle_nested_loads(processed_obj, {
|
||||
api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
||||
enabled, hidden, try_cache: false, log_lvl
|
||||
api_cfg,
|
||||
inc_device_li,
|
||||
inc_file_li,
|
||||
inc_location_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_template_li,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache: false,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -142,8 +197,27 @@ async function _refresh_event_background({
|
||||
/**
|
||||
* Shared logic for loading nested child collections
|
||||
*/
|
||||
async function _handle_nested_loads(event_obj: any, { api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li, enabled, hidden, try_cache, log_lvl }: any) {
|
||||
if (log_lvl) console.log(`Loading nested collections for event: ${event_obj.event_id} (Devices: ${inc_device_li}, Files: ${inc_file_li}, Locations: ${inc_location_li}, Sessions: ${inc_session_li}, Presentations: ${inc_presentation_li}, Presenters: ${inc_presenter_li}, Templates: ${inc_template_li})`);
|
||||
async function _handle_nested_loads(
|
||||
event_obj: any,
|
||||
{
|
||||
api_cfg,
|
||||
inc_device_li,
|
||||
inc_file_li,
|
||||
inc_location_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_template_li,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any
|
||||
) {
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`Loading nested collections for event: ${event_obj.event_id} (Devices: ${inc_device_li}, Files: ${inc_file_li}, Locations: ${inc_location_li}, Sessions: ${inc_session_li}, Presentations: ${inc_presentation_li}, Presenters: ${inc_presenter_li}, Templates: ${inc_template_li})`
|
||||
);
|
||||
// String-Only ID Vision: the '_id' field IS the string ID
|
||||
const current_event_id = event_obj.id || event_obj.event_id;
|
||||
|
||||
@@ -151,56 +225,66 @@ async function _handle_nested_loads(event_obj: any, { api_cfg, inc_device_li, in
|
||||
const tasks = [];
|
||||
|
||||
if (inc_device_li) {
|
||||
tasks.push(load_ae_obj_li__event_device({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then(res => event_obj.event_device_obj_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_device({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_device_obj_li = res))
|
||||
);
|
||||
}
|
||||
if (inc_file_li) {
|
||||
tasks.push(load_ae_obj_li__event_file({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
enabled: 'all',
|
||||
limit: 100,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then(res => event_obj.event_file_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_file({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
enabled: 'all',
|
||||
limit: 100,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_file_li = res))
|
||||
);
|
||||
}
|
||||
if (inc_location_li) {
|
||||
tasks.push(load_ae_obj_li__event_location({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then(res => event_obj.event_location_obj_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_location({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_location_obj_li = res))
|
||||
);
|
||||
}
|
||||
if (inc_session_li) {
|
||||
tasks.push(load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then(res => event_obj.event_session_obj_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_session_obj_li = res))
|
||||
);
|
||||
}
|
||||
if (inc_template_li) {
|
||||
tasks.push(load_ae_obj_li__event_badge_template({
|
||||
api_cfg,
|
||||
event_id: current_event_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then(res => event_obj.event_badge_template_obj_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_badge_template({
|
||||
api_cfg,
|
||||
event_id: current_event_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_badge_template_obj_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (tasks.length > 0) await Promise.all(tasks);
|
||||
@@ -238,20 +322,25 @@ export async function load_ae_obj_li__event({
|
||||
inc_presenter_li?: boolean;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[];
|
||||
order_by_li?:
|
||||
| Record<string, 'ASC' | 'DESC'>
|
||||
| Record<string, 'ASC' | 'DESC'>[];
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Event[]> {
|
||||
|
||||
// Hierarchy Enforcement: Pulling presentations/presenters requires pulling sessions first
|
||||
if (inc_presenter_li || inc_presentation_li) inc_session_li = true;
|
||||
|
||||
// Check if offline
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||
if (log_lvl) console.log('Browser is offline. Skipping API and attempting cache load.');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'Browser is offline. Skipping API and attempting cache load.'
|
||||
);
|
||||
ae_promises.load__event_obj_li = await db_events.event
|
||||
.where('account_id').equals(for_obj_id)
|
||||
.where('account_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
return ae_promises.load__event_obj_li || [];
|
||||
}
|
||||
@@ -264,7 +353,11 @@ export async function load_ae_obj_li__event({
|
||||
};
|
||||
|
||||
if (for_obj_id) {
|
||||
search_query.and.push({ field: `${for_obj_type}_id`, op: 'eq', value: for_obj_id });
|
||||
search_query.and.push({
|
||||
field: `${for_obj_type}_id`,
|
||||
op: 'eq',
|
||||
value: for_obj_id
|
||||
});
|
||||
}
|
||||
|
||||
promise = api.search_ae_obj({
|
||||
@@ -319,9 +412,11 @@ export async function load_ae_obj_li__event({
|
||||
} else {
|
||||
console.log('No results returned from API.');
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
||||
if (log_lvl)
|
||||
console.log('Attempting to load from local cache...');
|
||||
ae_promises.load__event_obj_li = await db_events.event
|
||||
.where('account_id').equals(for_obj_id)
|
||||
.where('account_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
} else {
|
||||
ae_promises.load__event_obj_li = [];
|
||||
@@ -330,9 +425,13 @@ export async function load_ae_obj_li__event({
|
||||
} catch (error: any) {
|
||||
console.log('API request failed.', error);
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'Attempting to load from local cache after error...'
|
||||
);
|
||||
ae_promises.load__event_obj_li = await db_events.event
|
||||
.where('account_id').equals(for_obj_id)
|
||||
.where('account_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
} else {
|
||||
ae_promises.load__event_obj_li = [];
|
||||
@@ -340,18 +439,20 @@ export async function load_ae_obj_li__event({
|
||||
}
|
||||
|
||||
if (inc_session_li && ae_promises.load__event_obj_li) {
|
||||
const session_tasks = ae_promises.load__event_obj_li.map((event_obj: any) => {
|
||||
const current_event_id = event_obj.id || event_obj.event_id;
|
||||
return load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_session_obj_li = res));
|
||||
});
|
||||
const session_tasks = ae_promises.load__event_obj_li.map(
|
||||
(event_obj: any) => {
|
||||
const current_event_id = event_obj.id || event_obj.event_id;
|
||||
return load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (event_obj.event_session_obj_li = res));
|
||||
}
|
||||
);
|
||||
await Promise.all(session_tasks);
|
||||
}
|
||||
|
||||
@@ -543,13 +644,21 @@ export async function search__event({
|
||||
};
|
||||
const params: key_val = {};
|
||||
|
||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${qry_str.trim()}%` });
|
||||
params['lk_qry'] = { 'default_qry_str': qry_str.trim() };
|
||||
search_query.and.push({
|
||||
field: 'default_qry_str',
|
||||
op: 'like',
|
||||
value: `%${qry_str.trim()}%`
|
||||
});
|
||||
params['lk_qry'] = { default_qry_str: qry_str.trim() };
|
||||
|
||||
if (for_obj_id) {
|
||||
// V3 Standard: Use random string ID for body filters.
|
||||
// The API resolves this to the integer column automatically.
|
||||
search_query.and.push({ field: `${for_obj_type}_id_random`, op: 'eq', value: for_obj_id });
|
||||
search_query.and.push({
|
||||
field: `${for_obj_type}_id_random`,
|
||||
op: 'eq',
|
||||
value: for_obj_id
|
||||
});
|
||||
}
|
||||
|
||||
// NOTE: We do NOT push 'physical' and 'virtual' to the server-side query here.
|
||||
@@ -593,7 +702,11 @@ export async function search__event({
|
||||
let valid_result_li: ae_Event[] = [];
|
||||
if (Array.isArray(result_li)) {
|
||||
valid_result_li = result_li;
|
||||
} else if (result_li && typeof result_li === 'object' && Array.isArray((result_li as any).data)) {
|
||||
} else if (
|
||||
result_li &&
|
||||
typeof result_li === 'object' &&
|
||||
Array.isArray((result_li as any).data)
|
||||
) {
|
||||
valid_result_li = (result_li as any).data;
|
||||
} else {
|
||||
return [];
|
||||
@@ -641,13 +754,12 @@ export async function search__event({
|
||||
|
||||
// Handle person ID filter
|
||||
if (qry_person_id) {
|
||||
const match = (
|
||||
const match =
|
||||
ev.external_person_id === qry_person_id ||
|
||||
ev.poc_person_id === qry_person_id ||
|
||||
ev.poc_person_id_random === qry_person_id ||
|
||||
ev.poc_event_person_id === qry_person_id ||
|
||||
ev.poc_event_person_id_random === qry_person_id
|
||||
);
|
||||
ev.poc_event_person_id_random === qry_person_id;
|
||||
if (!match) return false;
|
||||
}
|
||||
|
||||
@@ -655,7 +767,9 @@ export async function search__event({
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Filter results (Hybrid): Input=${processed_obj_li.length}, Output=${filtered_obj_li.length}`);
|
||||
console.log(
|
||||
`Filter results (Hybrid): Input=${processed_obj_li.length}, Output=${filtered_obj_li.length}`
|
||||
);
|
||||
}
|
||||
|
||||
return filtered_obj_li.slice(0, limit);
|
||||
@@ -663,7 +777,6 @@ export async function search__event({
|
||||
|
||||
export const qry_ae_obj_li__event = search__event;
|
||||
|
||||
|
||||
// Updated 2026-03-10
|
||||
export const properties_to_save = [
|
||||
'id',
|
||||
@@ -780,14 +893,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -849,7 +969,8 @@ export function sync_config__event_pres_mgmt({
|
||||
pres_mgmt_cfg_remote?.label__session_poc_name_short ?? 'POC';
|
||||
pres_mgmt_cfg_local.label__session_poc_name =
|
||||
pres_mgmt_cfg_remote?.label__session_poc_name ?? 'Point of Contact';
|
||||
pres_mgmt_cfg_local.hide__session_poc = pres_mgmt_cfg_remote?.hide__session_poc ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_poc =
|
||||
pres_mgmt_cfg_remote?.hide__session_poc ?? false;
|
||||
pres_mgmt_cfg_local.require__presenter_agree =
|
||||
pres_mgmt_cfg_remote?.require__presenter_agree ?? false;
|
||||
pres_mgmt_cfg_local.require__session_agree =
|
||||
@@ -874,27 +995,31 @@ export function sync_config__event_pres_mgmt({
|
||||
pres_mgmt_cfg_local.hide__presentation_datetime =
|
||||
pres_mgmt_cfg_remote?.hide__presentation_datetime ?? false;
|
||||
pres_mgmt_cfg_local.show_content__presentation_description =
|
||||
pres_mgmt_cfg_remote?.show_content__presentation_description ?? false;
|
||||
pres_mgmt_cfg_remote?.show_content__presentation_description ??
|
||||
false;
|
||||
pres_mgmt_cfg_local.hide__presenter_code =
|
||||
pres_mgmt_cfg_remote?.hide__presenter_code ?? false;
|
||||
pres_mgmt_cfg_local.hide__presenter_biography =
|
||||
pres_mgmt_cfg_remote?.hide__presenter_biography ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_code = pres_mgmt_cfg_remote?.hide__session_code ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_code =
|
||||
pres_mgmt_cfg_remote?.hide__session_code ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_description =
|
||||
pres_mgmt_cfg_remote?.hide__session_description ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_location =
|
||||
pres_mgmt_cfg_remote?.hide__session_location ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_msg = pres_mgmt_cfg_remote?.hide__session_msg ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_msg =
|
||||
pres_mgmt_cfg_remote?.hide__session_msg ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_poc_profile =
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_profile ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_poc_biography =
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_biography ?? false;
|
||||
pres_mgmt_cfg_local.hide__session_poc_profile_pic =
|
||||
pres_mgmt_cfg_remote?.hide__session_poc_profile_pic ?? false;
|
||||
pres_mgmt_cfg_local.hide_launcher_link = pres_mgmt_cfg_remote?.hide_launcher_link ?? false;
|
||||
pres_mgmt_cfg_local.hide_launcher_link =
|
||||
pres_mgmt_cfg_remote?.hide_launcher_link ?? false;
|
||||
pres_mgmt_cfg_local.hide_launcher_link_legacy =
|
||||
pres_mgmt_cfg_remote?.hide_launcher_link_legacy ?? false;
|
||||
}
|
||||
|
||||
return pres_mgmt_cfg_local;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,15 @@ vi.mock('$lib/api/api', () => ({
|
||||
search_ae_obj: vi.fn()
|
||||
}
|
||||
}));
|
||||
vi.mock('$lib/ae_core/core__idb_dexie', () => ({ db_save_ae_obj_li__ae_obj: vi.fn() }));
|
||||
vi.mock('$lib/ae_events/db_events', () => ({ db_events: { badge: { get: vi.fn(), delete: vi.fn() } } }));
|
||||
vi.mock('$lib/ae_events/ae_events__event_badge_template', () => ({ load_ae_obj_id__event_badge_template: vi.fn() }));
|
||||
vi.mock('$lib/ae_core/core__idb_dexie', () => ({
|
||||
db_save_ae_obj_li__ae_obj: vi.fn()
|
||||
}));
|
||||
vi.mock('$lib/ae_events/db_events', () => ({
|
||||
db_events: { badge: { get: vi.fn(), delete: vi.fn() } }
|
||||
}));
|
||||
vi.mock('$lib/ae_events/ae_events__event_badge_template', () => ({
|
||||
load_ae_obj_id__event_badge_template: vi.fn()
|
||||
}));
|
||||
|
||||
import { create_ae_obj__event_badge } from './ae_events__event_badge';
|
||||
|
||||
@@ -25,9 +31,17 @@ describe('create_ae_obj__event_badge', () => {
|
||||
|
||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||
const event_id = 'evt1';
|
||||
const data_kv = { full_name_override: 'Test User', email: 't@example.com' };
|
||||
const data_kv = {
|
||||
full_name_override: 'Test User',
|
||||
email: 't@example.com'
|
||||
};
|
||||
|
||||
const result = await create_ae_obj__event_badge({ api_cfg, event_id, data_kv, try_cache: false });
|
||||
const result = await create_ae_obj__event_badge({
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache: false
|
||||
});
|
||||
|
||||
expect(mockCreateNested).toHaveBeenCalled();
|
||||
expect(mockCreateNested).toHaveBeenCalledWith({
|
||||
@@ -51,9 +65,16 @@ describe('update_ae_obj__event_badge', () => {
|
||||
const fakeResult = { event_badge_id: 'eb999', full_name: 'Updated' };
|
||||
mockUpdate.mockResolvedValue(fakeResult);
|
||||
|
||||
const { update_ae_obj__event_badge } = await import('./ae_events__event_badge');
|
||||
const { update_ae_obj__event_badge } =
|
||||
await import('./ae_events__event_badge');
|
||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||
const res = await update_ae_obj__event_badge({ api_cfg, event_id: 'evt1', event_badge_id: 'eb999', data_kv: { full_name_override: 'Updated' }, try_cache: false });
|
||||
const res = await update_ae_obj__event_badge({
|
||||
api_cfg,
|
||||
event_id: 'evt1',
|
||||
event_badge_id: 'eb999',
|
||||
data_kv: { full_name_override: 'Updated' },
|
||||
try_cache: false
|
||||
});
|
||||
|
||||
expect(mockUpdate).toHaveBeenCalled();
|
||||
expect(mockUpdate).toHaveBeenCalledWith({
|
||||
@@ -79,10 +100,16 @@ describe('delete_ae_obj_id__event_badge', () => {
|
||||
const db = await import('$lib/ae_events/db_events');
|
||||
const dbDelete = db.db_events.badge.delete as any;
|
||||
|
||||
const { delete_ae_obj_id__event_badge } = await import('./ae_events__event_badge');
|
||||
const { delete_ae_obj_id__event_badge } =
|
||||
await import('./ae_events__event_badge');
|
||||
|
||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||
const res = await delete_ae_obj_id__event_badge({ api_cfg, event_id: 'evt1', event_badge_id: 'ebDel', try_cache: true });
|
||||
const res = await delete_ae_obj_id__event_badge({
|
||||
api_cfg,
|
||||
event_id: 'evt1',
|
||||
event_badge_id: 'ebDel',
|
||||
try_cache: true
|
||||
});
|
||||
|
||||
expect(mockDelete).toHaveBeenCalled();
|
||||
expect(dbDelete).toHaveBeenCalledWith('ebDel');
|
||||
@@ -97,9 +124,15 @@ describe('search__event_badge', () => {
|
||||
const fakeList = [{ event_badge_id: 'eb1' }, { event_badge_id: 'eb2' }];
|
||||
mockSearch.mockResolvedValue({ data: fakeList });
|
||||
|
||||
const { search__event_badge } = await import('./ae_events__event_badge');
|
||||
const { search__event_badge } =
|
||||
await import('./ae_events__event_badge');
|
||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||
const res = await search__event_badge({ api_cfg, event_id: 'evt1', fulltext_search_qry_str: 'Test', try_cache: false });
|
||||
const res = await search__event_badge({
|
||||
api_cfg,
|
||||
event_id: 'evt1',
|
||||
fulltext_search_qry_str: 'Test',
|
||||
try_cache: false
|
||||
});
|
||||
|
||||
expect(mockSearch).toHaveBeenCalled();
|
||||
expect(Array.isArray(res)).toBe(true);
|
||||
|
||||
@@ -35,29 +35,36 @@ export async function load_ae_obj_id__event_badge({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
ae_promises.load__event_badge_obj = await api
|
||||
.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge',
|
||||
obj_id: event_badge_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__event_badge_obj = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge',
|
||||
obj_id: event_badge_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (ae_promises.load__event_badge_obj) {
|
||||
if (try_cache) {
|
||||
// In theory we should be able to use the event_id found in the Badge load object. 2026-02-04
|
||||
// This keeps coming up as undefined: ae_promises.load__event_badge_obj.event_id
|
||||
if (log_lvl) console.log(`Saving to local cache... Event ID: ${event_id} or ${ae_promises.load__event_badge_obj.event_id}`);
|
||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
||||
obj_li: [ae_promises.load__event_badge_obj],
|
||||
event_id: event_id || ae_promises.load__event_badge_obj.event_id,
|
||||
log_lvl
|
||||
});
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`Saving to local cache... Event ID: ${event_id} or ${ae_promises.load__event_badge_obj.event_id}`
|
||||
);
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__event_badge_props({
|
||||
obj_li: [ae_promises.load__event_badge_obj],
|
||||
event_id:
|
||||
event_id ||
|
||||
ae_promises.load__event_badge_obj.event_id,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge',
|
||||
@@ -71,15 +78,21 @@ export async function load_ae_obj_id__event_badge({
|
||||
} else {
|
||||
console.log('No results returned from API.');
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
||||
ae_promises.load__event_badge_obj = await db_events.badge.get(event_badge_id);
|
||||
if (log_lvl)
|
||||
console.log('Attempting to load from local cache...');
|
||||
ae_promises.load__event_badge_obj =
|
||||
await db_events.badge.get(event_badge_id);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('API request failed.', error);
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
||||
ae_promises.load__event_badge_obj = await db_events.badge.get(event_badge_id);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'Attempting to load from local cache after error...'
|
||||
);
|
||||
ae_promises.load__event_badge_obj =
|
||||
await db_events.badge.get(event_badge_id);
|
||||
} else {
|
||||
ae_promises.load__event_badge_obj = null;
|
||||
}
|
||||
@@ -87,14 +100,16 @@ export async function load_ae_obj_id__event_badge({
|
||||
|
||||
if (inc_template && ae_promises.load__event_badge_obj) {
|
||||
// Load the templates for the event badge
|
||||
const current_template_id = ae_promises.load__event_badge_obj.event_badge_template_id;
|
||||
const current_template_id =
|
||||
ae_promises.load__event_badge_obj.event_badge_template_id;
|
||||
if (current_template_id) {
|
||||
ae_promises.load__event_badge_obj.event_badge_template = await load_ae_obj_id__event_badge_template({
|
||||
api_cfg: api_cfg,
|
||||
event_badge_template_id: current_template_id,
|
||||
try_cache: try_cache,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
ae_promises.load__event_badge_obj.event_badge_template =
|
||||
await load_ae_obj_id__event_badge_template({
|
||||
api_cfg: api_cfg,
|
||||
event_badge_template_id: current_template_id,
|
||||
try_cache: try_cache,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +126,12 @@ export async function load_ae_obj_li__event_badge({
|
||||
view = 'default',
|
||||
limit = 99,
|
||||
offset = 0,
|
||||
order_by_li = { priority: 'DESC', sort: 'DESC', updated_on: 'DESC', created_on: 'DESC' },
|
||||
order_by_li = {
|
||||
priority: 'DESC',
|
||||
sort: 'DESC',
|
||||
updated_on: 'DESC',
|
||||
created_on: 'DESC'
|
||||
},
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
@@ -130,32 +150,34 @@ export async function load_ae_obj_li__event_badge({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__event_badge() *** event_id=${event_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__event_badge() *** event_id=${event_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
ae_promises.load__event_badge_obj_li = await api
|
||||
.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge',
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
view: view,
|
||||
order_by_li: order_by_li,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
ae_promises.load__event_badge_obj_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge',
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
enabled: enabled,
|
||||
hidden: hidden,
|
||||
view: view,
|
||||
order_by_li: order_by_li,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
if (ae_promises.load__event_badge_obj_li) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
||||
obj_li: ae_promises.load__event_badge_obj_li,
|
||||
event_id,
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__event_badge_props({
|
||||
obj_li: ae_promises.load__event_badge_obj_li,
|
||||
event_id,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge',
|
||||
@@ -169,9 +191,11 @@ export async function load_ae_obj_li__event_badge({
|
||||
} else {
|
||||
console.log('No results returned from API.');
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
||||
if (log_lvl)
|
||||
console.log('Attempting to load from local cache...');
|
||||
ae_promises.load__event_badge_obj_li = await db_events.badge
|
||||
.where('event_id').equals(event_id)
|
||||
.where('event_id')
|
||||
.equals(event_id)
|
||||
.toArray();
|
||||
} else {
|
||||
ae_promises.load__event_badge_obj_li = [];
|
||||
@@ -180,9 +204,13 @@ export async function load_ae_obj_li__event_badge({
|
||||
} catch (error: any) {
|
||||
console.log('API request failed.', error);
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
'Attempting to load from local cache after error...'
|
||||
);
|
||||
ae_promises.load__event_badge_obj_li = await db_events.badge
|
||||
.where('event_id').equals(event_id)
|
||||
.where('event_id')
|
||||
.equals(event_id)
|
||||
.toArray();
|
||||
} else {
|
||||
ae_promises.load__event_badge_obj_li = [];
|
||||
@@ -193,12 +221,13 @@ export async function load_ae_obj_li__event_badge({
|
||||
for (const badge_obj of ae_promises.load__event_badge_obj_li) {
|
||||
const current_template_id = badge_obj.event_badge_template_id;
|
||||
if (current_template_id) {
|
||||
badge_obj.event_badge_template = await load_ae_obj_id__event_badge_template({
|
||||
api_cfg: api_cfg,
|
||||
event_badge_template_id: current_template_id,
|
||||
try_cache: try_cache,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
badge_obj.event_badge_template =
|
||||
await load_ae_obj_id__event_badge_template({
|
||||
api_cfg: api_cfg,
|
||||
event_badge_template_id: current_template_id,
|
||||
try_cache: try_cache,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +252,9 @@ export async function create_ae_obj__event_badge({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** create_ae_obj__event_badge() *** event_id=${event_id}`);
|
||||
console.log(
|
||||
`*** create_ae_obj__event_badge() *** event_id=${event_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.create_nested_obj({
|
||||
@@ -275,7 +306,9 @@ export async function delete_ae_obj_id__event_badge({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`);
|
||||
console.log(
|
||||
`*** delete_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
@@ -315,7 +348,9 @@ export async function update_ae_obj__event_badge({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__event_badge() *** event_badge_id=${event_badge_id}`);
|
||||
console.log(
|
||||
`*** update_ae_obj__event_badge() *** event_badge_id=${event_badge_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.update_nested_obj({
|
||||
@@ -391,7 +426,9 @@ export async function search__event_badge({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventBadge[] | false> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__event_badge() *** event_id=${event_id} ft=${fulltext_search_qry_str}`);
|
||||
console.log(
|
||||
`*** search__event_badge() *** event_id=${event_id} ft=${fulltext_search_qry_str}`
|
||||
);
|
||||
}
|
||||
|
||||
const search_query: any = {
|
||||
@@ -406,15 +443,23 @@ export async function search__event_badge({
|
||||
// Multi-word support: Split query by spaces and search for all words (AND logic)
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.trim().length > 0) {
|
||||
const qry = fulltext_search_qry_str.trim();
|
||||
const words = qry.split(/\s+/).filter(w => w.length > 0);
|
||||
const words = qry.split(/\s+/).filter((w) => w.length > 0);
|
||||
|
||||
if (words.length === 1) {
|
||||
// Single word: use simple LIKE
|
||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${words[0]}%` });
|
||||
search_query.and.push({
|
||||
field: 'default_qry_str',
|
||||
op: 'like',
|
||||
value: `%${words[0]}%`
|
||||
});
|
||||
} else if (words.length > 1) {
|
||||
// Multiple words: each word must match (AND logic)
|
||||
for (const word of words) {
|
||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${word}%` });
|
||||
search_query.and.push({
|
||||
field: 'default_qry_str',
|
||||
op: 'like',
|
||||
value: `%${word}%`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,7 +469,11 @@ export async function search__event_badge({
|
||||
|
||||
if (affiliations_qry_str && affiliations_qry_str.trim().length > 0) {
|
||||
const qry = affiliations_qry_str.trim();
|
||||
search_query.and.push({ field: 'affiliations', op: 'like', value: `%${qry}%` });
|
||||
search_query.and.push({
|
||||
field: 'affiliations',
|
||||
op: 'like',
|
||||
value: `%${qry}%`
|
||||
});
|
||||
params['lk_qry'] = params['lk_qry'] || {};
|
||||
params['lk_qry']['affiliations'] = qry;
|
||||
}
|
||||
@@ -435,11 +484,19 @@ export async function search__event_badge({
|
||||
}
|
||||
|
||||
if (external_event_id) {
|
||||
search_query.and.push({ field: 'external_event_id', op: 'eq', value: external_event_id });
|
||||
search_query.and.push({
|
||||
field: 'external_event_id',
|
||||
op: 'eq',
|
||||
value: external_event_id
|
||||
});
|
||||
}
|
||||
|
||||
if (type_code) {
|
||||
search_query.and.push({ field: 'badge_type_code', op: 'eq', value: type_code });
|
||||
search_query.and.push({
|
||||
field: 'badge_type_code',
|
||||
op: 'eq',
|
||||
value: type_code
|
||||
});
|
||||
}
|
||||
|
||||
if (printed_status === 'printed') {
|
||||
@@ -448,11 +505,15 @@ export async function search__event_badge({
|
||||
search_query.and.push({ field: 'print_count', op: 'eq', value: 0 });
|
||||
}
|
||||
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
|
||||
ae_promises.search__event_badge_obj_li = await api
|
||||
.search_ae_obj({
|
||||
@@ -473,17 +534,21 @@ export async function search__event_badge({
|
||||
let result_li: ae_EventBadge[] = [];
|
||||
if (Array.isArray(badge_obj_li_get_result)) {
|
||||
result_li = badge_obj_li_get_result;
|
||||
} else if (badge_obj_li_get_result?.data && Array.isArray(badge_obj_li_get_result.data)) {
|
||||
} else if (
|
||||
badge_obj_li_get_result?.data &&
|
||||
Array.isArray(badge_obj_li_get_result.data)
|
||||
) {
|
||||
result_li = badge_obj_li_get_result.data;
|
||||
}
|
||||
|
||||
if (result_li.length > 0) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
||||
obj_li: result_li,
|
||||
event_id,
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__event_badge_props({
|
||||
obj_li: result_li,
|
||||
event_id,
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge',
|
||||
@@ -631,14 +696,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -663,7 +735,9 @@ export async function process_ae_obj__event_badge_props({
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
if (log_lvl) {
|
||||
console.log(`*** process_ae_obj__event_badge_props() *** event_id=${event_id}`);
|
||||
console.log(
|
||||
`*** process_ae_obj__event_badge_props() *** event_id=${event_id}`
|
||||
);
|
||||
}
|
||||
if (event_id) {
|
||||
if (!obj.event_id) obj.event_id = event_id;
|
||||
@@ -672,4 +746,4 @@ export async function process_ae_obj__event_badge_props({
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,11 +87,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -129,7 +133,9 @@ export async function load_ae_obj_id__event_badge_template({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event_badge_template() *** [V3] id=${event_badge_template_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event_badge_template() *** [V3] id=${event_badge_template_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -156,11 +162,13 @@ export async function load_ae_obj_id__event_badge_template({
|
||||
});
|
||||
}
|
||||
} else if (try_cache) {
|
||||
ae_promises.load__event_badge_template_obj = await db_events.badge_template.get(event_badge_template_id);
|
||||
ae_promises.load__event_badge_template_obj =
|
||||
await db_events.badge_template.get(event_badge_template_id);
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (try_cache) {
|
||||
ae_promises.load__event_badge_template_obj = await db_events.badge_template.get(event_badge_template_id);
|
||||
ae_promises.load__event_badge_template_obj =
|
||||
await db_events.badge_template.get(event_badge_template_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,19 +205,21 @@ export async function load_ae_obj_li__event_badge_template({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
try {
|
||||
ae_promises.load__event_badge_template_obj_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_badge_template',
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__event_badge_template_obj_li = await api.get_ae_obj_li(
|
||||
{
|
||||
api_cfg,
|
||||
obj_type: 'event_badge_template',
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
}
|
||||
);
|
||||
|
||||
if (ae_promises.load__event_badge_template_obj_li) {
|
||||
if (try_cache) {
|
||||
@@ -226,15 +236,19 @@ export async function load_ae_obj_li__event_badge_template({
|
||||
});
|
||||
}
|
||||
} else if (try_cache) {
|
||||
ae_promises.load__event_badge_template_obj_li = await db_events.badge_template
|
||||
.where('event_id').equals(event_id)
|
||||
.toArray();
|
||||
ae_promises.load__event_badge_template_obj_li =
|
||||
await db_events.badge_template
|
||||
.where('event_id')
|
||||
.equals(event_id)
|
||||
.toArray();
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (try_cache) {
|
||||
ae_promises.load__event_badge_template_obj_li = await db_events.badge_template
|
||||
.where('event_id').equals(event_id)
|
||||
.toArray();
|
||||
ae_promises.load__event_badge_template_obj_li =
|
||||
await db_events.badge_template
|
||||
.where('event_id')
|
||||
.equals(event_id)
|
||||
.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,115 +257,115 @@ export async function load_ae_obj_li__event_badge_template({
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function create_ae_obj__event_badge_template({
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_badge_template',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_badge_template',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result && try_cache) {
|
||||
const processed_obj_li = await process_ae_badge_template_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge_template',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
if (result && try_cache) {
|
||||
const processed_obj_li = await process_ae_badge_template_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge_template',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function delete_ae_obj_id__event_badge_template({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_badge_template_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_badge_template_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_badge_template_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_badge_template_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_badge_template',
|
||||
obj_id: event_badge_template_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_badge_template',
|
||||
obj_id: event_badge_template_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (try_cache) {
|
||||
await db_events.badge_template.delete(event_badge_template_id);
|
||||
}
|
||||
return result;
|
||||
if (try_cache) {
|
||||
await db_events.badge_template.delete(event_badge_template_id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function update_ae_obj__event_badge_template({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_badge_template_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_badge_template_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_badge_template_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_badge_template_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_badge_template',
|
||||
obj_id: event_badge_template_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_badge_template',
|
||||
obj_id: event_badge_template_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result && try_cache) {
|
||||
const processed_obj_li = await process_ae_badge_template_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge_template',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
if (result && try_cache) {
|
||||
const processed_obj_li = await process_ae_badge_template_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'badge_template',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
@@ -388,11 +402,15 @@ export async function search__event_badge_template({
|
||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||
};
|
||||
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
|
||||
const result_li = await api.search_ae_obj({
|
||||
api_cfg,
|
||||
@@ -418,4 +436,4 @@ export async function search__event_badge_template({
|
||||
});
|
||||
}
|
||||
return result_li || [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ export async function load_ae_obj_id__event_device({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventDevice | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event_device() *** [V3] id=${event_device_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event_device() *** [V3] id=${event_device_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -57,26 +59,30 @@ export async function load_ae_obj_id__event_device({
|
||||
});
|
||||
}
|
||||
} else if (try_cache) {
|
||||
ae_promises.load__event_device_obj = await db_events.device.get(event_device_id);
|
||||
ae_promises.load__event_device_obj =
|
||||
await db_events.device.get(event_device_id);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('V3 Request failed.', error);
|
||||
if (try_cache) {
|
||||
ae_promises.load__event_device_obj = await db_events.device.get(event_device_id);
|
||||
ae_promises.load__event_device_obj =
|
||||
await db_events.device.get(event_device_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ae_promises.load__event_device_obj) return null;
|
||||
|
||||
if (inc_location_id) {
|
||||
const current_location_id = ae_promises.load__event_device_obj.event_location_id;
|
||||
const current_location_id =
|
||||
ae_promises.load__event_device_obj.event_location_id;
|
||||
if (current_location_id) {
|
||||
ae_promises.load__event_device_obj.event_location_obj = await load_ae_obj_id__event_location({
|
||||
api_cfg,
|
||||
event_location_id: current_location_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__event_device_obj.event_location_obj =
|
||||
await load_ae_obj_id__event_location({
|
||||
api_cfg,
|
||||
event_location_id: current_location_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +121,9 @@ export async function load_ae_obj_li__event_device({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventDevice[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__event_device() *** [V3] for=${for_obj_type}:${for_obj_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__event_device() *** [V3] for=${for_obj_type}:${for_obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -150,14 +158,16 @@ export async function load_ae_obj_li__event_device({
|
||||
}
|
||||
} else if (try_cache) {
|
||||
ae_promises.load__event_device_obj_li = await db_events.device
|
||||
.where('event_id').equals(for_obj_id)
|
||||
.where('event_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('V3 List Request failed.', error);
|
||||
if (try_cache) {
|
||||
ae_promises.load__event_device_obj_li = await db_events.device
|
||||
.where('event_id').equals(for_obj_id)
|
||||
.where('event_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
}
|
||||
}
|
||||
@@ -165,12 +175,13 @@ export async function load_ae_obj_li__event_device({
|
||||
if (inc_location_id && ae_promises.load__event_device_obj_li) {
|
||||
for (const device of ae_promises.load__event_device_obj_li) {
|
||||
if (device.event_location_id) {
|
||||
device.event_location_obj = await load_ae_obj_id__event_location({
|
||||
api_cfg,
|
||||
event_location_id: device.event_location_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
device.event_location_obj =
|
||||
await load_ae_obj_id__event_location({
|
||||
api_cfg,
|
||||
event_location_id: device.event_location_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,155 +191,161 @@ export async function load_ae_obj_li__event_device({
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function create_ae_obj__event_device({
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventDevice | null> {
|
||||
if (!event_id) event_id = get(slct).event_id;
|
||||
if (!event_id) {
|
||||
console.error('create_ae_obj__event_device: event_id is required');
|
||||
return null;
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log(`*** create_ae_obj__event_device() *** [V3] event_id=${event_id}`);
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** create_ae_obj__event_device() *** [V3] event_id=${event_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_device',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_device',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_device_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_device_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'device',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'device',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function delete_ae_obj_id__event_device({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_device_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_device_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_device_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_device_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (!event_id) event_id = get(slct).event_id;
|
||||
if (!event_id) {
|
||||
console.error('delete_ae_obj_id__event_device: event_id is required');
|
||||
return null;
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__event_device() *** [V3] id=${event_device_id}`);
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** delete_ae_obj_id__event_device() *** [V3] id=${event_device_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_device',
|
||||
obj_id: event_device_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_device',
|
||||
obj_id: event_device_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (try_cache) {
|
||||
await db_events.device.delete(event_device_id);
|
||||
}
|
||||
if (try_cache) {
|
||||
await db_events.device.delete(event_device_id);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function update_ae_obj__event_device({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_device_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_device_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_device_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_device_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventDevice | null> {
|
||||
if (!event_id) event_id = get(slct).event_id;
|
||||
if (!event_id) {
|
||||
console.error('update_ae_obj__event_device: event_id is required');
|
||||
return null;
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__event_device() *** [V3] id=${event_device_id}`);
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** update_ae_obj__event_device() *** [V3] id=${event_device_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_device',
|
||||
obj_id: event_device_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_device',
|
||||
obj_id: event_device_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_device_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_device_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'device',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'device',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
@@ -361,7 +378,9 @@ export async function search__event_device({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventDevice[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__event_device() *** [V3] event_id=${event_id} qry=${qry_str}`);
|
||||
console.log(
|
||||
`*** search__event_device() *** [V3] event_id=${event_id} qry=${qry_str}`
|
||||
);
|
||||
}
|
||||
|
||||
const search_query: any = {
|
||||
@@ -370,11 +389,15 @@ export async function search__event_device({
|
||||
};
|
||||
|
||||
// Logical filters
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
|
||||
const result_li = await api.search_ae_obj({
|
||||
api_cfg,
|
||||
@@ -499,11 +522,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
|
||||
@@ -191,7 +191,9 @@ async function _refresh_file_li_background({
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
if (log_lvl) {
|
||||
console.log(`📡 [DEBUG] _refresh_file_li_background: Fetching files for ${for_obj_type}:${for_obj_id}`);
|
||||
console.log(
|
||||
`📡 [DEBUG] _refresh_file_li_background: Fetching files for ${for_obj_type}:${for_obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
@@ -211,7 +213,10 @@ async function _refresh_file_li_background({
|
||||
|
||||
if (result_li) {
|
||||
if (log_lvl) {
|
||||
console.log(`📦 [DEBUG] Raw API results count:`, result_li.length);
|
||||
console.log(
|
||||
`📦 [DEBUG] Raw API results count:`,
|
||||
result_li.length
|
||||
);
|
||||
if (result_li.length > 0) {
|
||||
console.log(`🔍 [DEBUG] Sample Raw IDs:`, {
|
||||
id: result_li[0].id,
|
||||
@@ -253,7 +258,10 @@ async function _refresh_file_li_background({
|
||||
}
|
||||
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log(`💾 [DEBUG] Saving ${processed.length} records to ae_events_db.file`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`💾 [DEBUG] Saving ${processed.length} records to ae_events_db.file`
|
||||
);
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'file',
|
||||
@@ -265,10 +273,15 @@ async function _refresh_file_li_background({
|
||||
return processed;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [DEBUG] Error in _refresh_file_li_background:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [DEBUG] Error in _refresh_file_li_background:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}export async function create_event_file_obj_from_hosted_file_async({
|
||||
}
|
||||
export async function create_event_file_obj_from_hosted_file_async({
|
||||
api_cfg,
|
||||
hosted_file_id,
|
||||
params = {},
|
||||
@@ -459,7 +472,7 @@ export async function search__event_file({
|
||||
});
|
||||
}
|
||||
|
||||
return processed; // Return processed data with mapped fields
|
||||
return processed; // Return processed data with mapped fields
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -545,7 +558,11 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
if (key.endsWith('_random')) {
|
||||
const newKey = key.slice(0, -7);
|
||||
// ONLY overwrite if the random variant has a valid value
|
||||
if (processed_obj[key] !== null && processed_obj[key] !== undefined && processed_obj[key] !== '') {
|
||||
if (
|
||||
processed_obj[key] !== null &&
|
||||
processed_obj[key] !== undefined &&
|
||||
processed_obj[key] !== ''
|
||||
) {
|
||||
(processed_obj as any)[newKey] = processed_obj[key];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,9 @@ export async function load_ae_obj_id__event_location({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventLocation | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event_location() *** [V3] id=${event_location_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event_location() *** [V3] id=${event_location_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Cache hit
|
||||
@@ -46,12 +48,26 @@ export async function load_ae_obj_id__event_location({
|
||||
const cached = await db_events.location.get(event_location_id);
|
||||
if (cached) {
|
||||
_refresh_location_id_background({
|
||||
api_cfg, event_location_id, view, try_cache,
|
||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
api_cfg,
|
||||
event_location_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl: 0
|
||||
});
|
||||
return await _handle_nested_loads(cached, {
|
||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
@@ -60,24 +76,65 @@ export async function load_ae_obj_id__event_location({
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_location_id_background({
|
||||
api_cfg, event_location_id, view, try_cache,
|
||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
api_cfg,
|
||||
event_location_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_location_id_background({ api_cfg, event_location_id, view, try_cache, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li, log_lvl }: any) {
|
||||
async function _refresh_location_id_background({
|
||||
api_cfg,
|
||||
event_location_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
const result = await api.get_ae_obj({ api_cfg, obj_type: 'event_location', obj_id: event_location_id, view, log_lvl });
|
||||
const result = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_location',
|
||||
obj_id: event_location_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_location_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__event_location_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'location', obj_li: [processed_obj], properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return await _handle_nested_loads(processed_obj, {
|
||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
@@ -129,23 +186,47 @@ export async function load_ae_obj_li__event_location({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventLocation[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__event_location() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__event_location() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Check cache
|
||||
if (try_cache) {
|
||||
try {
|
||||
const cached_li = await db_events.location.where('event_id').equals(for_obj_id).toArray();
|
||||
const cached_li = await db_events.location
|
||||
.where('event_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
if (cached_li && cached_li.length > 0) {
|
||||
_refresh_location_li_background({
|
||||
api_cfg, for_obj_type, for_obj_id,
|
||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
enabled, hidden, view, limit, offset, order_by_li, try_cache,
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
for (const loc of cached_li) {
|
||||
_handle_nested_loads(loc, {
|
||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl: 0
|
||||
});
|
||||
}
|
||||
@@ -156,31 +237,89 @@ export async function load_ae_obj_li__event_location({
|
||||
|
||||
// 2. SLOW PATH: API
|
||||
return await _refresh_location_li_background({
|
||||
api_cfg, for_obj_type, for_obj_id,
|
||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
enabled, hidden, view, limit, offset, order_by_li, try_cache,
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_location_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
||||
async function _refresh_location_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
const result_li = await api.get_ae_obj_li({ api_cfg, obj_type: 'event_location', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_location',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
});
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_location_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_location_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
// String-Only ID Vision: Ensure linking ID is set for indexing
|
||||
if (for_obj_type === 'event') {
|
||||
processed.forEach(loc => loc.event_id = for_obj_id);
|
||||
processed.forEach((loc) => (loc.event_id = for_obj_id));
|
||||
}
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'location', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
for (const loc of processed) {
|
||||
_handle_nested_loads(loc, {
|
||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl: 0
|
||||
});
|
||||
}
|
||||
@@ -193,34 +332,66 @@ async function _refresh_location_li_background({ api_cfg, for_obj_type, for_obj_
|
||||
/**
|
||||
* Handle nested data loads for a single location object.
|
||||
*/
|
||||
async function _handle_nested_loads(location_obj: any, { api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li, log_lvl }: any) {
|
||||
const current_location_id = location_obj.id || location_obj.event_location_id;
|
||||
async function _handle_nested_loads(
|
||||
location_obj: any,
|
||||
{
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_session_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
inc_device_li,
|
||||
inc_all_file_li,
|
||||
log_lvl
|
||||
}: any
|
||||
) {
|
||||
const current_location_id =
|
||||
location_obj.id || location_obj.event_location_id;
|
||||
if (!current_location_id) return location_obj;
|
||||
|
||||
const tasks = [];
|
||||
if (inc_file_li) {
|
||||
tasks.push(load_ae_obj_li__event_file({
|
||||
api_cfg, for_obj_type: 'event_location', for_obj_id: current_location_id,
|
||||
enabled: 'all', limit: 25, log_lvl
|
||||
}).then(res => location_obj.event_file_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_file({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_location',
|
||||
for_obj_id: current_location_id,
|
||||
enabled: 'all',
|
||||
limit: 25,
|
||||
log_lvl
|
||||
}).then((res) => (location_obj.event_file_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (inc_session_li) {
|
||||
tasks.push(load_ae_obj_li__event_session({
|
||||
api_cfg, for_obj_type: 'event_location', for_obj_id: current_location_id,
|
||||
inc_file_li: inc_all_file_li,
|
||||
inc_all_file_li: inc_all_file_li,
|
||||
inc_presentation_li: inc_presentation_li,
|
||||
inc_presenter_li: inc_presenter_li,
|
||||
enabled: 'enabled', hidden: 'not_hidden', limit: 150, log_lvl
|
||||
}).then(res => location_obj.event_session_obj_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_location',
|
||||
for_obj_id: current_location_id,
|
||||
inc_file_li: inc_all_file_li,
|
||||
inc_all_file_li: inc_all_file_li,
|
||||
inc_presentation_li: inc_presentation_li,
|
||||
inc_presenter_li: inc_presenter_li,
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
limit: 150,
|
||||
log_lvl
|
||||
}).then((res) => (location_obj.event_session_obj_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (inc_device_li) {
|
||||
tasks.push(load_ae_obj_li__event_device({
|
||||
api_cfg, for_obj_type: 'event_location', for_obj_id: current_location_id,
|
||||
enabled: 'all', limit: 50, log_lvl
|
||||
}).then(res => location_obj.event_device_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_device({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_location',
|
||||
for_obj_id: current_location_id,
|
||||
enabled: 'all',
|
||||
limit: 50,
|
||||
log_lvl
|
||||
}).then((res) => (location_obj.event_device_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (tasks.length > 0) await Promise.all(tasks);
|
||||
@@ -229,132 +400,183 @@ async function _handle_nested_loads(location_obj: any, { api_cfg, inc_file_li, i
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function create_ae_obj__event_location({
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventLocation | null> {
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_location',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_location',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_location_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_location_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function delete_ae_obj_id__event_location({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_location_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_location_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_location_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_location_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_location',
|
||||
obj_id: event_location_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.location.delete(event_location_id);
|
||||
return result;
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_location',
|
||||
obj_id: event_location_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.location.delete(event_location_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function update_ae_obj__event_location({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_location_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_location_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_location_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
event_location_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventLocation | null> {
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_location',
|
||||
obj_id: event_location_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_location_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_location',
|
||||
obj_id: event_location_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_location_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function search__event_location({
|
||||
api_cfg, event_id, qry_str = '', enabled = 'enabled', hidden = 'not_hidden', view = 'default', limit = 25, offset = 0, order_by_li = [{ sort: 'ASC' }, { name: 'ASC' }], try_cache = true, log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
qry_str = '',
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
view = 'default',
|
||||
limit = 25,
|
||||
offset = 0,
|
||||
order_by_li = [{ sort: 'ASC' }, { name: 'ASC' }],
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any; event_id: string; qry_str?: string; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; view?: string; limit?: number; offset?: number; order_by_li?: any; try_cache?: boolean; log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
qry_str?: string;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: any;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventLocation[]> {
|
||||
const search_query: any = { q: qry_str, and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
const search_query: any = {
|
||||
q: qry_str,
|
||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||
};
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||
|
||||
const result_li = await api.search_ae_obj({ api_cfg, obj_type: 'event_location', search_query, order_by_li, view, limit, offset, log_lvl });
|
||||
const result_li = await api.search_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_location',
|
||||
search_query,
|
||||
order_by_li,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_location_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_location_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'location', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'location',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
@@ -362,10 +584,40 @@ export async function search__event_location({
|
||||
}
|
||||
|
||||
export const properties_to_save = [
|
||||
'id', 'event_location_id', 'event_location_id_random', 'event_id', 'event_id_random', 'external_id', 'code', 'name', 'description', 'passcode', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'event_name'
|
||||
'id',
|
||||
'event_location_id',
|
||||
'event_location_id_random',
|
||||
'event_id',
|
||||
'event_id_random',
|
||||
'external_id',
|
||||
'code',
|
||||
'name',
|
||||
'description',
|
||||
'passcode',
|
||||
'enable',
|
||||
'hide',
|
||||
'priority',
|
||||
'sort',
|
||||
'group',
|
||||
'notes',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
'tmp_sort_1',
|
||||
'tmp_sort_2',
|
||||
'event_name'
|
||||
];
|
||||
|
||||
async function _process_generic_props<T extends Record<string, any>>({ obj_li, obj_type, log_lvl = 0, specific_processor }: { obj_li: T[]; obj_type: string; log_lvl?: number; specific_processor?: (obj: T) => Promise<T> | T; }): Promise<T[]> {
|
||||
async function _process_generic_props<T extends Record<string, any>>({
|
||||
obj_li,
|
||||
obj_type,
|
||||
log_lvl = 0,
|
||||
specific_processor
|
||||
}: {
|
||||
obj_li: T[];
|
||||
obj_type: string;
|
||||
log_lvl?: number;
|
||||
specific_processor?: (obj: T) => Promise<T> | T;
|
||||
}): Promise<T[]> {
|
||||
if (!obj_li || obj_li.length === 0) return [];
|
||||
const processed_obj_li: T[] = [];
|
||||
for (const original_obj of obj_li) {
|
||||
@@ -378,24 +630,42 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
||||
}
|
||||
const randomIdKey = `${obj_type}_id_random`;
|
||||
const baseIdKey = `${obj_type}_id`;
|
||||
if (processed_obj[randomIdKey]) (processed_obj as any).id = processed_obj[randomIdKey];
|
||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
||||
if (processed_obj[randomIdKey])
|
||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||
else if (processed_obj[baseIdKey])
|
||||
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor)
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
}
|
||||
return processed_obj_li;
|
||||
}
|
||||
|
||||
export async function process_ae_obj__event_location_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
||||
return _process_generic_props({ obj_li, obj_type: 'event_location', log_lvl, specific_processor: (obj) => {
|
||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||
return obj;
|
||||
}});
|
||||
}
|
||||
export async function process_ae_obj__event_location_props({
|
||||
obj_li,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
obj_li: any[];
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
return _process_generic_props({
|
||||
obj_li,
|
||||
obj_type: 'event_location',
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,41 +37,116 @@ export async function load_ae_obj_id__event_presentation({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresentation | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event_presentation() *** id=${event_presentation_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event_presentation() *** id=${event_presentation_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Cache hit
|
||||
if (try_cache) {
|
||||
try {
|
||||
const cached = await db_events.presentation.get(event_presentation_id);
|
||||
const cached = await db_events.presentation.get(
|
||||
event_presentation_id
|
||||
);
|
||||
if (cached) {
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_presentation_id_background({ api_cfg, event_presentation_id, view, try_cache, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl: 0 });
|
||||
_refresh_presentation_id_background({
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl: 0
|
||||
});
|
||||
// Await nested loads from cache to return a complete object
|
||||
return await _handle_nested_loads(cached, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
|
||||
return await _handle_nested_loads(cached, {
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_presentation_id_background({ api_cfg, event_presentation_id, view, try_cache, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl });
|
||||
return await _refresh_presentation_id_background({
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal background refresh for a single presentation
|
||||
*/
|
||||
async function _refresh_presentation_id_background({ api_cfg, event_presentation_id, view, try_cache, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl }: any) {
|
||||
async function _refresh_presentation_id_background({
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
const result = await api.get_ae_obj({ api_cfg, obj_type: 'event_presentation', obj_id: event_presentation_id, view, log_lvl });
|
||||
const result = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_presentation',
|
||||
obj_id: event_presentation_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__event_presentation_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: [processed_obj], properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presentation',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
// During refresh, we disable child SWR to prevent a request storm
|
||||
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache: false, log_lvl });
|
||||
return await _handle_nested_loads(processed_obj, {
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache: false,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
return null;
|
||||
@@ -80,23 +155,54 @@ async function _refresh_presentation_id_background({ api_cfg, event_presentation
|
||||
/**
|
||||
* Helper to handle nested collection loads for a presentation
|
||||
*/
|
||||
async function _handle_nested_loads(presentation_obj: any, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl }: any) {
|
||||
const current_presentation_id = presentation_obj.id || presentation_obj.event_presentation_id;
|
||||
async function _handle_nested_loads(
|
||||
presentation_obj: any,
|
||||
{
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any
|
||||
) {
|
||||
const current_presentation_id =
|
||||
presentation_obj.id || presentation_obj.event_presentation_id;
|
||||
if (!current_presentation_id) return presentation_obj;
|
||||
|
||||
const tasks = [];
|
||||
if (inc_file_li) {
|
||||
tasks.push(load_ae_obj_li__event_file({
|
||||
api_cfg, for_obj_type: 'event_presentation', for_obj_id: current_presentation_id,
|
||||
enabled, limit: 25, try_cache, log_lvl
|
||||
}).then(res => presentation_obj.event_file_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_file({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: current_presentation_id,
|
||||
enabled,
|
||||
limit: 25,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (presentation_obj.event_file_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (inc_presenter_li) {
|
||||
tasks.push(load_ae_obj_li__event_presenter({
|
||||
api_cfg, for_obj_type: 'event_presentation', for_obj_id: current_presentation_id,
|
||||
inc_file_li, enabled, hidden, limit, offset, try_cache, log_lvl
|
||||
}).then(res => presentation_obj.event_presenter_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_presenter({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: current_presentation_id,
|
||||
inc_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (presentation_obj.event_presenter_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (tasks.length > 0) await Promise.all(tasks);
|
||||
@@ -140,17 +246,36 @@ export async function load_ae_obj_li__event_presentation({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresentation[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__event_presentation() *** for=${for_obj_type}:${for_obj_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__event_presentation() *** for=${for_obj_type}:${for_obj_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Cache hit
|
||||
if (try_cache) {
|
||||
try {
|
||||
// String-Only ID Vision: query event_session_id using the string ID
|
||||
const cached_li = await db_events.presentation.where('event_session_id').equals(for_obj_id).toArray();
|
||||
const cached_li = await db_events.presentation
|
||||
.where('event_session_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
if (cached_li && cached_li.length > 0) {
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: 0 });
|
||||
_refresh_presentation_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
|
||||
// Warm cache for nested loads in the background (FIRE AND FORGET)
|
||||
// DEPRECATED Optimization: Don't fire child loads for every item in a list here.
|
||||
@@ -167,23 +292,72 @@ export async function load_ae_obj_li__event_presentation({
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl });
|
||||
return await _refresh_presentation_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
||||
async function _refresh_presentation_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
const result_li = await api.get_ae_obj_li({ api_cfg, obj_type: 'event_presentation', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_presentation',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
});
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_presentation_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
// Ensure the linking ID is set correctly for indexing
|
||||
if (for_obj_type === 'event_session') {
|
||||
processed.forEach(p => p.event_session_id = for_obj_id);
|
||||
processed.forEach((p) => (p.event_session_id = for_obj_id));
|
||||
}
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presentation',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
||||
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
||||
// to IDB *before* the write completes, causing empty results on cold-start.
|
||||
@@ -194,9 +368,21 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
|
||||
// before presenter data was loaded, causing "refresh twice" bug on cold-start.
|
||||
// Now we await all nested loads AND preserve try_cache so presenters are written to IDB.
|
||||
if (inc_file_li || inc_presenter_li) {
|
||||
await Promise.all(processed.map(p =>
|
||||
_handle_nested_loads(p, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 })
|
||||
));
|
||||
await Promise.all(
|
||||
processed.map((p) =>
|
||||
_handle_nested_loads(p, {
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
@@ -206,42 +392,45 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function create_ae_obj__event_presentation({
|
||||
api_cfg,
|
||||
event_session_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_session_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_session_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_session_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresentation | null> {
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_session',
|
||||
for_obj_id: event_session_id,
|
||||
obj_type: 'event_presentation',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_session',
|
||||
for_obj_id: event_session_id,
|
||||
obj_type: 'event_presentation',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presentation',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presentation_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presentation',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
@@ -259,7 +448,11 @@ export async function delete_ae_obj_id__event_presentation({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
const result = await api.delete_ae_obj({
|
||||
api_cfg, obj_type: 'event_presentation', obj_id: event_presentation_id, method, log_lvl
|
||||
api_cfg,
|
||||
obj_type: 'event_presentation',
|
||||
obj_id: event_presentation_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.presentation.delete(event_presentation_id);
|
||||
return result;
|
||||
@@ -280,13 +473,26 @@ export async function update_ae_obj__event_presentation({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresentation | null> {
|
||||
const result = await api.update_ae_obj({
|
||||
api_cfg, obj_type: 'event_presentation', obj_id: event_presentation_id, fields: data_kv, log_lvl
|
||||
api_cfg,
|
||||
obj_type: 'event_presentation',
|
||||
obj_id: event_presentation_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__event_presentation_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: [processed_obj], properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presentation',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
@@ -295,24 +501,74 @@ export async function update_ae_obj__event_presentation({
|
||||
|
||||
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
||||
export async function search__event_presentation({
|
||||
api_cfg, event_id, fulltext_search_qry_str = '', like_search_qry_str = '', enabled = 'enabled', hidden = 'not_hidden', view = 'default', limit = 50, offset = 0, order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }], try_cache = true, log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
fulltext_search_qry_str = '',
|
||||
like_search_qry_str = '',
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
view = 'default',
|
||||
limit = 50,
|
||||
offset = 0,
|
||||
order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }],
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any; event_id: string; fulltext_search_qry_str?: string; like_search_qry_str?: string; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; view?: string; limit?: number; offset?: number; order_by_li?: any; try_cache?: boolean; log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
fulltext_search_qry_str?: string;
|
||||
like_search_qry_str?: string;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: any;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresentation[]> {
|
||||
const search_query: any = { q: '', and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
||||
const search_query: any = {
|
||||
q: '',
|
||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||
};
|
||||
const params: key_val = {};
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) params['ft_qry'] = { 'default_qry_str': fulltext_search_qry_str };
|
||||
if (like_search_qry_str) params['lk_qry'] = { 'default_qry_str': like_search_qry_str };
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
||||
params['ft_qry'] = { default_qry_str: fulltext_search_qry_str };
|
||||
if (like_search_qry_str)
|
||||
params['lk_qry'] = { default_qry_str: like_search_qry_str };
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
|
||||
const result_li = await api.search_ae_obj({ api_cfg, obj_type: 'event_presentation', search_query, order_by_li, params, view, limit, offset, log_lvl });
|
||||
const result_li = await api.search_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_presentation',
|
||||
search_query,
|
||||
order_by_li,
|
||||
params,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_presentation_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presentation',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
@@ -322,10 +578,53 @@ export async function search__event_presentation({
|
||||
export const qry__event_presentation = search__event_presentation;
|
||||
|
||||
export const properties_to_save = [
|
||||
'id', 'event_presentation_id', 'event_presentation_id_random', 'external_id', 'code', 'for_type', 'for_id', 'for_id_random', 'type_code', 'event_id', 'event_session_id', 'event_abstract_id', 'event_id_random', 'event_session_id_random', 'event_abstract_id_random', 'abstract_code', 'name', 'description', 'start_datetime', 'end_datetime', 'passcode', 'hide_event_launcher', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'event_session_code', 'event_session_name'
|
||||
'id',
|
||||
'event_presentation_id',
|
||||
'event_presentation_id_random',
|
||||
'external_id',
|
||||
'code',
|
||||
'for_type',
|
||||
'for_id',
|
||||
'for_id_random',
|
||||
'type_code',
|
||||
'event_id',
|
||||
'event_session_id',
|
||||
'event_abstract_id',
|
||||
'event_id_random',
|
||||
'event_session_id_random',
|
||||
'event_abstract_id_random',
|
||||
'abstract_code',
|
||||
'name',
|
||||
'description',
|
||||
'start_datetime',
|
||||
'end_datetime',
|
||||
'passcode',
|
||||
'hide_event_launcher',
|
||||
'enable',
|
||||
'hide',
|
||||
'priority',
|
||||
'sort',
|
||||
'group',
|
||||
'notes',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
'tmp_sort_1',
|
||||
'tmp_sort_2',
|
||||
'event_session_code',
|
||||
'event_session_name'
|
||||
];
|
||||
|
||||
async function _process_generic_props<T extends Record<string, any>>({ obj_li, obj_type, log_lvl = 0, specific_processor }: { obj_li: T[]; obj_type: string; log_lvl?: number; specific_processor?: (obj: T) => Promise<T> | T; }): Promise<T[]> {
|
||||
async function _process_generic_props<T extends Record<string, any>>({
|
||||
obj_li,
|
||||
obj_type,
|
||||
log_lvl = 0,
|
||||
specific_processor
|
||||
}: {
|
||||
obj_li: T[];
|
||||
obj_type: string;
|
||||
log_lvl?: number;
|
||||
specific_processor?: (obj: T) => Promise<T> | T;
|
||||
}): Promise<T[]> {
|
||||
if (!obj_li || obj_li.length === 0) return [];
|
||||
const processed_obj_li: T[] = [];
|
||||
for (const original_obj of obj_li) {
|
||||
@@ -338,26 +637,48 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
||||
}
|
||||
const randomIdKey = `${obj_type}_id_random`;
|
||||
const baseIdKey = `${obj_type}_id`;
|
||||
if (processed_obj[randomIdKey]) (processed_obj as any).id = processed_obj[randomIdKey];
|
||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
||||
if (processed_obj[randomIdKey])
|
||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||
else if (processed_obj[baseIdKey])
|
||||
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor)
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
}
|
||||
return processed_obj_li;
|
||||
}
|
||||
|
||||
export async function process_ae_obj__event_presentation_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
||||
return _process_generic_props({ obj_li, obj_type: 'event_presentation', log_lvl, specific_processor: (obj) => {
|
||||
// Ensure linking IDs are the string versions for indexing
|
||||
if (obj.event_session_id_random) obj.event_session_id = obj.event_session_id_random;
|
||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||
return obj;
|
||||
}});
|
||||
}
|
||||
export async function process_ae_obj__event_presentation_props({
|
||||
obj_li,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
obj_li: any[];
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
return _process_generic_props({
|
||||
obj_li,
|
||||
obj_type: 'event_presentation',
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
// Ensure linking IDs are the string versions for indexing
|
||||
if (obj.event_session_id_random)
|
||||
obj.event_session_id = obj.event_session_id_random;
|
||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ export async function load_ae_obj_id__event_presenter({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresenter | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event_presenter() *** [V3] id=${event_presenter_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__event_presenter() *** [V3] id=${event_presenter_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Cache hit
|
||||
@@ -38,30 +40,71 @@ export async function load_ae_obj_id__event_presenter({
|
||||
const cached = await db_events.presenter.get(event_presenter_id);
|
||||
if (cached) {
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_presenter_id_background({ api_cfg, event_presenter_id, view, try_cache, inc_file_li, log_lvl: 0 });
|
||||
_refresh_presenter_id_background({
|
||||
api_cfg,
|
||||
event_presenter_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
log_lvl: 0
|
||||
});
|
||||
return cached;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_presenter_id_background({ api_cfg, event_presenter_id, view, try_cache, inc_file_li, log_lvl });
|
||||
return await _refresh_presenter_id_background({
|
||||
api_cfg,
|
||||
event_presenter_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_presenter_id_background({ api_cfg, event_presenter_id, view, try_cache, inc_file_li, log_lvl }: any) {
|
||||
async function _refresh_presenter_id_background({
|
||||
api_cfg,
|
||||
event_presenter_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
const result = await api.get_ae_obj({ api_cfg, obj_type: 'event_presenter', obj_id: event_presenter_id, view, log_lvl });
|
||||
const result = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_presenter',
|
||||
obj_id: event_presenter_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__event_presenter_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: [processed_obj], properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
if (inc_file_li) {
|
||||
processed_obj.event_file_li = await load_ae_obj_li__event_file({
|
||||
api_cfg, for_obj_type: 'event_presenter', for_obj_id: event_presenter_id,
|
||||
enabled: 'all', limit: 25, try_cache: false, log_lvl
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presenter',
|
||||
for_obj_id: event_presenter_id,
|
||||
enabled: 'all',
|
||||
limit: 25,
|
||||
try_cache: false,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
@@ -104,7 +147,9 @@ export async function load_ae_obj_li__event_presenter({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresenter[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__event_presenter() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__event_presenter() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Check cache using specific indices
|
||||
@@ -112,31 +157,94 @@ export async function load_ae_obj_li__event_presenter({
|
||||
try {
|
||||
let cached_li: any[] = [];
|
||||
if (for_obj_type === 'event_presentation') {
|
||||
cached_li = await db_events.presenter.where('event_presentation_id').equals(for_obj_id).toArray();
|
||||
cached_li = await db_events.presenter
|
||||
.where('event_presentation_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
} else if (for_obj_type === 'event_session') {
|
||||
cached_li = await db_events.presenter.where('event_session_id').equals(for_obj_id).toArray();
|
||||
cached_li = await db_events.presenter
|
||||
.where('event_session_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
} else if (for_obj_type === 'event') {
|
||||
cached_li = await db_events.presenter.where('event_id').equals(for_obj_id).toArray();
|
||||
cached_li = await db_events.presenter
|
||||
.where('event_id')
|
||||
.equals(for_obj_id)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
if (cached_li && cached_li.length > 0) {
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: 0 });
|
||||
_refresh_presenter_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
return cached_li;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl });
|
||||
return await _refresh_presenter_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
||||
async function _refresh_presenter_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
inc_file_li,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
const result_li = await api.get_ae_obj_li({ api_cfg, obj_type: 'event_presenter', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_presenter',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
});
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_presenter_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
// String-Only ID Vision: Ensure linking ID is set for indexing
|
||||
processed.forEach((p) => {
|
||||
@@ -155,7 +263,13 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
|
||||
});
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
||||
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
||||
// to IDB *before* the write completes, causing empty results on cold-start.
|
||||
@@ -164,10 +278,15 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
|
||||
|
||||
// Background nested loads for refreshed items (FIRE AND FORGET)
|
||||
if (inc_file_li) {
|
||||
processed.forEach(p => {
|
||||
processed.forEach((p) => {
|
||||
load_ae_obj_li__event_file({
|
||||
api_cfg, for_obj_type: 'event_presenter', for_obj_id: p.id,
|
||||
enabled: 'all', limit: 25, try_cache: false, log_lvl: 0
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presenter',
|
||||
for_obj_id: p.id,
|
||||
enabled: 'all',
|
||||
limit: 25,
|
||||
try_cache: false,
|
||||
log_lvl: 0
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -180,128 +299,143 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function create_ae_obj__event_presenter({
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_presentation_id?: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_presentation_id?: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresenter | null> {
|
||||
if (!event_presentation_id) event_presentation_id = get(events_slct).event_presentation_id;
|
||||
if (!event_presentation_id)
|
||||
event_presentation_id = get(events_slct).event_presentation_id;
|
||||
if (!event_presentation_id) {
|
||||
console.error('create_ae_obj__event_presenter: event_presentation_id is required');
|
||||
console.error(
|
||||
'create_ae_obj__event_presenter: event_presentation_id is required'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: event_presentation_id,
|
||||
obj_type: 'event_presenter',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: event_presentation_id,
|
||||
obj_type: 'event_presenter',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presenter_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function delete_ae_obj_id__event_presenter({
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
event_presenter_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
event_presenter_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_presentation_id?: string;
|
||||
event_presenter_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_presentation_id?: string;
|
||||
event_presenter_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (!event_presentation_id) event_presentation_id = get(events_slct).event_presentation_id;
|
||||
if (!event_presentation_id)
|
||||
event_presentation_id = get(events_slct).event_presentation_id;
|
||||
if (!event_presentation_id) {
|
||||
console.error('delete_ae_obj_id__event_presenter: event_presentation_id is required');
|
||||
console.error(
|
||||
'delete_ae_obj_id__event_presenter: event_presentation_id is required'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: event_presentation_id,
|
||||
obj_type: 'event_presenter',
|
||||
obj_id: event_presenter_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.presenter.delete(event_presenter_id);
|
||||
return result;
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: event_presentation_id,
|
||||
obj_type: 'event_presenter',
|
||||
obj_id: event_presenter_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.presenter.delete(event_presenter_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updated 2026-01-20 to V3
|
||||
export async function update_ae_obj__event_presenter({
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
event_presenter_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_presentation_id,
|
||||
event_presenter_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_presentation_id?: string;
|
||||
event_presenter_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_presentation_id?: string;
|
||||
event_presenter_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresenter | null> {
|
||||
if (!event_presentation_id) event_presentation_id = get(events_slct).event_presentation_id;
|
||||
if (!event_presentation_id)
|
||||
event_presentation_id = get(events_slct).event_presentation_id;
|
||||
if (!event_presentation_id) {
|
||||
console.error('update_ae_obj__event_presenter: event_presentation_id is required');
|
||||
console.error(
|
||||
'update_ae_obj__event_presenter: event_presentation_id is required'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: event_presentation_id,
|
||||
obj_type: 'event_presenter',
|
||||
obj_id: event_presenter_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_presentation',
|
||||
for_obj_id: event_presentation_id,
|
||||
obj_type: 'event_presenter',
|
||||
obj_id: event_presenter_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_presenter_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
||||
@@ -320,7 +454,11 @@ export async function search__event_presenter({
|
||||
view = 'default',
|
||||
limit = 25,
|
||||
offset = 0,
|
||||
order_by_li = [{ sort: 'ASC' }, { given_name: 'ASC' }, { family_name: 'ASC' }],
|
||||
order_by_li = [
|
||||
{ sort: 'ASC' },
|
||||
{ given_name: 'ASC' },
|
||||
{ family_name: 'ASC' }
|
||||
],
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
@@ -342,29 +480,71 @@ export async function search__event_presenter({
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventPresenter[]> {
|
||||
const search_query: any = { q: '', and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
||||
const search_query: any = {
|
||||
q: '',
|
||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||
};
|
||||
const params: key_val = {};
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
||||
params['ft_qry'] = { default_qry_str: fulltext_search_qry_str };
|
||||
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2)
|
||||
params['ft_qry'] = { ...params['ft_qry'], event_presenter_li_qry_str: ft_presenter_search_qry_str };
|
||||
if (like_search_qry_str) params['lk_qry'] = { default_qry_str: like_search_qry_str };
|
||||
params['ft_qry'] = {
|
||||
...params['ft_qry'],
|
||||
event_presenter_li_qry_str: ft_presenter_search_qry_str
|
||||
};
|
||||
if (like_search_qry_str)
|
||||
params['lk_qry'] = { default_qry_str: like_search_qry_str };
|
||||
if (like_presentation_search_qry_str)
|
||||
params['lk_qry'] = { ...params['lk_qry'], event_presentation_li_qry_str: like_presentation_search_qry_str };
|
||||
params['lk_qry'] = {
|
||||
...params['lk_qry'],
|
||||
event_presentation_li_qry_str: like_presentation_search_qry_str
|
||||
};
|
||||
if (like_presenter_search_qry_str)
|
||||
params['lk_qry'] = { ...params['lk_qry'], event_presenter_li_qry_str: like_presenter_search_qry_str };
|
||||
if (agree !== null) search_query.and.push({ field: 'agree', op: 'eq', value: agree ? 1 : 0 });
|
||||
if (biography === true) search_query.and.push({ field: 'biography', op: 'ne', value: '' });
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
params['lk_qry'] = {
|
||||
...params['lk_qry'],
|
||||
event_presenter_li_qry_str: like_presenter_search_qry_str
|
||||
};
|
||||
if (agree !== null)
|
||||
search_query.and.push({
|
||||
field: 'agree',
|
||||
op: 'eq',
|
||||
value: agree ? 1 : 0
|
||||
});
|
||||
if (biography === true)
|
||||
search_query.and.push({ field: 'biography', op: 'ne', value: '' });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
|
||||
const result_li = await api.search_ae_obj({ api_cfg, obj_type: 'event_presenter', search_query, order_by_li, params, view, limit, offset, log_lvl });
|
||||
const result_li = await api.search_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_presenter',
|
||||
search_query,
|
||||
order_by_li,
|
||||
params,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_presenter_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'presenter',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
@@ -400,8 +580,16 @@ export async function email_sign_in__event_presenter({
|
||||
session_name?: string | null;
|
||||
presentation_name?: string | null;
|
||||
}) {
|
||||
if (!to_email || !person_id || !person_passcode || !event_id || !event_presenter_id) {
|
||||
console.error('Missing required parameters for email_sign_in__event_presenter');
|
||||
if (
|
||||
!to_email ||
|
||||
!person_id ||
|
||||
!person_passcode ||
|
||||
!event_id ||
|
||||
!event_presenter_id
|
||||
) {
|
||||
console.error(
|
||||
'Missing required parameters for email_sign_in__event_presenter'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const subject = `Pres Mgmt Hub Sign In Link for Presenter: ${to_name ?? 'Presenter'}`;
|
||||
@@ -420,10 +608,75 @@ export async function email_sign_in__event_presenter({
|
||||
}
|
||||
|
||||
export const properties_to_save = [
|
||||
'id', 'event_presenter_id', 'event_presenter_id_random', 'external_id', 'code', 'event_id', 'event_session_id', 'event_presentation_id', 'event_person_id', 'person_id', 'person_profile_id', 'person_id_random', 'person_profile_id_random', 'pronouns', 'informal_name', 'title_names', 'given_name', 'middle_name', 'family_name', 'designations', 'professional_title', 'full_name', 'affiliations', 'email', 'biography', 'agree', 'comments', 'passcode', 'hide_event_launcher', 'data_json', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'file_count', 'event_session_code', 'event_session_name', 'event_session_start_datetime', 'event_presentation_code', 'event_presentation_name', 'event_presentation_start_datetime', 'person_external_id', 'person_external_sys_id', 'person_given_name', 'person_family_name', 'person_full_name', 'person_professional_title', 'person_affiliations', 'person_primary_email', 'person_passcode'
|
||||
'id',
|
||||
'event_presenter_id',
|
||||
'event_presenter_id_random',
|
||||
'external_id',
|
||||
'code',
|
||||
'event_id',
|
||||
'event_session_id',
|
||||
'event_presentation_id',
|
||||
'event_person_id',
|
||||
'person_id',
|
||||
'person_profile_id',
|
||||
'person_id_random',
|
||||
'person_profile_id_random',
|
||||
'pronouns',
|
||||
'informal_name',
|
||||
'title_names',
|
||||
'given_name',
|
||||
'middle_name',
|
||||
'family_name',
|
||||
'designations',
|
||||
'professional_title',
|
||||
'full_name',
|
||||
'affiliations',
|
||||
'email',
|
||||
'biography',
|
||||
'agree',
|
||||
'comments',
|
||||
'passcode',
|
||||
'hide_event_launcher',
|
||||
'data_json',
|
||||
'enable',
|
||||
'hide',
|
||||
'priority',
|
||||
'sort',
|
||||
'group',
|
||||
'notes',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
'tmp_sort_1',
|
||||
'tmp_sort_2',
|
||||
'file_count',
|
||||
'event_session_code',
|
||||
'event_session_name',
|
||||
'event_session_start_datetime',
|
||||
'event_presentation_code',
|
||||
'event_presentation_name',
|
||||
'event_presentation_start_datetime',
|
||||
'person_external_id',
|
||||
'person_external_sys_id',
|
||||
'person_given_name',
|
||||
'person_family_name',
|
||||
'person_full_name',
|
||||
'person_professional_title',
|
||||
'person_affiliations',
|
||||
'person_primary_email',
|
||||
'person_passcode'
|
||||
];
|
||||
|
||||
async function _process_generic_props<T extends Record<string, any>>({ obj_li, obj_type, log_lvl = 0, specific_processor }: { obj_li: T[]; obj_type: string; log_lvl?: number; specific_processor?: (obj: T) => Promise<T> | T; }): Promise<T[]> {
|
||||
async function _process_generic_props<T extends Record<string, any>>({
|
||||
obj_li,
|
||||
obj_type,
|
||||
log_lvl = 0,
|
||||
specific_processor
|
||||
}: {
|
||||
obj_li: T[];
|
||||
obj_type: string;
|
||||
log_lvl?: number;
|
||||
specific_processor?: (obj: T) => Promise<T> | T;
|
||||
}): Promise<T[]> {
|
||||
if (!obj_li || obj_li.length === 0) return [];
|
||||
const processed_obj_li: T[] = [];
|
||||
for (const original_obj of obj_li) {
|
||||
@@ -439,28 +692,50 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
||||
if (processed_obj[randomIdKey]) {
|
||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||
(processed_obj as any)[baseIdKey] = processed_obj[randomIdKey];
|
||||
}
|
||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
||||
} else if (processed_obj[baseIdKey])
|
||||
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor)
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
}
|
||||
return processed_obj_li;
|
||||
}
|
||||
|
||||
export async function process_ae_obj__event_presenter_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
||||
return _process_generic_props({ obj_li, obj_type: 'event_presenter', log_lvl, specific_processor: (obj) => {
|
||||
// String-Only ID Vision: Ensure linking IDs are the string versions for indexing
|
||||
if (obj.event_presenter_id_random) obj.event_presenter_id = obj.event_presenter_id_random;
|
||||
if (obj.event_presentation_id_random) obj.event_presentation_id = obj.event_presentation_id_random;
|
||||
if (obj.event_session_id_random) obj.event_session_id = obj.event_session_id_random;
|
||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||
return obj;
|
||||
}});
|
||||
export async function process_ae_obj__event_presenter_props({
|
||||
obj_li,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
obj_li: any[];
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
return _process_generic_props({
|
||||
obj_li,
|
||||
obj_type: 'event_presenter',
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
// String-Only ID Vision: Ensure linking IDs are the string versions for indexing
|
||||
if (obj.event_presenter_id_random)
|
||||
obj.event_presenter_id = obj.event_presenter_id_random;
|
||||
if (obj.event_presentation_id_random)
|
||||
obj.event_presentation_id = obj.event_presentation_id_random;
|
||||
if (obj.event_session_id_random)
|
||||
obj.event_session_id = obj.event_session_id_random;
|
||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +44,9 @@ export async function load_ae_obj_id__event_session({
|
||||
}): Promise<ae_EventSession | null> {
|
||||
const start_time = performance.now();
|
||||
if (log_lvl) {
|
||||
console.log(`🔎 [Trace] load_ae_obj_id__event_session: START (id=${event_session_id}, try_cache=${try_cache})`);
|
||||
console.log(
|
||||
`🔎 [Trace] load_ae_obj_id__event_session: START (id=${event_session_id}, try_cache=${try_cache})`
|
||||
);
|
||||
}
|
||||
|
||||
// Hierarchy Enforcement: Pulling presenters requires pulling presentations first
|
||||
@@ -56,65 +58,167 @@ export async function load_ae_obj_id__event_session({
|
||||
const cached = await db_events.session.get(event_session_id);
|
||||
if (cached) {
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale shell for id=${event_session_id}`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale shell for id=${event_session_id}`
|
||||
);
|
||||
|
||||
// Background tasks: refresh parent and warm child caches (non-blocking)
|
||||
_refresh_session_id_background({
|
||||
api_cfg, event_session_id, view, try_cache,
|
||||
inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li,
|
||||
enabled, hidden, limit, offset, log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
api_cfg,
|
||||
event_session_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
});
|
||||
|
||||
// In SWR mode, we fire child loads in background to warm IDB for the view's LiveQueries
|
||||
_handle_nested_loads(cached, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
|
||||
_handle_nested_loads(cached, {
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
|
||||
return cached; // Return immediately without awaiting nested loads
|
||||
} else if (log_lvl) {
|
||||
console.log(`⏳ [Trace] load_ae_obj_id: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for id=${event_session_id}`);
|
||||
console.log(
|
||||
`⏳ [Trace] load_ae_obj_id: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for id=${event_session_id}`
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_id: Cache access error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] load_ae_obj_id: Cache access error:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
if (log_lvl) console.log(`🚀 [Trace] load_ae_obj_id: Proceeding to API path for id=${event_session_id}`);
|
||||
return await _refresh_session_id_background({ api_cfg, event_session_id, view, try_cache, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl });
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`🚀 [Trace] load_ae_obj_id: Proceeding to API path for id=${event_session_id}`
|
||||
);
|
||||
return await _refresh_session_id_background({
|
||||
api_cfg,
|
||||
event_session_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal background refresh for a single session
|
||||
*/
|
||||
async function _refresh_session_id_background({ api_cfg, event_session_id, view, try_cache, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl }: any) {
|
||||
async function _refresh_session_id_background({
|
||||
api_cfg,
|
||||
event_session_id,
|
||||
view,
|
||||
try_cache,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
}: any) {
|
||||
const start_time = performance.now();
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
if (log_lvl) console.log(`📡 [Trace] _refresh_session_id: API Fetching id=${event_session_id}`);
|
||||
const result = await api.get_ae_obj({ api_cfg, obj_type: 'event_session', obj_id: event_session_id, view, log_lvl });
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📡 [Trace] _refresh_session_id: API Fetching id=${event_session_id}`
|
||||
);
|
||||
const result = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_session',
|
||||
obj_id: event_session_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__event_session_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
|
||||
if (log_lvl) console.log(`📦 [Trace] _refresh_session_id: Received from API at ${elapsed}ms (id=${processed_obj.id})`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📦 [Trace] _refresh_session_id: Received from API at ${elapsed}ms (id=${processed_obj.id})`
|
||||
);
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: [processed_obj], properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
||||
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
||||
// to IDB *before* the write completes, causing empty results on cold-start.
|
||||
await Promise.resolve();
|
||||
if (log_lvl) console.log(`💾 [Trace] _refresh_session_id: Saved to IDB cache.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`💾 [Trace] _refresh_session_id: Saved to IDB cache.`
|
||||
);
|
||||
}
|
||||
// CRITICAL FIX (2026-02-26): Preserve parent's try_cache value when loading nested data.
|
||||
// Previously set to `false`, which meant presentations/presenters were fetched from API
|
||||
// but NEVER written to IndexedDB, causing "refresh twice" bug on cold-start.
|
||||
// Now nested loads inherit parent's caching behavior for deterministic first-render.
|
||||
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl });
|
||||
return await _handle_nested_loads(processed_obj, {
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -122,29 +226,65 @@ async function _refresh_session_id_background({ api_cfg, event_session_id, view,
|
||||
/**
|
||||
* Helper to handle nested collection loads for a session
|
||||
*/
|
||||
async function _handle_nested_loads(session_obj: any, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl }: any) {
|
||||
async function _handle_nested_loads(
|
||||
session_obj: any,
|
||||
{
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any
|
||||
) {
|
||||
const start_time = performance.now();
|
||||
const current_session_id = session_obj.id || session_obj.event_session_id;
|
||||
if (!current_session_id) return session_obj;
|
||||
|
||||
const tasks = [];
|
||||
if (inc_file_li) {
|
||||
tasks.push(load_ae_obj_li__event_file({
|
||||
api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id,
|
||||
enabled, limit: 15, try_cache, log_lvl
|
||||
}).then(res => session_obj.event_file_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_file({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_session',
|
||||
for_obj_id: current_session_id,
|
||||
enabled,
|
||||
limit: 15,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (session_obj.event_file_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (inc_presentation_li) {
|
||||
tasks.push(load_ae_obj_li__event_presentation({
|
||||
api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id,
|
||||
inc_file_li: inc_all_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl
|
||||
}).then(res => session_obj.event_presentation_li = res));
|
||||
tasks.push(
|
||||
load_ae_obj_li__event_presentation({
|
||||
api_cfg,
|
||||
for_obj_type: 'event_session',
|
||||
for_obj_id: current_session_id,
|
||||
inc_file_li: inc_all_file_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}).then((res) => (session_obj.event_presentation_li = res))
|
||||
);
|
||||
}
|
||||
|
||||
if (tasks.length > 0) {
|
||||
await Promise.all(tasks);
|
||||
if (log_lvl) console.log(`🔗 [Trace] _handle_nested_loads: Finished child collections in ${(performance.now() - start_time).toFixed(2)}ms`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`🔗 [Trace] _handle_nested_loads: Finished child collections in ${(performance.now() - start_time).toFixed(2)}ms`
|
||||
);
|
||||
}
|
||||
return session_obj;
|
||||
}
|
||||
@@ -191,7 +331,9 @@ export async function load_ae_obj_li__event_session({
|
||||
}): Promise<ae_EventSession[]> {
|
||||
const start_time = performance.now();
|
||||
if (log_lvl) {
|
||||
console.log(`🔎 [Trace] load_ae_obj_li__event_session: START (for=${for_obj_type}:${for_obj_id}, try_cache=${try_cache})`);
|
||||
console.log(
|
||||
`🔎 [Trace] load_ae_obj_li__event_session: START (for=${for_obj_type}:${for_obj_id}, try_cache=${try_cache})`
|
||||
);
|
||||
}
|
||||
|
||||
// Hierarchy Enforcement: Pulling presenters requires pulling presentations first
|
||||
@@ -201,226 +343,409 @@ export async function load_ae_obj_li__event_session({
|
||||
try {
|
||||
// Robust lookup logic
|
||||
let query;
|
||||
if (for_obj_type === 'event_location') query = db_events.session.where('event_location_id').equals(for_obj_id);
|
||||
else if (for_obj_type === 'event') query = db_events.session.where('event_id').equals(for_obj_id);
|
||||
if (for_obj_type === 'event_location')
|
||||
query = db_events.session
|
||||
.where('event_location_id')
|
||||
.equals(for_obj_id);
|
||||
else if (for_obj_type === 'event')
|
||||
query = db_events.session.where('event_id').equals(for_obj_id);
|
||||
else query = db_events.session.where('for_id').equals(for_obj_id);
|
||||
|
||||
const cached_li = await query.toArray();
|
||||
|
||||
if (cached_li && cached_li.length > 0) {
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`
|
||||
);
|
||||
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_session_li_background({
|
||||
api_cfg, for_obj_type, for_obj_id, view,
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
view,
|
||||
// Optimization: Disable nested loads for list members to prevent request storms
|
||||
inc_file_li: false, inc_all_file_li: false, inc_presentation_li: false, inc_presenter_li: false,
|
||||
enabled, hidden, limit, offset, order_by_li, try_cache,
|
||||
inc_file_li: false,
|
||||
inc_all_file_li: false,
|
||||
inc_presentation_li: false,
|
||||
inc_presenter_li: false,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
});
|
||||
|
||||
return cached_li;
|
||||
} else if (log_lvl) {
|
||||
console.log(`⏳ [Trace] load_ae_obj_li: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for type=${for_obj_type} id=${for_obj_id}`);
|
||||
console.log(
|
||||
`⏳ [Trace] load_ae_obj_li: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for type=${for_obj_type} id=${for_obj_id}`
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_li: Cache access error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] load_ae_obj_li: Cache access error:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await _refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, view, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl });
|
||||
return await _refresh_session_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
view,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, view, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
||||
async function _refresh_session_li_background({
|
||||
api_cfg,
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
view,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
const start_time = performance.now();
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
if (log_lvl) console.log(`📡 [Trace] _refresh_session_li: API Fetching for=${for_obj_type}:${for_obj_id} (view=${view})`);
|
||||
const result_li = await api.get_ae_obj_li({ api_cfg, obj_type: 'event_session', for_obj_type, for_obj_id, view, enabled, hidden, limit, offset, order_by_li, log_lvl });
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📡 [Trace] _refresh_session_li: API Fetching for=${for_obj_type}:${for_obj_id} (view=${view})`
|
||||
);
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_session',
|
||||
for_obj_type,
|
||||
for_obj_id,
|
||||
view,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__event_session_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_session_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`📦 [Trace] _refresh_session_li: Received ${processed.length} items from API at ${elapsed}ms.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📦 [Trace] _refresh_session_li: Received ${processed.length} items from API at ${elapsed}ms.`
|
||||
);
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: processed, properties_to_save, log_lvl });
|
||||
if (log_lvl) console.log(`💾 [Trace] _refresh_session_li: Saved to IDB cache.`);
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`💾 [Trace] _refresh_session_li: Saved to IDB cache.`
|
||||
);
|
||||
}
|
||||
|
||||
// Fire nested loads for each session only if explicitly requested (usually only for single objects)
|
||||
if (inc_file_li || inc_presentation_li) {
|
||||
processed.forEach(s => {
|
||||
_handle_nested_loads(s, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
|
||||
processed.forEach((s) => {
|
||||
_handle_nested_loads(s, {
|
||||
api_cfg,
|
||||
inc_file_li,
|
||||
inc_all_file_li,
|
||||
inc_presentation_li,
|
||||
inc_presenter_li,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] _refresh_session_li: API error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(`❌ [Trace] _refresh_session_li: API error:`, e);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export async function create_ae_obj__event_session({
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventSession | null> {
|
||||
if (!event_id) event_id = get(slct).event_id;
|
||||
if (!event_id) {
|
||||
console.error('create_ae_obj__event_session: event_id is required');
|
||||
return null;
|
||||
}
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_session',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_session',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_session_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function delete_ae_obj_id__event_session({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_session_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_session_id,
|
||||
method = 'delete',
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_session_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_session_id: string;
|
||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (!event_id) event_id = get(slct).event_id;
|
||||
if (!event_id) {
|
||||
console.error('delete_ae_obj_id__event_session: event_id is required');
|
||||
return null;
|
||||
}
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_session',
|
||||
obj_id: event_session_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.session.delete(event_session_id);
|
||||
return result;
|
||||
const result = await api.delete_nested_ae_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_session',
|
||||
obj_id: event_session_id,
|
||||
method,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) await db_events.session.delete(event_session_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function update_ae_obj__event_session({
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_session_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
event_session_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_session_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id?: string;
|
||||
event_session_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventSession | null> {
|
||||
if (!event_id) event_id = get(slct).event_id;
|
||||
if (!event_id) {
|
||||
console.error('update_ae_obj__event_session: event_id is required');
|
||||
return null;
|
||||
}
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_session',
|
||||
obj_id: event_session_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: event_id,
|
||||
obj_type: 'event_session',
|
||||
obj_id: event_session_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__event_session_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function search__event_session({
|
||||
api_cfg, event_id, fulltext_search_qry_str = '', ft_presenter_search_qry_str = '', like_search_qry_str = '', like_presentation_search_qry_str = '', like_presenter_search_qry_str = '', like_poc_name_qry_str = '', location_name = null, qry_files = null, qry_poc_agree = null, qry_poc_kv_json = null, qry_start_datetime = null, enabled = 'enabled', hidden = 'not_hidden', view = 'default', limit = 50, offset = 0, order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }], try_cache = true, log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
fulltext_search_qry_str = '',
|
||||
ft_presenter_search_qry_str = '',
|
||||
like_search_qry_str = '',
|
||||
like_presentation_search_qry_str = '',
|
||||
like_presenter_search_qry_str = '',
|
||||
like_poc_name_qry_str = '',
|
||||
location_name = null,
|
||||
qry_files = null,
|
||||
qry_poc_agree = null,
|
||||
qry_poc_kv_json = null,
|
||||
qry_start_datetime = null,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
view = 'default',
|
||||
limit = 50,
|
||||
offset = 0,
|
||||
order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }],
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any; event_id: string; fulltext_search_qry_str?: string; ft_presenter_search_qry_str?: string | null; like_search_qry_str?: string; like_presentation_search_qry_str?: string; like_presenter_search_qry_str?: string; like_poc_name_qry_str?: string; location_name?: null | string; qry_files?: null | boolean; qry_poc_agree?: null | boolean; qry_poc_kv_json?: null | boolean; qry_start_datetime?: string | null; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; view?: string; limit?: number; offset?: number; order_by_li?: any; try_cache?: boolean; log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
fulltext_search_qry_str?: string;
|
||||
ft_presenter_search_qry_str?: string | null;
|
||||
like_search_qry_str?: string;
|
||||
like_presentation_search_qry_str?: string;
|
||||
like_presenter_search_qry_str?: string;
|
||||
like_poc_name_qry_str?: string;
|
||||
location_name?: null | string;
|
||||
qry_files?: null | boolean;
|
||||
qry_poc_agree?: null | boolean;
|
||||
qry_poc_kv_json?: null | boolean;
|
||||
qry_start_datetime?: string | null;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||
view?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: any;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventSession[]> {
|
||||
const search_query: any = { q: '', and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
||||
const search_query: any = {
|
||||
q: '',
|
||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||
};
|
||||
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
|
||||
const ft: any = {};
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) ft['default_qry_str'] = fulltext_search_qry_str;
|
||||
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2) ft['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
|
||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
||||
ft['default_qry_str'] = fulltext_search_qry_str;
|
||||
if (
|
||||
ft_presenter_search_qry_str &&
|
||||
ft_presenter_search_qry_str.length > 2
|
||||
)
|
||||
ft['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
|
||||
if (Object.keys(ft).length) search_query.params = { ft_qry: ft };
|
||||
}
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
|
||||
if (location_name) {
|
||||
search_query.and.push({ field: 'event_location_name', op: 'eq', value: location_name });
|
||||
search_query.and.push({
|
||||
field: 'event_location_name',
|
||||
op: 'eq',
|
||||
value: location_name
|
||||
});
|
||||
}
|
||||
|
||||
const result_li = await api.search_ae_obj({ api_cfg, obj_type: 'event_session', search_query, order_by_li, view, limit, offset, log_lvl });
|
||||
const result_li = await api.search_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_session',
|
||||
search_query,
|
||||
order_by_li,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
// Handle V3 API envelope
|
||||
let valid_result_li: ae_EventSession[] = [];
|
||||
if (Array.isArray(result_li)) {
|
||||
valid_result_li = result_li;
|
||||
} else if (result_li && typeof result_li === 'object' && Array.isArray((result_li as any).data)) {
|
||||
} else if (
|
||||
result_li &&
|
||||
typeof result_li === 'object' &&
|
||||
Array.isArray((result_li as any).data)
|
||||
) {
|
||||
valid_result_li = (result_li as any).data;
|
||||
}
|
||||
|
||||
if (valid_result_li && valid_result_li.length > 0) {
|
||||
const processed = await process_ae_obj__event_session_props({ obj_li: valid_result_li, log_lvl });
|
||||
const processed = await process_ae_obj__event_session_props({
|
||||
obj_li: valid_result_li,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: processed, properties_to_save, log_lvl });
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'session',
|
||||
obj_li: processed,
|
||||
properties_to_save,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
@@ -429,18 +754,103 @@ export async function search__event_session({
|
||||
|
||||
export const qry__event_session = search__event_session;
|
||||
|
||||
export async function email_sign_in__event_session({ api_cfg, to_email, to_name, base_url, person_id, person_passcode, event_id, event_session_id, session_name }: { api_cfg: any; to_email: string; to_name: string; base_url: string; person_id: string; person_passcode: string; event_id: string; event_session_id: string; session_name: string; }) {
|
||||
export async function email_sign_in__event_session({
|
||||
api_cfg,
|
||||
to_email,
|
||||
to_name,
|
||||
base_url,
|
||||
person_id,
|
||||
person_passcode,
|
||||
event_id,
|
||||
event_session_id,
|
||||
session_name
|
||||
}: {
|
||||
api_cfg: any;
|
||||
to_email: string;
|
||||
to_name: string;
|
||||
base_url: string;
|
||||
person_id: string;
|
||||
person_passcode: string;
|
||||
event_id: string;
|
||||
event_session_id: string;
|
||||
session_name: string;
|
||||
}) {
|
||||
const subject = `Pres Mgmt Hub Sign In Link for ${session_name}`;
|
||||
const sign_in_url = encodeURI(`${base_url}/events/${event_id}/session/${event_session_id}?person_id=${person_id}&person_pass=${person_passcode}`);
|
||||
const sign_in_url = encodeURI(
|
||||
`${base_url}/events/${event_id}/session/${event_session_id}?person_id=${person_id}&person_pass=${person_passcode}`
|
||||
);
|
||||
const body_html = `<div>${to_name},<p>Your sign-in link for ${session_name}: <a href="${sign_in_url}">${sign_in_url}</a></p></div>`;
|
||||
return await api.send_email({ api_cfg, from_email: 'noreply+presmgmt@oneskyit.com', from_name: 'Aether Pres Mgmt', to_email, subject, body_html });
|
||||
return await api.send_email({
|
||||
api_cfg,
|
||||
from_email: 'noreply+presmgmt@oneskyit.com',
|
||||
from_name: 'Aether Pres Mgmt',
|
||||
to_email,
|
||||
subject,
|
||||
body_html
|
||||
});
|
||||
}
|
||||
|
||||
export const properties_to_save = [
|
||||
'id', 'event_session_id', 'event_session_id_random', 'external_id', 'code', 'for_type', 'for_id', 'for_id_random', 'type_code', 'event_id', 'event_location_id', 'poc_person_id', 'poc_agree', 'poc_kv_json', 'name', 'description', 'start_datetime', 'end_datetime', 'passcode', 'hide_event_launcher', 'alert', 'alert_msg', 'data_json', 'ux_mode', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'file_count', 'file_count_all', 'internal_use_count', 'event_file_id_li_json', 'poc_person_given_name', 'poc_person_family_name', 'poc_person_full_name', 'poc_person_primary_email', 'poc_person_passcode', 'event_name', 'event_location_code', 'event_location_name', 'event_presentation_li'
|
||||
'id',
|
||||
'event_session_id',
|
||||
'event_session_id_random',
|
||||
'external_id',
|
||||
'code',
|
||||
'for_type',
|
||||
'for_id',
|
||||
'for_id_random',
|
||||
'type_code',
|
||||
'event_id',
|
||||
'event_location_id',
|
||||
'poc_person_id',
|
||||
'poc_agree',
|
||||
'poc_kv_json',
|
||||
'name',
|
||||
'description',
|
||||
'start_datetime',
|
||||
'end_datetime',
|
||||
'passcode',
|
||||
'hide_event_launcher',
|
||||
'alert',
|
||||
'alert_msg',
|
||||
'data_json',
|
||||
'ux_mode',
|
||||
'enable',
|
||||
'hide',
|
||||
'priority',
|
||||
'sort',
|
||||
'group',
|
||||
'notes',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
'tmp_sort_1',
|
||||
'tmp_sort_2',
|
||||
'file_count',
|
||||
'file_count_all',
|
||||
'internal_use_count',
|
||||
'event_file_id_li_json',
|
||||
'poc_person_given_name',
|
||||
'poc_person_family_name',
|
||||
'poc_person_full_name',
|
||||
'poc_person_primary_email',
|
||||
'poc_person_passcode',
|
||||
'event_name',
|
||||
'event_location_code',
|
||||
'event_location_name',
|
||||
'event_presentation_li'
|
||||
];
|
||||
|
||||
async function _process_generic_props<T extends Record<string, any>>({ obj_li, obj_type, log_lvl = 0, specific_processor }: { obj_li: T[]; obj_type: string; log_lvl?: number; specific_processor?: (obj: T) => Promise<T> | T; }): Promise<T[]> {
|
||||
async function _process_generic_props<T extends Record<string, any>>({
|
||||
obj_li,
|
||||
obj_type,
|
||||
log_lvl = 0,
|
||||
specific_processor
|
||||
}: {
|
||||
obj_li: T[];
|
||||
obj_type: string;
|
||||
log_lvl?: number;
|
||||
specific_processor?: (obj: T) => Promise<T> | T;
|
||||
}): Promise<T[]> {
|
||||
if (!obj_li || obj_li.length === 0) return [];
|
||||
const processed_obj_li: T[] = [];
|
||||
for (const original_obj of obj_li) {
|
||||
@@ -456,22 +866,40 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
||||
if (processed_obj[randomIdKey]) {
|
||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||
(processed_obj as any)[baseIdKey] = processed_obj[randomIdKey];
|
||||
}
|
||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
||||
} else if (processed_obj[baseIdKey])
|
||||
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
if (specific_processor)
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
}
|
||||
return processed_obj_li;
|
||||
}
|
||||
|
||||
export async function process_ae_obj__event_session_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
||||
return _process_generic_props({ obj_li, obj_type: 'event_session', log_lvl });
|
||||
}
|
||||
export async function process_ae_obj__event_session_props({
|
||||
obj_li,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
obj_li: any[];
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
return _process_generic_props({
|
||||
obj_li,
|
||||
obj_type: 'event_session',
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,4 +24,4 @@ export async function load_ae_obj_li__event_track({
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ export const editable_fields__event_exhibit = [
|
||||
'sort',
|
||||
'group',
|
||||
'notes'
|
||||
];
|
||||
];
|
||||
|
||||
@@ -92,11 +92,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
(processed_obj as any).description = '';
|
||||
}
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -137,7 +141,9 @@ export async function load_ae_obj_id__event_exhibit({
|
||||
}): Promise<ae_EventExhibit | null> {
|
||||
const start_time = performance.now();
|
||||
if (log_lvl) {
|
||||
console.log(`🔎 [Trace] load_ae_obj_id__event_exhibit: START (id=${exhibit_id}, try_cache=${try_cache})`);
|
||||
console.log(
|
||||
`🔎 [Trace] load_ae_obj_id__event_exhibit: START (id=${exhibit_id}, try_cache=${try_cache})`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Return cached data immediately
|
||||
@@ -146,34 +152,74 @@ export async function load_ae_obj_id__event_exhibit({
|
||||
const cached = await db_events.exhibit.get(exhibit_id);
|
||||
if (cached) {
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale exhibit shell.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale exhibit shell.`
|
||||
);
|
||||
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_exhibit_id_background({ api_cfg, exhibit_id, view, try_cache, log_lvl: log_lvl > 1 ? log_lvl : 0 });
|
||||
_refresh_exhibit_id_background({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
view,
|
||||
try_cache,
|
||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
});
|
||||
return cached;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_id: Cache access error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] load_ae_obj_id: Cache access error:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_exhibit_id_background({ api_cfg, exhibit_id, view, try_cache, log_lvl });
|
||||
return await _refresh_exhibit_id_background({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
view,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_exhibit_id_background({ api_cfg, exhibit_id, view, try_cache, log_lvl }: any) {
|
||||
async function _refresh_exhibit_id_background({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
view,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
const start_time = performance.now();
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
if (log_lvl) console.log(`📡 [Trace] _refresh_exhibit_id: API Fetching id=${exhibit_id}`);
|
||||
const result = await api.get_ae_obj({ api_cfg, obj_type: 'event_exhibit', obj_id: exhibit_id, view, log_lvl });
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📡 [Trace] _refresh_exhibit_id: API Fetching id=${exhibit_id}`
|
||||
);
|
||||
const result = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_exhibit',
|
||||
obj_id: exhibit_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__exhibit_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
|
||||
if (log_lvl) console.log(`📦 [Trace] _refresh_exhibit_id: Received from API at ${elapsed}ms`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📦 [Trace] _refresh_exhibit_id: Received from API at ${elapsed}ms`
|
||||
);
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -187,7 +233,11 @@ async function _refresh_exhibit_id_background({ api_cfg, exhibit_id, view, try_c
|
||||
return processed_obj;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] _refresh_exhibit_id: API error for id=${exhibit_id}:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] _refresh_exhibit_id: API error for id=${exhibit_id}:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -225,36 +275,82 @@ export async function load_ae_obj_li__event_exhibit({
|
||||
}): Promise<ae_EventExhibit[]> {
|
||||
const start_time = performance.now();
|
||||
if (log_lvl) {
|
||||
console.log(`🔎 [Trace] load_ae_obj_li__event_exhibit: START (event=${event_id}, try_cache=${try_cache})`);
|
||||
console.log(
|
||||
`🔎 [Trace] load_ae_obj_li__event_exhibit: START (event=${event_id}, try_cache=${try_cache})`
|
||||
);
|
||||
}
|
||||
|
||||
if (try_cache) {
|
||||
try {
|
||||
const cached_li = await db_events.exhibit
|
||||
.where('event_id').equals(event_id)
|
||||
.where('event_id')
|
||||
.equals(event_id)
|
||||
.toArray();
|
||||
|
||||
if (cached_li && cached_li.length > 0) {
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`
|
||||
);
|
||||
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_exhibit_li_background({ api_cfg, event_id, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: log_lvl > 1 ? log_lvl : 0 });
|
||||
_refresh_exhibit_li_background({
|
||||
api_cfg,
|
||||
event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
});
|
||||
return cached_li;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_li: Cache access error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] load_ae_obj_li: Cache access error:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await _refresh_exhibit_li_background({ api_cfg, event_id, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl });
|
||||
return await _refresh_exhibit_li_background({
|
||||
api_cfg,
|
||||
event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_exhibit_li_background({ api_cfg, event_id, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
||||
async function _refresh_exhibit_li_background({
|
||||
api_cfg,
|
||||
event_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
const start_time = performance.now();
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
if (log_lvl) console.log(`📡 [Trace] _refresh_exhibit_li: API Fetching exhibits for event=${event_id}`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📡 [Trace] _refresh_exhibit_li: API Fetching exhibits for event=${event_id}`
|
||||
);
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_exhibit',
|
||||
@@ -270,9 +366,15 @@ async function _refresh_exhibit_li_background({ api_cfg, event_id, enabled, hidd
|
||||
});
|
||||
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__exhibit_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__exhibit_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`📦 [Trace] _refresh_exhibit_li: Received ${processed.length} items from API at ${elapsed}ms.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📦 [Trace] _refresh_exhibit_li: Received ${processed.length} items from API at ${elapsed}ms.`
|
||||
);
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -286,7 +388,8 @@ async function _refresh_exhibit_li_background({ api_cfg, event_id, enabled, hidd
|
||||
return processed;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] _refresh_exhibit_li: API error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(`❌ [Trace] _refresh_exhibit_li: API error:`, e);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -295,87 +398,93 @@ async function _refresh_exhibit_li_background({ api_cfg, event_id, enabled, hidd
|
||||
* Exhibit Create (V3)
|
||||
*/
|
||||
export async function create_ae_obj__exhibit({
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibit | null> {
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event',
|
||||
parent_id: event_id,
|
||||
child_type: 'event_exhibit',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event',
|
||||
parent_id: event_id,
|
||||
child_type: 'event_exhibit',
|
||||
fields: { ...data_kv },
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exhibit Update (V3)
|
||||
*/
|
||||
export async function update_ae_obj__exhibit({
|
||||
api_cfg,
|
||||
event_id,
|
||||
exhibit_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
event_id,
|
||||
exhibit_id,
|
||||
data_kv,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
exhibit_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
event_id: string;
|
||||
exhibit_id: string;
|
||||
data_kv: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibit | null> {
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event',
|
||||
parent_id: event_id,
|
||||
child_type: 'event_exhibit',
|
||||
child_id: exhibit_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event',
|
||||
parent_id: event_id,
|
||||
child_type: 'event_exhibit',
|
||||
child_id: exhibit_id,
|
||||
fields: data_kv,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,24 +518,30 @@ export async function search__exhibit({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibit[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__exhibit() *** event_id=${event_id} ft=${fulltext_search_qry_str}`);
|
||||
console.log(
|
||||
`*** search__exhibit() *** event_id=${event_id} ft=${fulltext_search_qry_str}`
|
||||
);
|
||||
}
|
||||
|
||||
const search_query: any = {
|
||||
q: fulltext_search_qry_str || '',
|
||||
and: [
|
||||
{ field: 'event_id', op: 'eq', value: event_id }
|
||||
]
|
||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||
};
|
||||
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
|
||||
if (priority === 'priority') search_query.and.push({ field: 'priority', op: 'eq', value: 1 });
|
||||
else if (priority === 'not_priority') search_query.and.push({ field: 'priority', op: 'eq', value: 0 });
|
||||
if (priority === 'priority')
|
||||
search_query.and.push({ field: 'priority', op: 'eq', value: 1 });
|
||||
else if (priority === 'not_priority')
|
||||
search_query.and.push({ field: 'priority', op: 'eq', value: 0 });
|
||||
|
||||
try {
|
||||
const result_li = await api.search_ae_obj({
|
||||
@@ -443,7 +558,10 @@ export async function search__exhibit({
|
||||
});
|
||||
|
||||
if (result_li && Array.isArray(result_li)) {
|
||||
const processed = await process_ae_obj__exhibit_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__exhibit_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
@@ -460,4 +578,4 @@ export async function search__exhibit({
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,11 +106,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
(processed_obj as any).exhibitor_notes = '';
|
||||
}
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -151,43 +155,86 @@ export async function load_ae_obj_id__event_exhibit_tracking({
|
||||
}): Promise<ae_EventExhibitTracking | null> {
|
||||
const start_time = performance.now();
|
||||
if (log_lvl) {
|
||||
console.log(`🔎 [Trace] load_ae_obj_id__event_exhibit_tracking: START (id=${exhibit_tracking_id}, try_cache=${try_cache})`);
|
||||
console.log(
|
||||
`🔎 [Trace] load_ae_obj_id__event_exhibit_tracking: START (id=${exhibit_tracking_id}, try_cache=${try_cache})`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Return cached data immediately
|
||||
if (try_cache) {
|
||||
try {
|
||||
const cached = await db_events.exhibit_tracking.get(exhibit_tracking_id);
|
||||
const cached =
|
||||
await db_events.exhibit_tracking.get(exhibit_tracking_id);
|
||||
if (cached) {
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale lead shell.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale lead shell.`
|
||||
);
|
||||
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_tracking_id_background({ api_cfg, exhibit_tracking_id, view, try_cache, log_lvl: log_lvl > 1 ? log_lvl : 0 });
|
||||
_refresh_tracking_id_background({
|
||||
api_cfg,
|
||||
exhibit_tracking_id,
|
||||
view,
|
||||
try_cache,
|
||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
});
|
||||
return cached;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_id: Cache access error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] load_ae_obj_id: Cache access error:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_tracking_id_background({ api_cfg, exhibit_tracking_id, view, try_cache, log_lvl });
|
||||
return await _refresh_tracking_id_background({
|
||||
api_cfg,
|
||||
exhibit_tracking_id,
|
||||
view,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_tracking_id_background({ api_cfg, exhibit_tracking_id, view, try_cache, log_lvl }: any) {
|
||||
async function _refresh_tracking_id_background({
|
||||
api_cfg,
|
||||
exhibit_tracking_id,
|
||||
view,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
const start_time = performance.now();
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
if (log_lvl) console.log(`📡 [Trace] _refresh_tracking_id: API Fetching id=${exhibit_tracking_id}`);
|
||||
const result = await api.get_ae_obj({ api_cfg, obj_type: 'event_exhibit_tracking', obj_id: exhibit_tracking_id, view, log_lvl });
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📡 [Trace] _refresh_tracking_id: API Fetching id=${exhibit_tracking_id}`
|
||||
);
|
||||
const result = await api.get_ae_obj({
|
||||
api_cfg,
|
||||
obj_type: 'event_exhibit_tracking',
|
||||
obj_id: exhibit_tracking_id,
|
||||
view,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({ obj_li: [result], log_lvl });
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
|
||||
if (log_lvl) console.log(`📦 [Trace] _refresh_tracking_id: Received from API at ${elapsed}ms`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📦 [Trace] _refresh_tracking_id: Received from API at ${elapsed}ms`
|
||||
);
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -201,7 +248,11 @@ async function _refresh_tracking_id_background({ api_cfg, exhibit_tracking_id, v
|
||||
return processed_obj;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] _refresh_tracking_id: API error for id=${exhibit_tracking_id}:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] _refresh_tracking_id: API error for id=${exhibit_tracking_id}:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -238,36 +289,82 @@ export async function load_ae_obj_li__event_exhibit_tracking({
|
||||
}): Promise<ae_EventExhibitTracking[]> {
|
||||
const start_time = performance.now();
|
||||
if (log_lvl) {
|
||||
console.log(`🔎 [Trace] load_ae_obj_li__event_exhibit_tracking: START (exhibit=${exhibit_id}, try_cache=${try_cache})`);
|
||||
console.log(
|
||||
`🔎 [Trace] load_ae_obj_li__event_exhibit_tracking: START (exhibit=${exhibit_id}, try_cache=${try_cache})`
|
||||
);
|
||||
}
|
||||
|
||||
if (try_cache) {
|
||||
try {
|
||||
const cached_li = await db_events.exhibit_tracking
|
||||
.where('event_exhibit_id').equals(exhibit_id)
|
||||
.where('event_exhibit_id')
|
||||
.equals(exhibit_id)
|
||||
.toArray();
|
||||
|
||||
if (cached_li && cached_li.length > 0) {
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`
|
||||
);
|
||||
|
||||
// Background refresh (non-blocking)
|
||||
_refresh_tracking_li_background({ api_cfg, exhibit_id, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: log_lvl > 1 ? log_lvl : 0 });
|
||||
_refresh_tracking_li_background({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||
});
|
||||
return cached_li;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_li: Cache access error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(
|
||||
`❌ [Trace] load_ae_obj_li: Cache access error:`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await _refresh_tracking_li_background({ api_cfg, exhibit_id, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl });
|
||||
return await _refresh_tracking_li_background({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_tracking_li_background({ api_cfg, exhibit_id, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
||||
async function _refresh_tracking_li_background({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
enabled,
|
||||
hidden,
|
||||
view,
|
||||
limit,
|
||||
offset,
|
||||
order_by_li,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
const start_time = performance.now();
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||
try {
|
||||
if (log_lvl) console.log(`📡 [Trace] _refresh_tracking_li: API Fetching leads for exhibit=${exhibit_id}`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📡 [Trace] _refresh_tracking_li: API Fetching leads for exhibit=${exhibit_id}`
|
||||
);
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
api_cfg,
|
||||
obj_type: 'event_exhibit_tracking',
|
||||
@@ -283,9 +380,15 @@ async function _refresh_tracking_li_background({ api_cfg, exhibit_id, enabled, h
|
||||
});
|
||||
|
||||
if (result_li) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||
if (log_lvl) console.log(`📦 [Trace] _refresh_tracking_li: Received ${processed.length} items from API at ${elapsed}ms.`);
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`📦 [Trace] _refresh_tracking_li: Received ${processed.length} items from API at ${elapsed}ms.`
|
||||
);
|
||||
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -299,7 +402,8 @@ async function _refresh_tracking_li_background({ api_cfg, exhibit_id, enabled, h
|
||||
return processed;
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.error(`❌ [Trace] _refresh_tracking_li: API error:`, e);
|
||||
if (log_lvl)
|
||||
console.error(`❌ [Trace] _refresh_tracking_li: API error:`, e);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -308,95 +412,101 @@ async function _refresh_tracking_li_background({ api_cfg, exhibit_id, enabled, h
|
||||
* Lead Capture (V3)
|
||||
*/
|
||||
export async function create_ae_obj__exhibit_tracking({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
event_badge_id,
|
||||
external_person_id,
|
||||
group,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
event_badge_id,
|
||||
external_person_id,
|
||||
group,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
exhibit_id: string;
|
||||
event_badge_id: string;
|
||||
external_person_id: string;
|
||||
group?: string;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
exhibit_id: string;
|
||||
event_badge_id: string;
|
||||
external_person_id: string;
|
||||
group?: string;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibitTracking | null> {
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event_exhibit',
|
||||
parent_id: exhibit_id,
|
||||
child_type: 'event_exhibit_tracking',
|
||||
fields: {
|
||||
event_badge_id: event_badge_id,
|
||||
external_person_id,
|
||||
group
|
||||
},
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.create_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event_exhibit',
|
||||
parent_id: exhibit_id,
|
||||
child_type: 'event_exhibit_tracking',
|
||||
fields: {
|
||||
event_badge_id: event_badge_id,
|
||||
external_person_id,
|
||||
group
|
||||
},
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit_tracking',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit_tracking,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit_tracking',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit_tracking,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lead Update (V3)
|
||||
*/
|
||||
export async function update_ae_obj__exhibit_tracking({
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
exhibit_tracking_id,
|
||||
data,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
exhibit_id,
|
||||
exhibit_tracking_id,
|
||||
data,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
exhibit_id: string;
|
||||
exhibit_tracking_id: string;
|
||||
data: any;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
exhibit_id: string;
|
||||
exhibit_tracking_id: string;
|
||||
data: any;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibitTracking | null> {
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event_exhibit',
|
||||
parent_id: exhibit_id,
|
||||
child_type: 'event_exhibit_tracking',
|
||||
child_id: exhibit_tracking_id,
|
||||
fields: data,
|
||||
log_lvl
|
||||
});
|
||||
const result = await api.update_nested_obj({
|
||||
api_cfg,
|
||||
parent_type: 'event_exhibit',
|
||||
parent_id: exhibit_id,
|
||||
child_type: 'event_exhibit_tracking',
|
||||
child_id: exhibit_tracking_id,
|
||||
fields: data,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit_tracking',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit_tracking,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
if (result) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
const processed_obj = processed[0];
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
table_name: 'exhibit_tracking',
|
||||
obj_li: [processed_obj],
|
||||
properties_to_save: properties_to_save_exhibit_tracking,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
return processed_obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,13 +538,15 @@ export async function download_export__event_exhibit_tracking({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** download_export__event_exhibit_tracking() *** exhibit_id=${exhibit_id}`);
|
||||
console.log(
|
||||
`*** download_export__event_exhibit_tracking() *** exhibit_id=${exhibit_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const endpoint = `/v3/action/event_exhibit/${exhibit_id}/tracking_export`;
|
||||
const params: key_val = {
|
||||
file_type,
|
||||
return_file: 'true' // V3 convention: string 'true' for bool query flags
|
||||
return_file: 'true' // V3 convention: string 'true' for bool query flags
|
||||
};
|
||||
|
||||
return await api.get_object({
|
||||
@@ -485,7 +597,9 @@ export async function search__exhibit_tracking({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_EventExhibitTracking[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** search__exhibit_tracking() *** exhibit_id=${event_exhibit_id} ft=${fulltext_search_qry_str}`);
|
||||
console.log(
|
||||
`*** search__exhibit_tracking() *** exhibit_id=${event_exhibit_id} ft=${fulltext_search_qry_str}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!event_id || !event_exhibit_id) return [];
|
||||
@@ -498,15 +612,30 @@ export async function search__exhibit_tracking({
|
||||
]
|
||||
};
|
||||
|
||||
if (qry_group) search_query.and.push({ field: 'group', op: 'eq', value: qry_group });
|
||||
if (qry_external_person_id) search_query.and.push({ field: 'external_person_id', op: 'eq', value: qry_external_person_id });
|
||||
if (qry_badge_id) search_query.and.push({ field: 'event_badge_id', op: 'eq', value: qry_badge_id });
|
||||
if (qry_group)
|
||||
search_query.and.push({ field: 'group', op: 'eq', value: qry_group });
|
||||
if (qry_external_person_id)
|
||||
search_query.and.push({
|
||||
field: 'external_person_id',
|
||||
op: 'eq',
|
||||
value: qry_external_person_id
|
||||
});
|
||||
if (qry_badge_id)
|
||||
search_query.and.push({
|
||||
field: 'event_badge_id',
|
||||
op: 'eq',
|
||||
value: qry_badge_id
|
||||
});
|
||||
|
||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
if (enabled === 'enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||
else if (enabled === 'not_enabled')
|
||||
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||
|
||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
if (hidden === 'hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||
else if (hidden === 'not_hidden')
|
||||
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||
|
||||
try {
|
||||
const result_li = await api.search_ae_obj({
|
||||
@@ -525,7 +654,10 @@ export async function search__exhibit_tracking({
|
||||
});
|
||||
|
||||
if (result_li && Array.isArray(result_li)) {
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({ obj_li: result_li, log_lvl });
|
||||
const processed = await process_ae_obj__exhibit_tracking_props({
|
||||
obj_li: result_li,
|
||||
log_lvl
|
||||
});
|
||||
if (try_cache) {
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_events,
|
||||
@@ -542,4 +674,4 @@ export async function search__exhibit_tracking({
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +56,18 @@ const export_obj = {
|
||||
search__event_badge: event_badge.search__event_badge,
|
||||
|
||||
// Event Badge Templates
|
||||
load_ae_obj_id__event_badge_template: event_badge_template.load_ae_obj_id__event_badge_template,
|
||||
load_ae_obj_li__event_badge_template: event_badge_template.load_ae_obj_li__event_badge_template,
|
||||
create_ae_obj__event_badge_template: event_badge_template.create_ae_obj__event_badge_template,
|
||||
load_ae_obj_id__event_badge_template:
|
||||
event_badge_template.load_ae_obj_id__event_badge_template,
|
||||
load_ae_obj_li__event_badge_template:
|
||||
event_badge_template.load_ae_obj_li__event_badge_template,
|
||||
create_ae_obj__event_badge_template:
|
||||
event_badge_template.create_ae_obj__event_badge_template,
|
||||
delete_ae_obj_id__event_badge_template:
|
||||
event_badge_template.delete_ae_obj_id__event_badge_template,
|
||||
update_ae_obj__event_badge_template: event_badge_template.update_ae_obj__event_badge_template,
|
||||
search__event_badge_template: event_badge_template.search__event_badge_template,
|
||||
update_ae_obj__event_badge_template:
|
||||
event_badge_template.update_ae_obj__event_badge_template,
|
||||
search__event_badge_template:
|
||||
event_badge_template.search__event_badge_template,
|
||||
|
||||
// Event Devices
|
||||
load_ae_obj_id__event_device: event_device.load_ae_obj_id__event_device,
|
||||
@@ -77,53 +82,72 @@ const export_obj = {
|
||||
search__exhibit: search__exhibit,
|
||||
create_ae_obj__exhibit: create_ae_obj__exhibit,
|
||||
update_ae_obj__exhibit: update_ae_obj__exhibit,
|
||||
load_ae_obj_id__event_exhibit_tracking: load_ae_obj_id__event_exhibit_tracking,
|
||||
load_ae_obj_li__event_exhibit_tracking: load_ae_obj_li__event_exhibit_tracking,
|
||||
load_ae_obj_id__event_exhibit_tracking:
|
||||
load_ae_obj_id__event_exhibit_tracking,
|
||||
load_ae_obj_li__event_exhibit_tracking:
|
||||
load_ae_obj_li__event_exhibit_tracking,
|
||||
search__exhibit_tracking: search__exhibit_tracking,
|
||||
create_ae_obj__exhibit_tracking: create_ae_obj__exhibit_tracking,
|
||||
update_ae_obj__exhibit_tracking: update_ae_obj__exhibit_tracking,
|
||||
download_export__event_exhibit_tracking: download_export__event_exhibit_tracking,
|
||||
download_export__event_exhibit_tracking:
|
||||
download_export__event_exhibit_tracking,
|
||||
|
||||
// Event Files
|
||||
load_ae_obj_id__event_file: event_file.load_ae_obj_id__event_file,
|
||||
load_ae_obj_li__event_file: event_file.load_ae_obj_li__event_file,
|
||||
create_event_file_obj_from_hosted_file_async: event_file.create_event_file_obj_from_hosted_file_async,
|
||||
create_event_file_obj_from_hosted_file_async:
|
||||
event_file.create_event_file_obj_from_hosted_file_async,
|
||||
delete_ae_obj_id__event_file: event_file.delete_ae_obj_id__event_file,
|
||||
update_ae_obj__event_file: event_file.update_ae_obj__event_file,
|
||||
qry__event_file: event_file.qry__event_file,
|
||||
search__event_file: event_file.search__event_file,
|
||||
|
||||
// Event Locations
|
||||
load_ae_obj_id__event_location: event_location.load_ae_obj_id__event_location,
|
||||
load_ae_obj_li__event_location: event_location.load_ae_obj_li__event_location,
|
||||
load_ae_obj_id__event_location:
|
||||
event_location.load_ae_obj_id__event_location,
|
||||
load_ae_obj_li__event_location:
|
||||
event_location.load_ae_obj_li__event_location,
|
||||
create_ae_obj__event_location: event_location.create_ae_obj__event_location,
|
||||
delete_ae_obj_id__event_location: event_location.delete_ae_obj_id__event_location,
|
||||
delete_ae_obj_id__event_location:
|
||||
event_location.delete_ae_obj_id__event_location,
|
||||
update_ae_obj__event_location: event_location.update_ae_obj__event_location,
|
||||
|
||||
// Event Sessions
|
||||
load_ae_obj_id__event_session: event_session.load_ae_obj_id__event_session,
|
||||
load_ae_obj_li__event_session: event_session.load_ae_obj_li__event_session,
|
||||
create_ae_obj__event_session: event_session.create_ae_obj__event_session,
|
||||
delete_ae_obj_id__event_session: event_session.delete_ae_obj_id__event_session,
|
||||
delete_ae_obj_id__event_session:
|
||||
event_session.delete_ae_obj_id__event_session,
|
||||
update_ae_obj__event_session: event_session.update_ae_obj__event_session,
|
||||
qry__event_session: event_session.qry__event_session,
|
||||
search__event_session: event_session.search__event_session,
|
||||
email_sign_in__event_session: event_session.email_sign_in__event_session,
|
||||
|
||||
// Event Presentations
|
||||
load_ae_obj_id__event_presentation: event_presentation.load_ae_obj_id__event_presentation,
|
||||
load_ae_obj_li__event_presentation: event_presentation.load_ae_obj_li__event_presentation,
|
||||
create_ae_obj__event_presentation: event_presentation.create_ae_obj__event_presentation,
|
||||
delete_ae_obj_id__event_presentation: event_presentation.delete_ae_obj_id__event_presentation,
|
||||
update_ae_obj__event_presentation: event_presentation.update_ae_obj__event_presentation,
|
||||
load_ae_obj_id__event_presentation:
|
||||
event_presentation.load_ae_obj_id__event_presentation,
|
||||
load_ae_obj_li__event_presentation:
|
||||
event_presentation.load_ae_obj_li__event_presentation,
|
||||
create_ae_obj__event_presentation:
|
||||
event_presentation.create_ae_obj__event_presentation,
|
||||
delete_ae_obj_id__event_presentation:
|
||||
event_presentation.delete_ae_obj_id__event_presentation,
|
||||
update_ae_obj__event_presentation:
|
||||
event_presentation.update_ae_obj__event_presentation,
|
||||
|
||||
// Event Presenters
|
||||
load_ae_obj_id__event_presenter: event_presenter.load_ae_obj_id__event_presenter,
|
||||
load_ae_obj_li__event_presenter: event_presenter.load_ae_obj_li__event_presenter,
|
||||
create_ae_obj__event_presenter: event_presenter.create_ae_obj__event_presenter,
|
||||
delete_ae_obj_id__event_presenter: event_presenter.delete_ae_obj_id__event_presenter,
|
||||
update_ae_obj__event_presenter: event_presenter.update_ae_obj__event_presenter,
|
||||
load_ae_obj_id__event_presenter:
|
||||
event_presenter.load_ae_obj_id__event_presenter,
|
||||
load_ae_obj_li__event_presenter:
|
||||
event_presenter.load_ae_obj_li__event_presenter,
|
||||
create_ae_obj__event_presenter:
|
||||
event_presenter.create_ae_obj__event_presenter,
|
||||
delete_ae_obj_id__event_presenter:
|
||||
event_presenter.delete_ae_obj_id__event_presenter,
|
||||
update_ae_obj__event_presenter:
|
||||
event_presenter.update_ae_obj__event_presenter,
|
||||
search__event_presenter: event_presenter.search__event_presenter,
|
||||
email_sign_in__event_presenter: event_presenter.email_sign_in__event_presenter
|
||||
email_sign_in__event_presenter:
|
||||
event_presenter.email_sign_in__event_presenter
|
||||
};
|
||||
export const events_func = export_obj;
|
||||
export const events_func = export_obj;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
/* --- Badge front --- */
|
||||
|
||||
[data-layout="badge_4x5_fanfold"] .badge_front {
|
||||
[data-layout='badge_4x5_fanfold'] .badge_front {
|
||||
width: 4in;
|
||||
min-height: 5in;
|
||||
max-height: 5in;
|
||||
@@ -28,18 +28,18 @@
|
||||
}
|
||||
|
||||
/* Body area: 5in total − ~1in header − ~0.5in footer = ~3.5in for content */
|
||||
[data-layout="badge_4x5_fanfold"] .badge_body {
|
||||
[data-layout='badge_4x5_fanfold'] .badge_body {
|
||||
max-height: 3.5in;
|
||||
}
|
||||
|
||||
/* --- Badge back --- */
|
||||
|
||||
[data-layout="badge_4x5_fanfold"] .badge_back {
|
||||
[data-layout='badge_4x5_fanfold'] .badge_back {
|
||||
width: 4in;
|
||||
min-height: 5in;
|
||||
max-height: 5in;
|
||||
}
|
||||
|
||||
[data-layout="badge_4x5_fanfold"] .badge_back_content {
|
||||
[data-layout='badge_4x5_fanfold'] .badge_back_content {
|
||||
max-height: 4.5in;
|
||||
}
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
|
||||
/* --- Badge front --- */
|
||||
|
||||
[data-layout="badge_3.5x5.5_pvc"] .badge_front {
|
||||
[data-layout='badge_3.5x5.5_pvc'] .badge_front {
|
||||
width: 3.5in;
|
||||
min-height: 5.5in;
|
||||
max-height: 5.5in;
|
||||
|
||||
/* debug */
|
||||
/* outline: thick solid orange; */
|
||||
/* debug */
|
||||
/* outline: thick solid orange; */
|
||||
}
|
||||
|
||||
/* Outer wrapper: remove the generic 4×6 fanfold defaults so the blue dashed
|
||||
outline hugs the card tightly. The badge_front CSS above supplies the exact
|
||||
3.5×5.5in size; wrapper just needs to fit it with no extra space. */
|
||||
[data-layout="badge_3.5x5.5_pvc"].event_badge_wrapper {
|
||||
[data-layout='badge_3.5x5.5_pvc'].event_badge_wrapper {
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
min-height: 0;
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
|
||||
@media print {
|
||||
[data-layout="badge_3.5x5.5_pvc"].event_badge_wrapper {
|
||||
[data-layout='badge_3.5x5.5_pvc'].event_badge_wrapper {
|
||||
width: 3.5in !important;
|
||||
height: 5.5in !important;
|
||||
max-width: 3.5in !important;
|
||||
|
||||
@@ -829,7 +829,7 @@ export class MySubClassedDexie extends Dexie {
|
||||
constructor() {
|
||||
super('ae_events_db');
|
||||
this.version(6).stores({
|
||||
// NO LONGER USE "_random"
|
||||
// NO LONGER USE "_random"
|
||||
event: `
|
||||
id, event_id, event_id_random,
|
||||
code,
|
||||
|
||||
@@ -817,7 +817,10 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
@@ -862,7 +865,8 @@ export async function process_ae_obj__journal_props({
|
||||
obj.cfg_json = obj.cfg_json ?? {};
|
||||
obj.data_json = obj.data_json ?? {};
|
||||
|
||||
const updated = obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
obj.tmp_sort_3 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${
|
||||
obj.name
|
||||
}_${updated}`;
|
||||
|
||||
@@ -942,7 +942,10 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
@@ -1026,7 +1029,8 @@ export async function process_ae_obj__journal_entry_props({
|
||||
|
||||
// Journal entry-specific computed sort fields, overriding generic ones if needed
|
||||
const sort_val = (obj.sort ?? 0).toString().padStart(3, '0');
|
||||
const updated = obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
|
||||
sort_val
|
||||
}_${updated}`;
|
||||
|
||||
@@ -74,18 +74,19 @@ export async function load_ae_obj_id__post({
|
||||
});
|
||||
|
||||
if (inc_comment_li && ae_promises.load__post_obj) {
|
||||
ae_promises.load__post_obj.post_comment_li = await load_ae_obj_li__post_comment({
|
||||
api_cfg: api_cfg,
|
||||
for_obj_type: 'post',
|
||||
for_obj_id: post_id,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
params,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
ae_promises.load__post_obj.post_comment_li =
|
||||
await load_ae_obj_li__post_comment({
|
||||
api_cfg: api_cfg,
|
||||
for_obj_type: 'post',
|
||||
for_obj_id: post_id,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
params,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
return ae_promises.load__post_obj;
|
||||
@@ -151,7 +152,8 @@ 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,
|
||||
account_id:
|
||||
for_obj_type === 'account' ? for_obj_id : undefined,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
@@ -171,18 +173,19 @@ export async function load_ae_obj_li__post({
|
||||
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,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
params,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
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,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
params,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +294,10 @@ export async function update_ae_obj__post({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Post | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__post() *** post_id=${post_id}`, data_kv);
|
||||
console.log(
|
||||
`*** update_ae_obj__post() *** post_id=${post_id}`,
|
||||
data_kv
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.update_ae_obj({
|
||||
@@ -358,7 +364,11 @@ export async function qry__post({
|
||||
const search_query: any = { and: [] };
|
||||
|
||||
if (account_id) {
|
||||
search_query.and.push({ field: 'account_id', op: 'eq', value: account_id });
|
||||
search_query.and.push({
|
||||
field: 'account_id',
|
||||
op: 'eq',
|
||||
value: account_id
|
||||
});
|
||||
}
|
||||
|
||||
if (qry_str) {
|
||||
@@ -366,7 +376,11 @@ export async function qry__post({
|
||||
}
|
||||
|
||||
if (qry_person_id) {
|
||||
search_query.and.push({ field: 'external_person_id', op: 'eq', value: qry_person_id });
|
||||
search_query.and.push({
|
||||
field: 'external_person_id',
|
||||
op: 'eq',
|
||||
value: qry_person_id
|
||||
});
|
||||
}
|
||||
|
||||
// if (qry_archive_on) {
|
||||
@@ -428,18 +442,19 @@ export async function qry__post({
|
||||
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,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
// params,
|
||||
try_cache: true, // Always cache comments if we are caching posts
|
||||
log_lvl
|
||||
});
|
||||
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,
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
offset,
|
||||
// params,
|
||||
try_cache: true, // Always cache comments if we are caching posts
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,14 +527,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.username ?? processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -549,7 +571,8 @@ export async function process_ae_obj__post_props({
|
||||
}
|
||||
obj.name = obj.title;
|
||||
const sort_val = (obj.sort ?? 0).toString().padStart(3, '0');
|
||||
const updated = obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
|
||||
sort_val
|
||||
}_${updated}`;
|
||||
@@ -560,4 +583,4 @@ export async function process_ae_obj__post_props({
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ export async function load_ae_obj_id__post_comment({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_PostComment | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__post_comment() *** post_comment_id=${post_comment_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__post_comment() *** post_comment_id=${post_comment_id}`
|
||||
);
|
||||
}
|
||||
|
||||
ae_promises.load__post_comment_obj = await api
|
||||
@@ -39,10 +41,11 @@ export async function load_ae_obj_id__post_comment({
|
||||
.then(async function (post_comment_obj_get_result) {
|
||||
if (post_comment_obj_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__post_comment_props({
|
||||
obj_li: [post_comment_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__post_comment_props({
|
||||
obj_li: [post_comment_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_posts,
|
||||
table_name: 'comment',
|
||||
@@ -121,10 +124,11 @@ export async function load_ae_obj_li__post_comment({
|
||||
.then(async function (post_comment_obj_li_get_result) {
|
||||
if (post_comment_obj_li_get_result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__post_comment_props({
|
||||
obj_li: post_comment_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__post_comment_props({
|
||||
obj_li: post_comment_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_posts,
|
||||
table_name: 'comment',
|
||||
@@ -161,7 +165,9 @@ export async function create_ae_obj__post_comment({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_PostComment | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** create_ae_obj__post_comment() *** account_id=${account_id} post_id=${post_id}`);
|
||||
console.log(
|
||||
`*** create_ae_obj__post_comment() *** account_id=${account_id} post_id=${post_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.create_nested_obj({
|
||||
@@ -212,7 +218,9 @@ export async function delete_ae_obj_id__post_comment({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__post_comment() *** post_comment_id=${post_comment_id}`);
|
||||
console.log(
|
||||
`*** delete_ae_obj_id__post_comment() *** post_comment_id=${post_comment_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.delete_ae_obj({
|
||||
@@ -248,7 +256,10 @@ export async function update_ae_obj__post_comment({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_PostComment | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__post_comment() *** post_comment_id=${post_comment_id}`, data_kv);
|
||||
console.log(
|
||||
`*** update_ae_obj__post_comment() *** post_comment_id=${post_comment_id}`,
|
||||
data_kv
|
||||
);
|
||||
}
|
||||
|
||||
const result = await api.update_ae_obj({
|
||||
@@ -336,14 +347,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
processed_obj.updated_on ??
|
||||
processed_obj.created_on ??
|
||||
new Date(0).toISOString();
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -366,7 +384,8 @@ export async function process_ae_obj__post_comment_props({
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
const sort_val = (obj.sort ?? 0).toString().padStart(3, '0');
|
||||
const updated = obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
const updated =
|
||||
obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
|
||||
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
|
||||
sort_val
|
||||
}_${updated}`;
|
||||
@@ -377,4 +396,4 @@ export async function process_ae_obj__post_comment_props({
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
import { process_ae_obj__activity_log_props, properties_to_save } from '$lib/ae_core/ae_core__activity_log';
|
||||
import {
|
||||
process_ae_obj__activity_log_props,
|
||||
properties_to_save
|
||||
} from '$lib/ae_core/ae_core__activity_log';
|
||||
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
|
||||
@@ -17,129 +20,144 @@ import { db_core } from '$lib/ae_core/db_core';
|
||||
* @returns A structured array of meeting report objects.
|
||||
*/
|
||||
export async function qry__jitsi_report({
|
||||
api_cfg,
|
||||
account_id,
|
||||
enabled = 'all',
|
||||
hidden = 'all',
|
||||
limit = 500,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
api_cfg,
|
||||
account_id,
|
||||
enabled = 'all',
|
||||
hidden = 'all',
|
||||
limit = 500,
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
limit?: number;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
|
||||
limit?: number;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) console.log('*** qry__jitsi_report() ***');
|
||||
if (log_lvl) console.log('*** qry__jitsi_report() ***');
|
||||
|
||||
// Step 1: Query all relevant activity logs from the API.
|
||||
const search_query = {
|
||||
or: [
|
||||
{ field: 'name', op: 'eq', value: 'jitsi_meeting_event' },
|
||||
{ field: 'name', op: 'eq', value: 'jitsi_meeting_stats' }
|
||||
],
|
||||
and: [
|
||||
{ field: 'account_id_random', op: 'eq', value: account_id }
|
||||
]
|
||||
};
|
||||
// Step 1: Query all relevant activity logs from the API.
|
||||
const search_query = {
|
||||
or: [
|
||||
{ field: 'name', op: 'eq', value: 'jitsi_meeting_event' },
|
||||
{ field: 'name', op: 'eq', value: 'jitsi_meeting_stats' }
|
||||
],
|
||||
and: [{ field: 'account_id_random', op: 'eq', value: account_id }]
|
||||
};
|
||||
|
||||
const result = await api.search_ae_obj({
|
||||
api_cfg: api_cfg,
|
||||
obj_type: 'activity_log',
|
||||
search_query,
|
||||
headers: { 'x-account-id': account_id },
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
const result = await api.search_ae_obj({
|
||||
api_cfg: api_cfg,
|
||||
obj_type: 'activity_log',
|
||||
search_query,
|
||||
headers: { 'x-account-id': account_id },
|
||||
enabled,
|
||||
hidden,
|
||||
limit,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
// Handle potential V3 API envelope
|
||||
let flat_log_list: any[] = [];
|
||||
if (Array.isArray(result)) {
|
||||
flat_log_list = result;
|
||||
} else if (result && typeof result === 'object' && Array.isArray((result as any).data)) {
|
||||
flat_log_list = (result as any).data;
|
||||
}
|
||||
// Handle potential V3 API envelope
|
||||
let flat_log_list: any[] = [];
|
||||
if (Array.isArray(result)) {
|
||||
flat_log_list = result;
|
||||
} else if (
|
||||
result &&
|
||||
typeof result === 'object' &&
|
||||
Array.isArray((result as any).data)
|
||||
) {
|
||||
flat_log_list = (result as any).data;
|
||||
}
|
||||
|
||||
if (!flat_log_list || !Array.isArray(flat_log_list) || flat_log_list.length === 0) {
|
||||
if (log_lvl) console.log('No Jitsi activity logs found or error occurred.');
|
||||
return [];
|
||||
}
|
||||
if (
|
||||
!flat_log_list ||
|
||||
!Array.isArray(flat_log_list) ||
|
||||
flat_log_list.length === 0
|
||||
) {
|
||||
if (log_lvl)
|
||||
console.log('No Jitsi activity logs found or error occurred.');
|
||||
return [];
|
||||
}
|
||||
|
||||
// Frontier Standard: Process and Save to local cache
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__activity_log_props({
|
||||
obj_li: flat_log_list,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'activity_log',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
}
|
||||
// Frontier Standard: Process and Save to local cache
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__activity_log_props({
|
||||
obj_li: flat_log_list,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'activity_log',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
// Step 2: Process the flat list into a structured report.
|
||||
const meetings = new Map<string, any>();
|
||||
// Step 2: Process the flat list into a structured report.
|
||||
const meetings = new Map<string, any>();
|
||||
|
||||
for (const log of flat_log_list) {
|
||||
const meeting_id = log.external_client_id;
|
||||
if (!meeting_id) continue;
|
||||
for (const log of flat_log_list) {
|
||||
const meeting_id = log.external_client_id;
|
||||
if (!meeting_id) continue;
|
||||
|
||||
// Make sure the name field is prefixed with "jitsi_"
|
||||
if (!log.name.startsWith('jitsi_')) continue;
|
||||
// Make sure the name field is prefixed with "jitsi_"
|
||||
if (!log.name.startsWith('jitsi_')) continue;
|
||||
|
||||
// Ensure a base entry for the meeting exists
|
||||
if (!meetings.has(meeting_id)) {
|
||||
meetings.set(meeting_id, {
|
||||
meeting_id: meeting_id,
|
||||
room_name: 'Unknown',
|
||||
start_time: log.created_on, // Fallback start time
|
||||
final_duration: '00:00:00',
|
||||
final_participants: [],
|
||||
final_participant_count: 0,
|
||||
events: []
|
||||
});
|
||||
}
|
||||
// Ensure a base entry for the meeting exists
|
||||
if (!meetings.has(meeting_id)) {
|
||||
meetings.set(meeting_id, {
|
||||
meeting_id: meeting_id,
|
||||
room_name: 'Unknown',
|
||||
start_time: log.created_on, // Fallback start time
|
||||
final_duration: '00:00:00',
|
||||
final_participants: [],
|
||||
final_participant_count: 0,
|
||||
events: []
|
||||
});
|
||||
}
|
||||
|
||||
const meeting_report = meetings.get(meeting_id);
|
||||
const meeting_report = meetings.get(meeting_id);
|
||||
|
||||
if (log.action === 'jitsi_meeting_init') {
|
||||
// This is the main log entry, containing the final state.
|
||||
meeting_report.room_name = log.description;
|
||||
meeting_report.start_time = log.created_on; // The init log has the true start time
|
||||
if (log.meta_json) {
|
||||
meeting_report.final_duration = log.meta_json.duration;
|
||||
meeting_report.final_participants = log.meta_json.participants;
|
||||
meeting_report.final_participant_count = log.meta_json.participant_count;
|
||||
}
|
||||
} else {
|
||||
// This is a discrete event log.
|
||||
meeting_report.events.push({
|
||||
timestamp: log.created_on,
|
||||
action: log.action,
|
||||
details: log.meta_json
|
||||
});
|
||||
}
|
||||
}
|
||||
if (log.action === 'jitsi_meeting_init') {
|
||||
// This is the main log entry, containing the final state.
|
||||
meeting_report.room_name = log.description;
|
||||
meeting_report.start_time = log.created_on; // The init log has the true start time
|
||||
if (log.meta_json) {
|
||||
meeting_report.final_duration = log.meta_json.duration;
|
||||
meeting_report.final_participants = log.meta_json.participants;
|
||||
meeting_report.final_participant_count =
|
||||
log.meta_json.participant_count;
|
||||
}
|
||||
} else {
|
||||
// This is a discrete event log.
|
||||
meeting_report.events.push({
|
||||
timestamp: log.created_on,
|
||||
action: log.action,
|
||||
details: log.meta_json
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Sort events within each meeting chronologically
|
||||
for (const report of meetings.values()) {
|
||||
report.events.sort((a: any, b: any) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
||||
}
|
||||
// Sort events within each meeting chronologically
|
||||
for (const report of meetings.values()) {
|
||||
report.events.sort(
|
||||
(a: any, b: any) =>
|
||||
new Date(a.timestamp).getTime() -
|
||||
new Date(b.timestamp).getTime()
|
||||
);
|
||||
}
|
||||
|
||||
const final_report = Array.from(meetings.values());
|
||||
final_report.sort((a, b) => new Date(b.start_time).getTime() - new Date(a.start_time).getTime());
|
||||
const final_report = Array.from(meetings.values());
|
||||
final_report.sort(
|
||||
(a, b) =>
|
||||
new Date(b.start_time).getTime() - new Date(a.start_time).getTime()
|
||||
);
|
||||
|
||||
if (log_lvl) console.log('Final Jitsi report:', final_report);
|
||||
if (log_lvl) console.log('Final Jitsi report:', final_report);
|
||||
|
||||
return final_report;
|
||||
return final_report;
|
||||
}
|
||||
|
||||
export const load_jitsi_report = qry__jitsi_report;
|
||||
|
||||
@@ -175,11 +175,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_1 =
|
||||
`${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 =
|
||||
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
processed_obj = await Promise.resolve(
|
||||
specific_processor(processed_obj)
|
||||
);
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
@@ -201,7 +205,9 @@ export async function load_ae_obj_id__sponsorship_cfg({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_SponsorshipCfg | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__sponsorship_cfg() *** [V3] id=${sponsorship_cfg_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__sponsorship_cfg() *** [V3] id=${sponsorship_cfg_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Cache hit
|
||||
@@ -209,17 +215,32 @@ export async function load_ae_obj_id__sponsorship_cfg({
|
||||
try {
|
||||
const cached = await db_sponsorships.cfg.get(sponsorship_cfg_id);
|
||||
if (cached) {
|
||||
_refresh_sponsorship_cfg_id_background({ api_cfg, sponsorship_cfg_id, try_cache, log_lvl: 0 });
|
||||
_refresh_sponsorship_cfg_id_background({
|
||||
api_cfg,
|
||||
sponsorship_cfg_id,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
return cached as unknown as ae_SponsorshipCfg;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_sponsorship_cfg_id_background({ api_cfg, sponsorship_cfg_id, try_cache, log_lvl });
|
||||
return await _refresh_sponsorship_cfg_id_background({
|
||||
api_cfg,
|
||||
sponsorship_cfg_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_sponsorship_cfg_id_background({ api_cfg, sponsorship_cfg_id, try_cache, log_lvl }: any) {
|
||||
async function _refresh_sponsorship_cfg_id_background({
|
||||
api_cfg,
|
||||
sponsorship_cfg_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
const result = await api.get_ae_obj({
|
||||
@@ -230,7 +251,11 @@ async function _refresh_sponsorship_cfg_id_background({ api_cfg, sponsorship_cfg
|
||||
});
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__sponsorship_cfg_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__sponsorship_cfg_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_sponsorships,
|
||||
table_name: 'cfg',
|
||||
@@ -258,25 +283,43 @@ export async function load_ae_obj_id__sponsorship({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Sponsorship | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__sponsorship() *** [V3] id=${sponsorship_id} (SWR)`);
|
||||
console.log(
|
||||
`*** load_ae_obj_id__sponsorship() *** [V3] id=${sponsorship_id} (SWR)`
|
||||
);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Cache hit
|
||||
if (try_cache) {
|
||||
try {
|
||||
const cached = await db_sponsorships.sponsorship.get(sponsorship_id);
|
||||
const cached =
|
||||
await db_sponsorships.sponsorship.get(sponsorship_id);
|
||||
if (cached) {
|
||||
_refresh_sponsorship_id_background({ api_cfg, sponsorship_id, try_cache, log_lvl: 0 });
|
||||
_refresh_sponsorship_id_background({
|
||||
api_cfg,
|
||||
sponsorship_id,
|
||||
try_cache,
|
||||
log_lvl: 0
|
||||
});
|
||||
return cached as unknown as ae_Sponsorship;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API
|
||||
return await _refresh_sponsorship_id_background({ api_cfg, sponsorship_id, try_cache, log_lvl });
|
||||
return await _refresh_sponsorship_id_background({
|
||||
api_cfg,
|
||||
sponsorship_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
async function _refresh_sponsorship_id_background({ api_cfg, sponsorship_id, try_cache, log_lvl }: any) {
|
||||
async function _refresh_sponsorship_id_background({
|
||||
api_cfg,
|
||||
sponsorship_id,
|
||||
try_cache,
|
||||
log_lvl
|
||||
}: any) {
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||
try {
|
||||
const result = await api.get_ae_obj({
|
||||
@@ -287,7 +330,11 @@ async function _refresh_sponsorship_id_background({ api_cfg, sponsorship_id, try
|
||||
});
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
const processed_obj_li = await process_ae_obj__sponsorship_props({ obj_li: [result], log_lvl });
|
||||
const processed_obj_li =
|
||||
await process_ae_obj__sponsorship_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
});
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_sponsorships,
|
||||
table_name: 'sponsorship',
|
||||
@@ -332,7 +379,9 @@ export async function load_ae_obj_li__sponsorship({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Sponsorship[]> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_li__sponsorship() *** [V3] for=${for_obj_type}:${for_obj_id}`);
|
||||
console.log(
|
||||
`*** load_ae_obj_li__sponsorship() *** [V3] for=${for_obj_type}:${for_obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const result_li = await api.get_ae_obj_li({
|
||||
@@ -472,4 +521,4 @@ export const spons_func = {
|
||||
update_ae_obj__sponsorship,
|
||||
delete_ae_obj__sponsorship,
|
||||
download_export__sponsorship
|
||||
};
|
||||
};
|
||||
|
||||
@@ -9,7 +9,10 @@ import {
|
||||
import { get_obj_li_w_match_prop } from './ae_utils__get_obj_li_w_match_prop';
|
||||
import { file_extension_icon } from './ae_utils__file_extension_icon';
|
||||
import { file_extension_icon_lucide } from './ae_utils__file_extension_icon_lucide';
|
||||
import { process_permission_checks, compare_access_levels } from './ae_utils__perm_checks';
|
||||
import {
|
||||
process_permission_checks,
|
||||
compare_access_levels
|
||||
} from './ae_utils__perm_checks';
|
||||
import { iso_datetime_formatter } from './ae_utils__datetime_format';
|
||||
import { is_datetime_recent } from './ae_utils__is_datetime_recent';
|
||||
import { extract_prefixed_form_data } from './ae_utils__extract_prefixed_form_data';
|
||||
@@ -81,7 +84,6 @@ function handle_url_and_message(name: string, value: null | string) {
|
||||
// console.log('Message sent to parent (iframe):', message);
|
||||
}
|
||||
|
||||
|
||||
// ALERT: Not referenced anywhere -2026-02-03
|
||||
function create_a_element({
|
||||
account_id,
|
||||
|
||||
@@ -8,12 +8,22 @@ async function generate_iv() {
|
||||
}
|
||||
|
||||
// Updated 2025-05-08
|
||||
export const encrypt_content = async function encrypt_content(content: string, keyData: string) {
|
||||
export const encrypt_content = async function encrypt_content(
|
||||
content: string,
|
||||
keyData: string
|
||||
) {
|
||||
const iv = await generate_iv();
|
||||
const keyBytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(keyData));
|
||||
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, [
|
||||
'encrypt'
|
||||
]);
|
||||
const keyBytes = await crypto.subtle.digest(
|
||||
'SHA-256',
|
||||
new TextEncoder().encode(keyData)
|
||||
);
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
keyBytes,
|
||||
{ name: 'AES-CBC' },
|
||||
false,
|
||||
['encrypt']
|
||||
);
|
||||
const encodedContent = await crypto.subtle.encrypt(
|
||||
{ name: 'AES-CBC', iv: iv.buffer as ArrayBuffer },
|
||||
key,
|
||||
@@ -52,7 +62,10 @@ export const combine_iv_and_base64 = function combine_iv_and_base64(
|
||||
};
|
||||
|
||||
// Updated 2025-05-08
|
||||
export const encrypt_wrapper = async function encrypt_wrapper(content: string, keyData: string) {
|
||||
export const encrypt_wrapper = async function encrypt_wrapper(
|
||||
content: string,
|
||||
keyData: string
|
||||
) {
|
||||
if (!content) {
|
||||
console.error('No content provided. Returning empty string.');
|
||||
return '';
|
||||
@@ -73,11 +86,20 @@ export const decrypt_content = async function decrypt_content(
|
||||
iv: Uint8Array,
|
||||
keyData: string
|
||||
) {
|
||||
const keyBytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(keyData));
|
||||
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, [
|
||||
'decrypt'
|
||||
]);
|
||||
const encryptedContent = Uint8Array.from(atob(base64Content), (c) => c.charCodeAt(0));
|
||||
const keyBytes = await crypto.subtle.digest(
|
||||
'SHA-256',
|
||||
new TextEncoder().encode(keyData)
|
||||
);
|
||||
const key = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
keyBytes,
|
||||
{ name: 'AES-CBC' },
|
||||
false,
|
||||
['decrypt']
|
||||
);
|
||||
const encryptedContent = Uint8Array.from(atob(base64Content), (c) =>
|
||||
c.charCodeAt(0)
|
||||
);
|
||||
const decryptedContent = await crypto.subtle.decrypt(
|
||||
{ name: 'AES-CBC', iv: iv.buffer as ArrayBuffer },
|
||||
key,
|
||||
@@ -89,7 +111,9 @@ export const decrypt_content = async function decrypt_content(
|
||||
};
|
||||
|
||||
// Updated 2025-05-08
|
||||
export const split_iv_and_base64 = function split_iv_and_base64(combined: string) {
|
||||
export const split_iv_and_base64 = function split_iv_and_base64(
|
||||
combined: string
|
||||
) {
|
||||
if (!combined) {
|
||||
console.error('No combined string provided. Returning empty object.');
|
||||
return { iv: new Uint8Array(), base64: '' };
|
||||
@@ -97,7 +121,9 @@ export const split_iv_and_base64 = function split_iv_and_base64(combined: string
|
||||
const [iv_hex, encrypted_base64_string] = combined.split(':');
|
||||
const base64 = encrypted_base64_string;
|
||||
const match_result = iv_hex.match(/.{1,2}/g);
|
||||
const iv = new Uint8Array((match_result || []).map((byte) => parseInt(byte, 16)));
|
||||
const iv = new Uint8Array(
|
||||
(match_result || []).map((byte) => parseInt(byte, 16))
|
||||
);
|
||||
if (log_lvl) {
|
||||
console.log(`IV: ${iv}; Encrypted:`, base64);
|
||||
}
|
||||
@@ -105,7 +131,10 @@ export const split_iv_and_base64 = function split_iv_and_base64(combined: string
|
||||
};
|
||||
|
||||
// Updated 2025-05-15
|
||||
export const decrypt_wrapper = async function decrypt_wrapper(combined: string, keyData: string) {
|
||||
export const decrypt_wrapper = async function decrypt_wrapper(
|
||||
combined: string,
|
||||
keyData: string
|
||||
) {
|
||||
if (!combined) {
|
||||
console.error('No combined string provided. Returning empty string.');
|
||||
return false;
|
||||
|
||||
@@ -66,7 +66,9 @@ export const iso_datetime_formatter = function iso_datetime_formatter(
|
||||
datetime_string = dayjs(raw_datetime).format('MM-DD hh:mm A');
|
||||
break;
|
||||
case 'datetime_iso_tz':
|
||||
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD HH:mm:ss Z');
|
||||
datetime_string = dayjs(raw_datetime).format(
|
||||
'YYYY-MM-DD HH:mm:ss Z'
|
||||
);
|
||||
break;
|
||||
case 'datetime_iso_12_no_seconds':
|
||||
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD hh:mm A');
|
||||
@@ -75,7 +77,9 @@ export const iso_datetime_formatter = function iso_datetime_formatter(
|
||||
// datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD hh:mm A');
|
||||
// break;
|
||||
case 'datetime_us':
|
||||
datetime_string = dayjs(raw_datetime).format('MM/DD/YYYY hh:mm:ss A');
|
||||
datetime_string = dayjs(raw_datetime).format(
|
||||
'MM/DD/YYYY hh:mm:ss A'
|
||||
);
|
||||
break;
|
||||
case 'datetime_short':
|
||||
datetime_string = dayjs(raw_datetime).format('MMM D, YY HH:mm');
|
||||
@@ -93,13 +97,17 @@ export const iso_datetime_formatter = function iso_datetime_formatter(
|
||||
datetime_string = dayjs(raw_datetime).format('MMMM D, YYYY HH:mm');
|
||||
break;
|
||||
case 'datetime_12_long':
|
||||
datetime_string = dayjs(raw_datetime).format('MMMM D, YYYY hh:mm A');
|
||||
datetime_string = dayjs(raw_datetime).format(
|
||||
'MMMM D, YYYY hh:mm A'
|
||||
);
|
||||
break;
|
||||
case 'datetime_medium_sec':
|
||||
datetime_string = dayjs(raw_datetime).format('MMM D, YYYY H:mm:ss');
|
||||
break;
|
||||
case 'datetime_12_medium_sec':
|
||||
datetime_string = dayjs(raw_datetime).format('MMM D, YYYY h:mm:ss A');
|
||||
datetime_string = dayjs(raw_datetime).format(
|
||||
'MMM D, YYYY h:mm:ss A'
|
||||
);
|
||||
break;
|
||||
case 'datetime_short_month':
|
||||
datetime_string = dayjs(raw_datetime).format('MMM D hh:mm A');
|
||||
|
||||
@@ -50,7 +50,9 @@ export const extract_prefixed_form_data = function extract_prefixed_form_data({
|
||||
for (const field of form_data) {
|
||||
let [obj_prop_name, obj_prop_value] = field;
|
||||
if (log_lvl > 1) {
|
||||
console.log(`${obj_prop_name}: ${obj_prop_value} type=${typeof obj_prop_value}`);
|
||||
console.log(
|
||||
`${obj_prop_name}: ${obj_prop_value} type=${typeof obj_prop_value}`
|
||||
);
|
||||
}
|
||||
|
||||
// Trim string values if needed
|
||||
@@ -83,19 +85,31 @@ export const extract_prefixed_form_data = function extract_prefixed_form_data({
|
||||
// if (obj_prop_name.startsWith(prefix)) {
|
||||
obj_prop_name = obj_prop_name.replace(prefix, '');
|
||||
if (log_lvl) {
|
||||
console.log(`Checking: (${prefix})${obj_prop_name} value=${obj_prop_value}`);
|
||||
console.log(
|
||||
`Checking: (${prefix})${obj_prop_name} value=${obj_prop_value}`
|
||||
);
|
||||
}
|
||||
if (rm_empty_id && obj_prop_name.endsWith('id_random') && !obj_prop_value) {
|
||||
if (
|
||||
rm_empty_id &&
|
||||
obj_prop_name.endsWith('id_random') &&
|
||||
!obj_prop_value
|
||||
) {
|
||||
if (log_lvl) {
|
||||
console.log(`Match but empty *_id_random. Ignoring/removing: ${obj_prop_name}`);
|
||||
console.log(
|
||||
`Match but empty *_id_random. Ignoring/removing: ${obj_prop_name}`
|
||||
);
|
||||
}
|
||||
} else if (rm_empty && !obj_prop_value) {
|
||||
if (log_lvl) {
|
||||
console.log(`Match but empty. Ignoring/removing: ${obj_prop_name}`);
|
||||
console.log(
|
||||
`Match but empty. Ignoring/removing: ${obj_prop_name}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (log_lvl) {
|
||||
console.log(`Match: ${prefix})${obj_prop_name} value=${obj_prop_value}`);
|
||||
console.log(
|
||||
`Match: ${prefix})${obj_prop_name} value=${obj_prop_value}`
|
||||
);
|
||||
}
|
||||
data_obj[obj_prop_name] = obj_prop_value;
|
||||
}
|
||||
@@ -107,19 +121,31 @@ export const extract_prefixed_form_data = function extract_prefixed_form_data({
|
||||
} else {
|
||||
// No prefix set
|
||||
if (log_lvl) {
|
||||
console.log(`Checking: ${obj_prop_name} value=${obj_prop_value}`);
|
||||
console.log(
|
||||
`Checking: ${obj_prop_name} value=${obj_prop_value}`
|
||||
);
|
||||
}
|
||||
if (rm_empty_id && obj_prop_name.endsWith('id_random') && !obj_prop_value) {
|
||||
if (
|
||||
rm_empty_id &&
|
||||
obj_prop_name.endsWith('id_random') &&
|
||||
!obj_prop_value
|
||||
) {
|
||||
if (log_lvl > 1) {
|
||||
console.log(`Match but empty *_id_random. Ignoring/removing: ${obj_prop_name}`);
|
||||
console.log(
|
||||
`Match but empty *_id_random. Ignoring/removing: ${obj_prop_name}`
|
||||
);
|
||||
}
|
||||
} else if (rm_empty && !obj_prop_value) {
|
||||
if (log_lvl > 1) {
|
||||
console.log(`Match but empty. Ignoring/removing: ${obj_prop_name}`);
|
||||
console.log(
|
||||
`Match but empty. Ignoring/removing: ${obj_prop_name}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (log_lvl > 1) {
|
||||
console.log(`Match: ${obj_prop_name} value=${obj_prop_value}`);
|
||||
console.log(
|
||||
`Match: ${obj_prop_name} value=${obj_prop_value}`
|
||||
);
|
||||
}
|
||||
data_obj[obj_prop_name] = obj_prop_value;
|
||||
}
|
||||
|
||||
@@ -5,61 +5,63 @@ import * as Lucide from 'lucide-svelte';
|
||||
* @param extension The file extension (e.g., 'pdf', 'jpg').
|
||||
* @returns The Lucide icon component.
|
||||
*/
|
||||
export function file_extension_icon_lucide(extension: string | undefined | null): any {
|
||||
export function file_extension_icon_lucide(
|
||||
extension: string | undefined | null
|
||||
): any {
|
||||
const ext = extension?.toLowerCase() || '';
|
||||
|
||||
|
||||
const icon_map: Record<string, any> = {
|
||||
'pdf': Lucide.FileText,
|
||||
'doc': Lucide.FileText,
|
||||
'docx': Lucide.FileText,
|
||||
'txt': Lucide.FileText,
|
||||
'rtf': Lucide.FileText,
|
||||
|
||||
'xls': Lucide.FileSpreadsheet,
|
||||
'xlsx': Lucide.FileSpreadsheet,
|
||||
'csv': Lucide.FileSpreadsheet,
|
||||
|
||||
'png': Lucide.FileImage,
|
||||
'jpg': Lucide.FileImage,
|
||||
'jpeg': Lucide.FileImage,
|
||||
'gif': Lucide.FileImage,
|
||||
'webp': Lucide.FileImage,
|
||||
'bmp': Lucide.FileImage,
|
||||
'svg': Lucide.FileImage,
|
||||
|
||||
'mp3': Lucide.FileAudio,
|
||||
'wav': Lucide.FileAudio,
|
||||
'm4a': Lucide.FileAudio,
|
||||
'flac': Lucide.FileAudio,
|
||||
'aac': Lucide.FileAudio,
|
||||
'aif': Lucide.FileAudio,
|
||||
'aiff': Lucide.FileAudio,
|
||||
|
||||
'mp4': Lucide.FileVideo,
|
||||
'mkv': Lucide.FileVideo,
|
||||
'mov': Lucide.FileVideo,
|
||||
'avi': Lucide.FileVideo,
|
||||
pdf: Lucide.FileText,
|
||||
doc: Lucide.FileText,
|
||||
docx: Lucide.FileText,
|
||||
txt: Lucide.FileText,
|
||||
rtf: Lucide.FileText,
|
||||
|
||||
xls: Lucide.FileSpreadsheet,
|
||||
xlsx: Lucide.FileSpreadsheet,
|
||||
csv: Lucide.FileSpreadsheet,
|
||||
|
||||
png: Lucide.FileImage,
|
||||
jpg: Lucide.FileImage,
|
||||
jpeg: Lucide.FileImage,
|
||||
gif: Lucide.FileImage,
|
||||
webp: Lucide.FileImage,
|
||||
bmp: Lucide.FileImage,
|
||||
svg: Lucide.FileImage,
|
||||
|
||||
mp3: Lucide.FileAudio,
|
||||
wav: Lucide.FileAudio,
|
||||
m4a: Lucide.FileAudio,
|
||||
flac: Lucide.FileAudio,
|
||||
aac: Lucide.FileAudio,
|
||||
aif: Lucide.FileAudio,
|
||||
aiff: Lucide.FileAudio,
|
||||
|
||||
mp4: Lucide.FileVideo,
|
||||
mkv: Lucide.FileVideo,
|
||||
mov: Lucide.FileVideo,
|
||||
avi: Lucide.FileVideo,
|
||||
'3gp': Lucide.FileVideo,
|
||||
|
||||
'ppt': Lucide.Presentation,
|
||||
'pptx': Lucide.Presentation,
|
||||
'key': Lucide.Presentation,
|
||||
'odp': Lucide.Presentation,
|
||||
|
||||
'zip': Lucide.FileArchive,
|
||||
|
||||
ppt: Lucide.Presentation,
|
||||
pptx: Lucide.Presentation,
|
||||
key: Lucide.Presentation,
|
||||
odp: Lucide.Presentation,
|
||||
|
||||
zip: Lucide.FileArchive,
|
||||
'7z': Lucide.FileArchive,
|
||||
'rar': Lucide.FileArchive,
|
||||
'tar': Lucide.FileArchive,
|
||||
'gz': Lucide.FileArchive,
|
||||
|
||||
'json': Lucide.FileJson,
|
||||
|
||||
'html': Lucide.FileCode,
|
||||
'htm': Lucide.FileCode,
|
||||
'js': Lucide.FileCode,
|
||||
'ts': Lucide.FileCode,
|
||||
'css': Lucide.FileCode,
|
||||
'php': Lucide.FileCode
|
||||
rar: Lucide.FileArchive,
|
||||
tar: Lucide.FileArchive,
|
||||
gz: Lucide.FileArchive,
|
||||
|
||||
json: Lucide.FileJson,
|
||||
|
||||
html: Lucide.FileCode,
|
||||
htm: Lucide.FileCode,
|
||||
js: Lucide.FileCode,
|
||||
ts: Lucide.FileCode,
|
||||
css: Lucide.FileCode,
|
||||
php: Lucide.FileCode
|
||||
};
|
||||
|
||||
return icon_map[ext] || Lucide.File;
|
||||
|
||||
@@ -12,12 +12,18 @@ export const clean_filename = function clean_filename(
|
||||
return '';
|
||||
}
|
||||
|
||||
const cleaned_filename = filename.replace(unacceptable_chars, replacement_char);
|
||||
const cleaned_filename = filename.replace(
|
||||
unacceptable_chars,
|
||||
replacement_char
|
||||
);
|
||||
// console.log(cleaned_filename);
|
||||
return cleaned_filename;
|
||||
};
|
||||
|
||||
export const format_bytes = function format_bytes(bytes: number, decimals: number = 2) {
|
||||
export const format_bytes = function format_bytes(
|
||||
bytes: number,
|
||||
decimals: number = 2
|
||||
) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
||||
const k = 1024;
|
||||
@@ -30,14 +36,19 @@ export const format_bytes = function format_bytes(bytes: number, decimals: numbe
|
||||
};
|
||||
|
||||
// Updated 2024-08-12
|
||||
export const guess_file_name = function guess_file_name(filename_string: string) {
|
||||
export const guess_file_name = function guess_file_name(
|
||||
filename_string: string
|
||||
) {
|
||||
// console.log('*** guess_file_name() ***');
|
||||
if (!filename_string) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (filename_string.includes('.')) {
|
||||
const file_name = filename_string.substring(0, filename_string.lastIndexOf('.'));
|
||||
const file_name = filename_string.substring(
|
||||
0,
|
||||
filename_string.lastIndexOf('.')
|
||||
);
|
||||
// console.log(file_name);
|
||||
return file_name;
|
||||
} else {
|
||||
@@ -46,7 +57,9 @@ export const guess_file_name = function guess_file_name(filename_string: string)
|
||||
};
|
||||
|
||||
// Updated 2024-08-12
|
||||
export const guess_file_extension = function guess_file_extension(filename_string: string) {
|
||||
export const guess_file_extension = function guess_file_extension(
|
||||
filename_string: string
|
||||
) {
|
||||
// console.log('*** guess_file_extension() ***');
|
||||
if (!filename_string) {
|
||||
return '';
|
||||
@@ -57,21 +70,27 @@ export const guess_file_extension = function guess_file_extension(filename_strin
|
||||
}
|
||||
|
||||
const file_extension =
|
||||
filename_string.substring(filename_string.lastIndexOf('.') + 1, filename_string.length) ||
|
||||
filename_string;
|
||||
filename_string.substring(
|
||||
filename_string.lastIndexOf('.') + 1,
|
||||
filename_string.length
|
||||
) || filename_string;
|
||||
// console.log(file_extension);
|
||||
return file_extension;
|
||||
};
|
||||
|
||||
// Updated 2024-08-12
|
||||
export const get_file_hash = async function get_file_hash(file: File): Promise<string> {
|
||||
export const get_file_hash = async function get_file_hash(
|
||||
file: File
|
||||
): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file_reader = new FileReader();
|
||||
|
||||
file_reader.onload = async function () {
|
||||
const result = file_reader.result;
|
||||
if (!result || typeof result === 'string') {
|
||||
console.log('File was not read completely or is in wrong format');
|
||||
console.log(
|
||||
'File was not read completely or is in wrong format'
|
||||
);
|
||||
reject('Error reading the file');
|
||||
return;
|
||||
}
|
||||
@@ -84,7 +103,9 @@ export const get_file_hash = async function get_file_hash(file: File): Promise<s
|
||||
|
||||
const hash_buffer = await crypto.subtle.digest('SHA-256', result);
|
||||
const hash_array = Array.from(new Uint8Array(hash_buffer));
|
||||
const hash_hex = hash_array.map((b) => b.toString(16).padStart(2, '0')).join('');
|
||||
const hash_hex = hash_array
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
|
||||
resolve(hash_hex);
|
||||
};
|
||||
|
||||
@@ -4,17 +4,22 @@
|
||||
*/
|
||||
export function format_html(html: string): string {
|
||||
if (!html) return '';
|
||||
|
||||
|
||||
let indent = 0;
|
||||
const tab = ' ';
|
||||
return html
|
||||
.replace(/>\s*</g, '>\n<') // Add newlines between tags
|
||||
.split('\n')
|
||||
.map(line => {
|
||||
.map((line) => {
|
||||
line = line.trim();
|
||||
if (line.match(/<\//)) indent--; // Decrease indent for closing tags
|
||||
const out = tab.repeat(Math.max(0, indent)) + line;
|
||||
if (line.match(/<[^\/!]/) && !line.match(/\/>/) && !line.match(/<\//)) indent++; // Increase indent for opening tags
|
||||
if (
|
||||
line.match(/<[^\/!]/) &&
|
||||
!line.match(/\/>/) &&
|
||||
!line.match(/<\//)
|
||||
)
|
||||
indent++; // Increase indent for opening tags
|
||||
return out;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
@@ -9,7 +9,9 @@ export const is_datetime_recent = function is_datetime_recent({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** is_datetime_recent() *** datetime=${datetime} minutes=${minutes}`);
|
||||
console.log(
|
||||
`*** is_datetime_recent() *** datetime=${datetime} minutes=${minutes}`
|
||||
);
|
||||
}
|
||||
|
||||
const now: any = new Date();
|
||||
|
||||
@@ -17,7 +17,10 @@ export const access_level_order = [
|
||||
* Compares two access levels based on the hierarchy.
|
||||
* @returns 1 if level_a is higher, -1 if level_b is higher, 0 if equal.
|
||||
*/
|
||||
export const compare_access_levels = function (level_a: string, level_b: string): number {
|
||||
export const compare_access_levels = function (
|
||||
level_a: string,
|
||||
level_b: string
|
||||
): number {
|
||||
const index_a = access_level_order.indexOf(level_a || 'anonymous');
|
||||
const index_b = access_level_order.indexOf(level_b || 'anonymous');
|
||||
|
||||
@@ -30,7 +33,9 @@ export const compare_access_levels = function (level_a: string, level_b: string)
|
||||
// NOTE: I know there is a better more efficient way to do this, but I don't have time for that right now.
|
||||
// Reminder: super > manager > administrator > trusted > public > authenticated > anonymous
|
||||
// Super is the highest level. Anonymous is the lowest level.
|
||||
export const process_permission_checks = function process_permission_checks(access_type: string) {
|
||||
export const process_permission_checks = function process_permission_checks(
|
||||
access_type: string
|
||||
) {
|
||||
// let access_checks = { 'access_type': null, 'super_check': null };
|
||||
const access_checks: key_val = {};
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import type { key_val } from './ae_utils';
|
||||
*/
|
||||
// Updated 2022-02-11
|
||||
|
||||
export const process_data_string = function process_data_string(data_string: string) {
|
||||
export const process_data_string = function process_data_string(
|
||||
data_string: string
|
||||
) {
|
||||
console.log('*** process_data_string() ***');
|
||||
// console.log(data_string);
|
||||
if (!data_string || data_string.length < 1) {
|
||||
@@ -70,14 +72,18 @@ export const process_data_string = function process_data_string(data_string: str
|
||||
obj['type'] = 'url';
|
||||
obj['url'] = data_string;
|
||||
} else {
|
||||
console.log('The unknown data string type was found. Returning the string part.');
|
||||
console.log(
|
||||
'The unknown data string type was found. Returning the string part.'
|
||||
);
|
||||
const unknown_str = data_string.slice(colon_index + 1);
|
||||
console.log(unknown_str);
|
||||
|
||||
obj['str'] = unknown_str;
|
||||
}
|
||||
} else {
|
||||
console.log('The data string type was not found. Returning the entire string.');
|
||||
console.log(
|
||||
'The data string type was not found. Returning the entire string.'
|
||||
);
|
||||
console.log(data_string);
|
||||
|
||||
obj['qr_type'] = 'UNKNOWN';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export function return_obj_type_path({
|
||||
obj_type = null,
|
||||
obj_type_prop_name = null
|
||||
}: {
|
||||
obj_type?: string | null,
|
||||
obj_type_prop_name?: string | null
|
||||
export function return_obj_type_path({
|
||||
obj_type = null,
|
||||
obj_type_prop_name = null
|
||||
}: {
|
||||
obj_type?: string | null;
|
||||
obj_type_prop_name?: string | null;
|
||||
}) {
|
||||
console.log('*** return_obj_type_path() ***');
|
||||
|
||||
@@ -14,29 +14,69 @@ export function return_obj_type_path({
|
||||
{ name: 'archive', display: 'Archive', path: 'archive' },
|
||||
{ name: 'address', display: 'Address', path: 'address' },
|
||||
{ name: 'archive', display: 'Archive', path: 'archive' },
|
||||
{ name: 'archive_content', display: 'Archive Content', path: 'archive/content' },
|
||||
{
|
||||
name: 'archive_content',
|
||||
display: 'Archive Content',
|
||||
path: 'archive/content'
|
||||
},
|
||||
{ name: 'contact', display: 'Contact', path: 'contact' },
|
||||
{ name: 'data_store', display: 'Data Store', path: 'data_store' },
|
||||
{ name: 'event_abstract', display: 'Event Abstract', path: 'event/abstract' },
|
||||
{
|
||||
name: 'event_abstract',
|
||||
display: 'Event Abstract',
|
||||
path: 'event/abstract'
|
||||
},
|
||||
{ name: 'event_badge', display: 'Event Badge', path: 'event/badge' },
|
||||
{ name: 'event_device', display: 'Event Device', path: 'event/device' },
|
||||
{ name: 'event_exhibit', display: 'Event Exhibit', path: 'event/exhibit' },
|
||||
{
|
||||
name: 'event_exhibit',
|
||||
display: 'Event Exhibit',
|
||||
path: 'event/exhibit'
|
||||
},
|
||||
{ name: 'event_file', display: 'Event File', path: 'event/file' },
|
||||
{ name: 'event_location', display: 'Event Location', path: 'event/location' },
|
||||
{
|
||||
name: 'event_location',
|
||||
display: 'Event Location',
|
||||
path: 'event/location'
|
||||
},
|
||||
{ name: 'event_person', display: 'Event Person', path: 'event/person' },
|
||||
{ name: 'event_presentation', display: 'Event Presentation', path: 'event/' },
|
||||
{ name: 'event_presenter', display: 'Event Presenter', path: 'event/presenter' },
|
||||
{ name: 'event_registration', display: 'Event Registration', path: 'event/registration' },
|
||||
{ name: 'event_session', display: 'Event Session', path: 'event/session' },
|
||||
{
|
||||
name: 'event_presentation',
|
||||
display: 'Event Presentation',
|
||||
path: 'event/'
|
||||
},
|
||||
{
|
||||
name: 'event_presenter',
|
||||
display: 'Event Presenter',
|
||||
path: 'event/presenter'
|
||||
},
|
||||
{
|
||||
name: 'event_registration',
|
||||
display: 'Event Registration',
|
||||
path: 'event/registration'
|
||||
},
|
||||
{
|
||||
name: 'event_session',
|
||||
display: 'Event Session',
|
||||
path: 'event/session'
|
||||
},
|
||||
{ name: 'event', display: 'Event', path: 'event' },
|
||||
{ name: 'hosted_file', display: 'Hosted File', path: 'hosted_file' },
|
||||
{ name: 'journal', display: 'Journal', path: 'journal' },
|
||||
{ name: 'journal_entry', display: 'Journal Entry', path: 'journal/entry' },
|
||||
{
|
||||
name: 'journal_entry',
|
||||
display: 'Journal Entry',
|
||||
path: 'journal/entry'
|
||||
},
|
||||
{ name: 'order_line', display: 'Order Line', path: 'order/line' },
|
||||
{ name: 'order', display: 'Order', path: 'order' },
|
||||
{ name: 'person', display: 'Person', path: 'person' },
|
||||
{ name: 'post', display: 'Archive', path: 'post' },
|
||||
{ name: 'post_comment', display: 'Archive Content', path: 'post/comment' },
|
||||
{
|
||||
name: 'post_comment',
|
||||
display: 'Archive Content',
|
||||
path: 'post/comment'
|
||||
},
|
||||
{ name: 'user', display: 'User', path: 'user' }
|
||||
];
|
||||
|
||||
|
||||
@@ -76,7 +76,10 @@ export function set_obj_prop_display_name({
|
||||
// console.log(known_obj_type_li_dict[i]);
|
||||
if (prop_name.startsWith(known_obj_type_li_dict[i].name)) {
|
||||
// console.log(`Found ${known_obj_type_li_dict[i].name}`);
|
||||
prop_display_name = prop_name.replace(known_obj_type_li_dict[i].name, '');
|
||||
prop_display_name = prop_name.replace(
|
||||
known_obj_type_li_dict[i].name,
|
||||
''
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -101,7 +104,10 @@ export function set_obj_prop_display_name({
|
||||
// console.log(`Found ${known_obj_type_li_dict[i].name}`);
|
||||
found_obj_type = known_obj_type_li_dict[i].name;
|
||||
if (found_obj_type == obj_type) {
|
||||
prop_display_name = prop_name.replace(known_obj_type_li_dict[i].name, '');
|
||||
prop_display_name = prop_name.replace(
|
||||
known_obj_type_li_dict[i].name,
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -20,7 +20,8 @@ export function to_title_case(text_string: string) {
|
||||
array[index - 3] !== ':' &&
|
||||
array[index + 1] !== ':' &&
|
||||
/* Ignore small words that start a hyphenated phrase */
|
||||
(array[index + 1] !== '-' || (array[index - 1] === '-' && array[index + 1] === '-'))
|
||||
(array[index + 1] !== '-' ||
|
||||
(array[index - 1] === '-' && array[index + 1] === '-'))
|
||||
) {
|
||||
return current.toLowerCase();
|
||||
}
|
||||
@@ -36,9 +37,12 @@ export function to_title_case(text_string: string) {
|
||||
}
|
||||
|
||||
/* Capitalize the first letter */
|
||||
return current.replace(alphanumericPattern, function (match: string) {
|
||||
return match.toUpperCase();
|
||||
});
|
||||
return current.replace(
|
||||
alphanumericPattern,
|
||||
function (match: string) {
|
||||
return match.toUpperCase();
|
||||
}
|
||||
);
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { compare_access_levels, process_permission_checks, access_level_order } from './ae_utils__perm_checks';
|
||||
import {
|
||||
compare_access_levels,
|
||||
process_permission_checks,
|
||||
access_level_order
|
||||
} from './ae_utils__perm_checks';
|
||||
|
||||
describe('Permission Hierarchy Tests', () => {
|
||||
describe('compare_access_levels', () => {
|
||||
@@ -15,7 +19,9 @@ describe('Permission Hierarchy Tests', () => {
|
||||
it('should correctly identify downgrades', () => {
|
||||
// Low to High should return -1
|
||||
expect(compare_access_levels('manager', 'super')).toBe(-1);
|
||||
expect(compare_access_levels('anonymous', 'authenticated')).toBe(-1);
|
||||
expect(compare_access_levels('anonymous', 'authenticated')).toBe(
|
||||
-1
|
||||
);
|
||||
});
|
||||
|
||||
it('should return 0 for equal levels', () => {
|
||||
@@ -25,7 +31,9 @@ describe('Permission Hierarchy Tests', () => {
|
||||
|
||||
it('should handle null/empty as anonymous', () => {
|
||||
expect(compare_access_levels('trusted', '')).toBe(1);
|
||||
expect(compare_access_levels(null as any, 'authenticated')).toBe(-1);
|
||||
expect(compare_access_levels(null as any, 'authenticated')).toBe(
|
||||
-1
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -62,7 +62,9 @@ export const get_ae_obj_li_for_lu = async function get_ae_obj_li_for_lu({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** get_ae_obj_li_for_lu() *** for_lu_type=${for_lu_type}`);
|
||||
console.log(
|
||||
`*** get_ae_obj_li_for_lu() *** for_lu_type=${for_lu_type}`
|
||||
);
|
||||
}
|
||||
|
||||
// Pass headers as-is — get_object will auto-promote the real account_id from api_cfg.
|
||||
@@ -331,7 +333,9 @@ export const delete_ae_obj_id_crud = async function delete_ae_obj_id_crud({
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id_crud() *** obj_type: ${obj_type} obj_id: ${obj_id}`);
|
||||
console.log(
|
||||
`*** delete_ae_obj_id_crud() *** obj_type: ${obj_type} obj_id: ${obj_id}`
|
||||
);
|
||||
}
|
||||
|
||||
data['super_key'] = key;
|
||||
@@ -369,7 +373,6 @@ export const delete_ae_obj_id_crud = async function delete_ae_obj_id_crud({
|
||||
return object_obj_delete_promise;
|
||||
};
|
||||
|
||||
|
||||
/* BEGIN: Hosted File Related */
|
||||
|
||||
// Updated 2026-01-07
|
||||
@@ -473,74 +476,75 @@ export const delete_hosted_file = async function delete_hosted_file({
|
||||
/* BEGIN: Data Store Related */
|
||||
|
||||
// Updated 2023-06-29
|
||||
export const get_data_store_obj_w_code = async function get_data_store_obj_w_code({
|
||||
api_cfg,
|
||||
data_store_code,
|
||||
data_type = 'text',
|
||||
headers = {},
|
||||
params = {},
|
||||
timeout = 25000,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
data_store_code: string;
|
||||
data_type?: string;
|
||||
headers?: key_val;
|
||||
params?: key_val;
|
||||
timeout?: number;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log('*** get_data_store_obj_w_code() ***');
|
||||
}
|
||||
export const get_data_store_obj_w_code =
|
||||
async function get_data_store_obj_w_code({
|
||||
api_cfg,
|
||||
data_store_code,
|
||||
data_type = 'text',
|
||||
headers = {},
|
||||
params = {},
|
||||
timeout = 25000,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
data_store_code: string;
|
||||
data_type?: string;
|
||||
headers?: key_val;
|
||||
params?: key_val;
|
||||
timeout?: number;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log('*** get_data_store_obj_w_code() ***');
|
||||
}
|
||||
|
||||
// let get_item_result = window.localStorage.getItem(code);
|
||||
// let get_item_result = window.localStorage.getItem(code);
|
||||
|
||||
const endpoint = `/data_store/code/${data_store_code}`;
|
||||
let data_store_obj_get_promise = await api.get_object({
|
||||
api_cfg: api_cfg,
|
||||
endpoint: endpoint,
|
||||
headers: headers,
|
||||
params: params,
|
||||
timeout: timeout,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
if (data_store_obj_get_promise === false) {
|
||||
console.log('Data Store - RUN AGAIN WITH BACKUP');
|
||||
const original_api_base_url = api_cfg['base_url'];
|
||||
|
||||
const temp_api = api_cfg;
|
||||
temp_api['base_url'] = temp_api['base_url_bak'];
|
||||
|
||||
data_store_obj_get_promise = await api.get_object({
|
||||
api_cfg: temp_api,
|
||||
const endpoint = `/data_store/code/${data_store_code}`;
|
||||
let data_store_obj_get_promise = await api.get_object({
|
||||
api_cfg: api_cfg,
|
||||
endpoint: endpoint,
|
||||
headers: headers,
|
||||
params: params,
|
||||
timeout: timeout,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
temp_api['base_url'] = original_api_base_url;
|
||||
}
|
||||
|
||||
const data_store_obj = data_store_obj_get_promise;
|
||||
if (data_store_obj_get_promise === false) {
|
||||
console.log('Data Store - RUN AGAIN WITH BACKUP');
|
||||
const original_api_base_url = api_cfg['base_url'];
|
||||
|
||||
if (data_type == 'text') {
|
||||
// console.log(data_store_obj.text);
|
||||
// window.localStorage.setItem(data_store_code, data_store_obj.text);
|
||||
// localStorage.setItem(data_store_code, data_store_obj.text);
|
||||
} else if (data_type == 'json') {
|
||||
// console.log(data_store_obj.json);
|
||||
// window.localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json));
|
||||
// localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json));
|
||||
}
|
||||
const temp_api = api_cfg;
|
||||
temp_api['base_url'] = temp_api['base_url_bak'];
|
||||
|
||||
if (log_lvl > 1) {
|
||||
console.log('Response Data:', data_store_obj);
|
||||
}
|
||||
return data_store_obj;
|
||||
};
|
||||
data_store_obj_get_promise = await api.get_object({
|
||||
api_cfg: temp_api,
|
||||
endpoint: endpoint,
|
||||
headers: headers,
|
||||
params: params,
|
||||
timeout: timeout,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
temp_api['base_url'] = original_api_base_url;
|
||||
}
|
||||
|
||||
const data_store_obj = data_store_obj_get_promise;
|
||||
|
||||
if (data_type == 'text') {
|
||||
// console.log(data_store_obj.text);
|
||||
// window.localStorage.setItem(data_store_code, data_store_obj.text);
|
||||
// localStorage.setItem(data_store_code, data_store_obj.text);
|
||||
} else if (data_type == 'json') {
|
||||
// console.log(data_store_obj.json);
|
||||
// window.localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json));
|
||||
// localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json));
|
||||
}
|
||||
|
||||
if (log_lvl > 1) {
|
||||
console.log('Response Data:', data_store_obj);
|
||||
}
|
||||
return data_store_obj;
|
||||
};
|
||||
/* END: Data Store Related */
|
||||
|
||||
/* BEGIN: Utility: Email Related */
|
||||
@@ -591,8 +595,13 @@ export const send_email = async function send_email({
|
||||
|
||||
// Skip email sending entirely when running in a test/Playwright environment.
|
||||
// Set window.__ae_test_mode = true via addInitScript to activate this guard.
|
||||
if (typeof globalThis !== 'undefined' && (globalThis as any).__ae_test_mode) {
|
||||
console.log(`[TEST MODE] send_email() suppressed — would have sent to: ${to_email}, subject: ${subject}`);
|
||||
if (
|
||||
typeof globalThis !== 'undefined' &&
|
||||
(globalThis as any).__ae_test_mode
|
||||
) {
|
||||
console.log(
|
||||
`[TEST MODE] send_email() suppressed — would have sent to: ${to_email}, subject: ${subject}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -663,7 +672,7 @@ const obj = {
|
||||
create_nested_obj: create_nested_obj,
|
||||
update_ae_obj: update_ae_obj,
|
||||
update_nested_obj: update_nested_obj,
|
||||
delete_ae_obj:delete_ae_obj,
|
||||
delete_ae_obj: delete_ae_obj,
|
||||
delete_nested_ae_obj: delete_nested_ae_obj,
|
||||
create_ae_obj_crud: create_ae_obj_crud,
|
||||
update_ae_obj_id_crud: update_ae_obj_id_crud,
|
||||
@@ -676,4 +685,4 @@ const obj = {
|
||||
send_email: send_email
|
||||
};
|
||||
export const api = obj;
|
||||
// module.exports = api;
|
||||
// module.exports = api;
|
||||
|
||||
@@ -1,295 +1,320 @@
|
||||
<script lang="ts">
|
||||
// *** Import Svelte specific
|
||||
import { onDestroy, onMount, tick } from 'svelte';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
// *** Import Svelte specific
|
||||
import { onDestroy, onMount, tick } from 'svelte';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
// import { liveQuery } from "dexie";
|
||||
import { Lock, LockOpen, RefreshCw, ShieldEllipsis, ShieldMinus, ShieldPlus, ShieldUser, Unlink, User, UserCheck, UserRound, Wand2 } from '@lucide/svelte';
|
||||
// *** Import Aether specific variables and functions
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
// import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
// Ideally the Event related stores should not be imported here?
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
// import { db_events } from "$lib/db_events";
|
||||
// *** Import other supporting libraries
|
||||
// import { liveQuery } from "dexie";
|
||||
import {
|
||||
Lock,
|
||||
LockOpen,
|
||||
RefreshCw,
|
||||
ShieldEllipsis,
|
||||
ShieldMinus,
|
||||
ShieldPlus,
|
||||
ShieldUser,
|
||||
Unlink,
|
||||
User,
|
||||
UserCheck,
|
||||
UserRound,
|
||||
Wand2
|
||||
} from '@lucide/svelte';
|
||||
// *** Import Aether specific variables and functions
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
// import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
// Ideally the Event related stores should not be imported here?
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
// import { db_events } from "$lib/db_events";
|
||||
|
||||
// export let hidden: boolean = false;
|
||||
// export let hidden: boolean = false;
|
||||
|
||||
// *** Setup Svelte properties
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
focus_input: boolean;
|
||||
expand?: boolean;
|
||||
show_passcode_input: boolean;
|
||||
trigger_clear_access: null | boolean;
|
||||
// *** Setup Svelte properties
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
focus_input: boolean;
|
||||
expand?: boolean;
|
||||
show_passcode_input: boolean;
|
||||
trigger_clear_access: null | boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
focus_input = $bindable(false),
|
||||
expand = $bindable(false),
|
||||
show_passcode_input = $bindable(false),
|
||||
trigger_clear_access = $bindable(null)
|
||||
}: Props = $props();
|
||||
|
||||
let entered_passcode: null | string = $state(null);
|
||||
let checked_passcode: null | string = $state(null);
|
||||
// let password_checked: boolean = $state(false);
|
||||
// let entered_passcode: null|string = '';
|
||||
// let show_passcode_input: boolean = $state(false);
|
||||
// let show_passcode_input: boolean = false;
|
||||
|
||||
// let trigger: null|string|boolean = null;
|
||||
let trigger: null | string | boolean = $state(null);
|
||||
|
||||
// const dispatch = createEventDispatcher();
|
||||
|
||||
// WARNING: There is a bug (I think) around here related to the entered_passcode not being cleared. There seems to be something different about how Svelte handles state in this component compared to the others. This might be related to the `$effect` or `$derived` usage. Maybe there are conflicting things trying to update the $ae_loc store at the same time.
|
||||
onMount(() => {
|
||||
// log_lvl = 2;
|
||||
if (log_lvl > 1) {
|
||||
console.log('** Element Mounted: ** Element Access Type');
|
||||
}
|
||||
entered_passcode = '';
|
||||
trigger = null;
|
||||
|
||||
// /** @type {HTMLElement | null} */
|
||||
// const to_focus = document.getElementById('access_passcode_input');
|
||||
// to_focus?.focus();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (log_lvl > 1) {
|
||||
console.log('** Element Destroyed: ** Element Access Type');
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
focus_input = $bindable(false),
|
||||
expand = $bindable(false),
|
||||
show_passcode_input = $bindable(false),
|
||||
trigger_clear_access = $bindable(null)
|
||||
}: Props = $props();
|
||||
// Clean up any references or listeners if needed
|
||||
entered_passcode = null; // Clear the entered passcode
|
||||
show_passcode_input = false;
|
||||
|
||||
let entered_passcode: null | string = $state(null);
|
||||
let checked_passcode: null | string = $state(null);
|
||||
// let password_checked: boolean = $state(false);
|
||||
// let entered_passcode: null|string = '';
|
||||
// let show_passcode_input: boolean = $state(false);
|
||||
// let show_passcode_input: boolean = false;
|
||||
// Reset trigger
|
||||
trigger = null;
|
||||
});
|
||||
|
||||
// let trigger: null|string|boolean = null;
|
||||
let trigger: null | string | boolean = $state(null);
|
||||
// afterNavigate(() => {
|
||||
// /** @type {HTMLElement | null} */
|
||||
// const to_focus = document.getElementById('access_passcode_input');
|
||||
// to_focus?.focus();
|
||||
// });
|
||||
|
||||
// const dispatch = createEventDispatcher();
|
||||
$effect(() => {
|
||||
if (
|
||||
entered_passcode &&
|
||||
entered_passcode.length >= 5 &&
|
||||
entered_passcode != checked_passcode
|
||||
) {
|
||||
checked_passcode = entered_passcode;
|
||||
if (log_lvl) {
|
||||
console.log(`entered_passcode=${entered_passcode}`);
|
||||
}
|
||||
handle_check_access_type_passcode();
|
||||
}
|
||||
});
|
||||
|
||||
// WARNING: There is a bug (I think) around here related to the entered_passcode not being cleared. There seems to be something different about how Svelte handles state in this component compared to the others. This might be related to the `$effect` or `$derived` usage. Maybe there are conflicting things trying to update the $ae_loc store at the same time.
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
if (trigger && $ae_loc.access_type) {
|
||||
trigger = false;
|
||||
if (log_lvl) {
|
||||
console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
|
||||
}
|
||||
|
||||
let access_checks_results = ae_util.process_permission_checks(
|
||||
$ae_loc.access_type
|
||||
);
|
||||
|
||||
$ae_loc = { ...$ae_loc, ...access_checks_results };
|
||||
$ae_loc = $ae_loc;
|
||||
$ae_loc.sys_menu.expand = false;
|
||||
} else if (trigger) {
|
||||
trigger = false;
|
||||
if (log_lvl) {
|
||||
console.log(`$ae_loc.access_type=not set`);
|
||||
}
|
||||
|
||||
// Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
|
||||
let access_checks_results = ae_util.process_permission_checks('');
|
||||
|
||||
$ae_loc = { ...$ae_loc, ...access_checks_results };
|
||||
$ae_loc = $ae_loc;
|
||||
}
|
||||
});
|
||||
|
||||
// This does not seem to work. I feel like it should though...?
|
||||
$effect(() => {
|
||||
if (!hide && focus_input) {
|
||||
focus_input = false;
|
||||
// log_lvl = 2;
|
||||
// await tick();
|
||||
// document.getElementById('access_passcode_input')?.focus();
|
||||
if (log_lvl > 1) {
|
||||
console.log('** Element Mounted: ** Element Access Type');
|
||||
console.log('Effect: Setting focus on the passcode input field');
|
||||
}
|
||||
entered_passcode = '';
|
||||
trigger = null;
|
||||
/** @type {HTMLElement | null} */
|
||||
const to_focus = document.getElementById('access_passcode_input');
|
||||
to_focus?.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// /** @type {HTMLElement | null} */
|
||||
// const to_focus = document.getElementById('access_passcode_input');
|
||||
// to_focus?.focus();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (log_lvl > 1) {
|
||||
console.log('** Element Destroyed: ** Element Access Type');
|
||||
$effect(() => {
|
||||
if (trigger_clear_access) {
|
||||
trigger_clear_access = false;
|
||||
if (log_lvl) {
|
||||
console.log(`trigger_clear_access=${trigger_clear_access}`);
|
||||
}
|
||||
handle_clear_access();
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up any references or listeners if needed
|
||||
entered_passcode = null; // Clear the entered passcode
|
||||
show_passcode_input = false;
|
||||
function handle_check_access_type_passcode() {
|
||||
if (log_lvl > 1) {
|
||||
console.log(
|
||||
`*** handle_check_access_type_passcode() *** passcode list:`,
|
||||
$ae_loc.site_access_code_kv
|
||||
);
|
||||
}
|
||||
|
||||
// Reset trigger
|
||||
trigger = null;
|
||||
});
|
||||
// Reminder: super > manager > administrator > trusted > public > authenticated > anonymous
|
||||
|
||||
// afterNavigate(() => {
|
||||
// /** @type {HTMLElement | null} */
|
||||
// const to_focus = document.getElementById('access_passcode_input');
|
||||
// to_focus?.focus();
|
||||
// });
|
||||
|
||||
$effect(() => {
|
||||
if (entered_passcode && entered_passcode.length >= 5) {
|
||||
if (
|
||||
entered_passcode &&
|
||||
entered_passcode.length >= 5 &&
|
||||
entered_passcode != checked_passcode
|
||||
$ae_loc.site_access_code_kv.super.length >= 8 &&
|
||||
$ae_loc.site_access_code_kv.super == entered_passcode
|
||||
) {
|
||||
checked_passcode = entered_passcode;
|
||||
if (log_lvl) {
|
||||
console.log(`entered_passcode=${entered_passcode}`);
|
||||
}
|
||||
handle_check_access_type_passcode();
|
||||
}
|
||||
});
|
||||
console.log('Super passcode matched');
|
||||
|
||||
$effect(() => {
|
||||
if (trigger && $ae_loc.access_type) {
|
||||
trigger = false;
|
||||
if (log_lvl) {
|
||||
console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
|
||||
}
|
||||
window.localStorage.setItem('access_type', 'super');
|
||||
|
||||
let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
|
||||
$ae_loc.access_type = 'super';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.manager.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.manager == entered_passcode
|
||||
) {
|
||||
console.log('Manager passcode matched');
|
||||
|
||||
$ae_loc = { ...$ae_loc, ...access_checks_results };
|
||||
$ae_loc = $ae_loc;
|
||||
$ae_loc.sys_menu.expand = false;
|
||||
} else if (trigger) {
|
||||
trigger = false;
|
||||
if (log_lvl) {
|
||||
console.log(`$ae_loc.access_type=not set`);
|
||||
}
|
||||
window.localStorage.setItem('access_type', 'manager');
|
||||
|
||||
// Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
|
||||
let access_checks_results = ae_util.process_permission_checks('');
|
||||
$ae_loc.access_type = 'manager';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.administrator.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.administrator == entered_passcode
|
||||
) {
|
||||
console.log('Administrator passcode matched');
|
||||
|
||||
$ae_loc = { ...$ae_loc, ...access_checks_results };
|
||||
$ae_loc = $ae_loc;
|
||||
}
|
||||
});
|
||||
window.localStorage.setItem('access_type', 'administrator');
|
||||
|
||||
// This does not seem to work. I feel like it should though...?
|
||||
$effect(() => {
|
||||
if (!hide && focus_input) {
|
||||
focus_input = false;
|
||||
// log_lvl = 2;
|
||||
// await tick();
|
||||
// document.getElementById('access_passcode_input')?.focus();
|
||||
$ae_loc.access_type = 'administrator';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.trusted.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.trusted == entered_passcode
|
||||
) {
|
||||
console.log('Trusted passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'trusted');
|
||||
|
||||
$ae_loc.access_type = 'trusted';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.public.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.public == entered_passcode
|
||||
) {
|
||||
console.log('Public passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'public');
|
||||
|
||||
$ae_loc.access_type = 'public';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.authenticated == entered_passcode
|
||||
) {
|
||||
console.log('Authenticated passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'authenticated');
|
||||
|
||||
$ae_loc.access_type = 'authenticated';
|
||||
} else {
|
||||
if (log_lvl > 1) {
|
||||
console.log('Effect: Setting focus on the passcode input field');
|
||||
}
|
||||
/** @type {HTMLElement | null} */
|
||||
const to_focus = document.getElementById('access_passcode_input');
|
||||
to_focus?.focus();
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (trigger_clear_access) {
|
||||
trigger_clear_access = false;
|
||||
if (log_lvl) {
|
||||
console.log(`trigger_clear_access=${trigger_clear_access}`);
|
||||
}
|
||||
handle_clear_access();
|
||||
}
|
||||
});
|
||||
|
||||
function handle_check_access_type_passcode() {
|
||||
if (log_lvl > 1) {
|
||||
console.log(
|
||||
`*** handle_check_access_type_passcode() *** passcode list:`,
|
||||
$ae_loc.site_access_code_kv
|
||||
);
|
||||
}
|
||||
|
||||
// Reminder: super > manager > administrator > trusted > public > authenticated > anonymous
|
||||
|
||||
if (entered_passcode && entered_passcode.length >= 5) {
|
||||
if (
|
||||
$ae_loc.site_access_code_kv.super.length >= 8 &&
|
||||
$ae_loc.site_access_code_kv.super == entered_passcode
|
||||
) {
|
||||
console.log('Super passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'super');
|
||||
|
||||
$ae_loc.access_type = 'super';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.manager.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.manager == entered_passcode
|
||||
) {
|
||||
console.log('Manager passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'manager');
|
||||
|
||||
$ae_loc.access_type = 'manager';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.administrator.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.administrator == entered_passcode
|
||||
) {
|
||||
console.log('Administrator passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'administrator');
|
||||
|
||||
$ae_loc.access_type = 'administrator';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.trusted.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.trusted == entered_passcode
|
||||
) {
|
||||
console.log('Trusted passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'trusted');
|
||||
|
||||
$ae_loc.access_type = 'trusted';
|
||||
} else if (
|
||||
$ae_loc.site_access_code_kv.public.length >= 5 &&
|
||||
$ae_loc.site_access_code_kv.public == entered_passcode
|
||||
) {
|
||||
console.log('Public passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'public');
|
||||
|
||||
$ae_loc.access_type = 'public';
|
||||
} else if ($ae_loc.site_access_code_kv.authenticated == entered_passcode) {
|
||||
console.log('Authenticated passcode matched');
|
||||
|
||||
window.localStorage.setItem('access_type', 'authenticated');
|
||||
|
||||
$ae_loc.access_type = 'authenticated';
|
||||
} else {
|
||||
if (log_lvl > 1) {
|
||||
console.log('Entered passcode does not match any of the site access codes.');
|
||||
}
|
||||
|
||||
if ($ae_loc.access_type != 'anonymous') {
|
||||
console.log('Access type is not anonymous');
|
||||
}
|
||||
// window.localStorage.setItem('access_type', 'anonymous');
|
||||
|
||||
// $ae_loc.access_type = 'anonymous';
|
||||
|
||||
// trigger = 'process_permission_check';
|
||||
|
||||
// $ae_loc = $ae_loc; // Trigger Svelte just in case
|
||||
// ae_loc.set($ae_loc);
|
||||
// console.log($ae_loc);
|
||||
|
||||
// dispatch_access_type_changed();
|
||||
|
||||
return false;
|
||||
console.log(
|
||||
'Entered passcode does not match any of the site access codes.'
|
||||
);
|
||||
}
|
||||
|
||||
entered_passcode = '';
|
||||
show_passcode_input = false;
|
||||
trigger = 'process_permission_check';
|
||||
|
||||
$ae_loc.app_cfg.show_element__menu = false;
|
||||
$ae_loc.app_cfg.show_element__menu_btn = true;
|
||||
|
||||
// WARNING 2024-08-21: For some reason the config element does not auto show or hide when the access type changes.
|
||||
if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
|
||||
$ae_loc.app_cfg.show_element__access_type = true;
|
||||
$ae_loc.app_cfg.show_element__cfg = true;
|
||||
} else if ($ae_loc.iframe && $ae_loc.trusted_access) {
|
||||
$ae_loc.app_cfg.show_element__access_type = true;
|
||||
$ae_loc.app_cfg.show_element__cfg = true;
|
||||
} else {
|
||||
$ae_loc.app_cfg.show_element__access_type = true;
|
||||
$ae_loc.app_cfg.show_element__cfg = false;
|
||||
if ($ae_loc.access_type != 'anonymous') {
|
||||
console.log('Access type is not anonymous');
|
||||
}
|
||||
// window.localStorage.setItem('access_type', 'anonymous');
|
||||
|
||||
// $ae_loc.access_type = 'anonymous';
|
||||
|
||||
// trigger = 'process_permission_check';
|
||||
|
||||
// $ae_loc = $ae_loc; // Trigger Svelte just in case
|
||||
// ae_loc.set($ae_loc);
|
||||
// console.log($ae_loc);
|
||||
|
||||
// dispatch_access_type_changed();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (log_lvl > 1) {
|
||||
console.log('Entered passcode too short.');
|
||||
}
|
||||
|
||||
// $ae_loc.access_type = null; // 'anonymous';
|
||||
|
||||
// dispatch_access_type_changed()
|
||||
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function handle_clear_access() {
|
||||
// console.log('handle_clear_access()');
|
||||
// NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
|
||||
window.localStorage.setItem('access_type', 'anonymous');
|
||||
|
||||
// $ae_loc.access_type = null; // 'anonymous';
|
||||
// Revert back to the user's access type after quick access (temporarily escalate permissions) is turned off.
|
||||
$ae_loc.access_type = $ae_loc.user_access_type ?? 'anonymous';
|
||||
entered_passcode = '';
|
||||
show_passcode_input = false;
|
||||
trigger = 'process_permission_check';
|
||||
|
||||
entered_passcode = ''; // Clear the entered passcode
|
||||
// Reset so the same passcode can be re-entered after clearing.
|
||||
// Without this, the $effect guard (entered_passcode != checked_passcode) silently
|
||||
// blocks re-entry of the same passcode until the component remounts (page refresh).
|
||||
checked_passcode = null;
|
||||
show_passcode_input = true;
|
||||
|
||||
$ae_loc.app_cfg.show_element__menu = false;
|
||||
$ae_loc.app_cfg.show_element__menu_btn = true;
|
||||
|
||||
$ae_loc.edit_mode = false;
|
||||
// WARNING 2024-08-21: For some reason the config element does not auto show or hide when the access type changes.
|
||||
if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
|
||||
$ae_loc.app_cfg.show_element__access_type = true;
|
||||
$ae_loc.app_cfg.show_element__cfg = true;
|
||||
} else if ($ae_loc.iframe && $ae_loc.trusted_access) {
|
||||
$ae_loc.app_cfg.show_element__access_type = true;
|
||||
$ae_loc.app_cfg.show_element__cfg = true;
|
||||
} else {
|
||||
$ae_loc.app_cfg.show_element__access_type = true;
|
||||
$ae_loc.app_cfg.show_element__cfg = false;
|
||||
}
|
||||
|
||||
// dispatch_access_type_changed();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (log_lvl > 1) {
|
||||
console.log('Entered passcode too short.');
|
||||
}
|
||||
|
||||
// $ae_loc.access_type = null; // 'anonymous';
|
||||
|
||||
// dispatch_access_type_changed()
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function handle_clear_access() {
|
||||
// console.log('handle_clear_access()');
|
||||
// NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
|
||||
window.localStorage.setItem('access_type', 'anonymous');
|
||||
|
||||
// $ae_loc.access_type = null; // 'anonymous';
|
||||
// Revert back to the user's access type after quick access (temporarily escalate permissions) is turned off.
|
||||
$ae_loc.access_type = $ae_loc.user_access_type ?? 'anonymous';
|
||||
trigger = 'process_permission_check';
|
||||
|
||||
entered_passcode = ''; // Clear the entered passcode
|
||||
// Reset so the same passcode can be re-entered after clearing.
|
||||
// Without this, the $effect guard (entered_passcode != checked_passcode) silently
|
||||
// blocks re-entry of the same passcode until the component remounts (page refresh).
|
||||
checked_passcode = null;
|
||||
show_passcode_input = true;
|
||||
|
||||
$ae_loc.app_cfg.show_element__menu = false;
|
||||
$ae_loc.app_cfg.show_element__menu_btn = true;
|
||||
|
||||
$ae_loc.edit_mode = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<section
|
||||
@@ -298,24 +323,23 @@
|
||||
ae_access_type
|
||||
hidden-print
|
||||
|
||||
bg-blue-100 text-gray-900
|
||||
dark:bg-blue-800 dark:text-gray-200
|
||||
flex w-full
|
||||
flex-col flex-wrap
|
||||
|
||||
flex flex-col flex-wrap gap-1
|
||||
items-end justify-center
|
||||
items-end justify-center gap-1 border-2
|
||||
border-gray-200 bg-blue-100
|
||||
|
||||
w-full
|
||||
p-1
|
||||
border-2 border-gray-200
|
||||
text-gray-900
|
||||
transition-all delay-150
|
||||
|
||||
duration-300 delay-150 hover:delay-1000 hover:ease-out
|
||||
transition-all
|
||||
duration-300 hover:delay-1000 hover:ease-out dark:bg-blue-800
|
||||
dark:text-gray-200
|
||||
"
|
||||
class:hidden={hide}
|
||||
>
|
||||
class:hidden={hide}>
|
||||
<!-- class:hidden={!$ae_sess.show__sign_in_out__fields} -->
|
||||
<header class="ae_header hidden">
|
||||
<h2 class="text-sm text-center font-semibold">Passcode Sign In</h2>
|
||||
<h2 class="text-center text-sm font-semibold">Passcode Sign In</h2>
|
||||
</header>
|
||||
|
||||
<!-- Show list of authorized sessions and presentations for a user -->
|
||||
@@ -349,9 +373,8 @@
|
||||
// tick();
|
||||
return false;
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-success border border-success-500 hover:preset-filled-success-500 transition-all hover:transition-all *:hover:inline"
|
||||
title="Syncing the local configuration with the remote configuration."
|
||||
>
|
||||
class="btn btn-sm preset-tonal-success border-success-500 hover:preset-filled-success-500 border transition-all hover:transition-all *:hover:inline"
|
||||
title="Syncing the local configuration with the remote configuration.">
|
||||
<RefreshCw size="1em" class="m-1" />
|
||||
<span class="hidden"> Sync </span>
|
||||
</button>
|
||||
@@ -369,9 +392,8 @@
|
||||
// tick();
|
||||
return true;
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-warning border border-warning-500 hover:preset-filled-warning-500 transition-all hover:transition-all *:hover:inline"
|
||||
title="Currently not syncing with the remote server. Re-sync the local configuration with the remote configuration?"
|
||||
>
|
||||
class="btn btn-sm preset-tonal-warning border-warning-500 hover:preset-filled-warning-500 border transition-all hover:transition-all *:hover:inline"
|
||||
title="Currently not syncing with the remote server. Re-sync the local configuration with the remote configuration?">
|
||||
<Unlink size="1em" class="m-1" />
|
||||
<span class="hidden"> Re-sync? </span>
|
||||
</button>
|
||||
@@ -411,7 +433,8 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-1 items-end justify-end w-full transition-all">
|
||||
<div
|
||||
class="flex w-full flex-row flex-wrap items-end justify-end gap-1 transition-all">
|
||||
{#if $ae_loc?.access_type && $ae_loc?.access_type == 'anonymous'}
|
||||
<span>
|
||||
<button
|
||||
@@ -421,15 +444,16 @@
|
||||
show_passcode_input = !show_passcode_input;
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-success hover:preset-filled-warning-500 access_type_unlock_btn transition-all"
|
||||
title={show_passcode_input ? 'Cancel passcode entry' : 'Enter a passcode to unlock access'}
|
||||
>
|
||||
title={show_passcode_input
|
||||
? 'Cancel passcode entry'
|
||||
: 'Enter a passcode to unlock access'}>
|
||||
{#if show_passcode_input}
|
||||
<LockOpen size="1em" class="mx-1" />
|
||||
<span>Cancel</span>
|
||||
{:else}
|
||||
<Lock size="1em" class="mx-1" />
|
||||
<span class="lock_icon">Locked</span>
|
||||
<LockOpen size="1em" class="mx-1 unlock_icon hidden" />
|
||||
<LockOpen size="1em" class="unlock_icon mx-1 hidden" />
|
||||
<span class="unlock_text">Access?</span>
|
||||
{/if}
|
||||
</button>
|
||||
@@ -437,14 +461,13 @@
|
||||
{/if}
|
||||
|
||||
{#if $ae_loc?.access_type && $ae_loc?.access_type != 'anonymous'}
|
||||
<span class="flex flex-row gap-1 items-center justify-center">
|
||||
<span class="flex flex-row items-center justify-center gap-1">
|
||||
<!-- <span class="fas fa-unlock mx-1"></span> -->
|
||||
<ShieldPlus class="inline-block" />
|
||||
|
||||
<span
|
||||
class="*:hover:inline"
|
||||
title={`Current access type/level: ${$ae_loc.access_type}`}
|
||||
>
|
||||
title={`Current access type/level: ${$ae_loc.access_type}`}>
|
||||
{#if $ae_loc.access_type == 'super'}
|
||||
<Wand2 size="1em" class="m-1" />
|
||||
<span class="hidden">Super</span>
|
||||
@@ -478,9 +501,8 @@
|
||||
// trigger_clear_access = true;
|
||||
show_passcode_input = true;
|
||||
}}
|
||||
class="btn btn-sm variant-outline-surface hover:preset-tonal-warning border border-warning-500 transition-all"
|
||||
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}
|
||||
>
|
||||
class="btn btn-sm variant-outline-surface hover:preset-tonal-warning border-warning-500 border transition-all"
|
||||
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}>
|
||||
<!-- <span class="fas fa-lock mx-1"></span> -->
|
||||
<!-- <ShieldMinus /> -->
|
||||
<ShieldEllipsis class="inline-block" />
|
||||
@@ -495,9 +517,8 @@
|
||||
show_passcode_input = true;
|
||||
// show_passcode_input = true;
|
||||
}}
|
||||
class="btn btn-sm variant-outline-warning hover:preset-tonal-warning border border-warning-500 transition-all"
|
||||
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}
|
||||
>
|
||||
class="btn btn-sm variant-outline-warning hover:preset-tonal-warning border-warning-500 border transition-all"
|
||||
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}>
|
||||
<!-- <span class="fas fa-lock mx-1"></span> -->
|
||||
<ShieldMinus class="inline-block" />
|
||||
Clear?
|
||||
@@ -507,7 +528,8 @@
|
||||
{/if}
|
||||
|
||||
{#if show_passcode_input}
|
||||
<span class="flex flex-row gap-1 items-center justify-between w-full">
|
||||
<span
|
||||
class="flex w-full flex-row items-center justify-between gap-1">
|
||||
<span>
|
||||
<ShieldEllipsis class="inline-block text-gray-500" />
|
||||
<span class="unlock_text text-sm">Passcode:</span>
|
||||
@@ -521,8 +543,7 @@
|
||||
class:hidden={!show_passcode_input}
|
||||
type="text"
|
||||
placeholder="Passcode"
|
||||
autofocus={show_passcode_input}
|
||||
/>
|
||||
autofocus={show_passcode_input} />
|
||||
<!-- <div class="current_text transition-all">{$ae_loc.access_type}</div> -->
|
||||
</span>
|
||||
{/if}
|
||||
@@ -530,8 +551,8 @@
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
/* BEGIN: AE's Svelte Quick Access Type component */
|
||||
/*
|
||||
/* BEGIN: AE's Svelte Quick Access Type component */
|
||||
/*
|
||||
#xxx-AE-Quick-Access-Type {
|
||||
// position: absolute;
|
||||
position: fixed;
|
||||
@@ -569,7 +590,7 @@
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
#xxx-AE-Quick-Access-Type:hover {
|
||||
|
||||
border-top: solid thin hsla(0,0%,0%,.95);
|
||||
@@ -586,21 +607,21 @@
|
||||
}
|
||||
*/
|
||||
|
||||
/* #Access-Type .unlock_text {
|
||||
/* #Access-Type .unlock_text {
|
||||
transition: width 2s, height 2s, background-color 2s, transform 2s;
|
||||
} */
|
||||
/* END: Svelte Access Type component */
|
||||
/* END: Svelte Access Type component */
|
||||
|
||||
.access_type_unlock_btn .unlock_text {
|
||||
display: none;
|
||||
}
|
||||
.access_type_unlock_btn .unlock_text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.access_type_unlock_btn:hover .unlock_text {
|
||||
display: initial;
|
||||
/* outline: solid thin red; */
|
||||
}
|
||||
.access_type_unlock_btn:hover .unlock_text {
|
||||
display: initial;
|
||||
/* outline: solid thin red; */
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
.ae_access_type .current_text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
<script lang="ts" module>
|
||||
declare global {
|
||||
interface Window {
|
||||
dataLayer: any[];
|
||||
gtag: (...args: any[]) => void;
|
||||
}
|
||||
declare global {
|
||||
interface Window {
|
||||
dataLayer: any[];
|
||||
gtag: (...args: any[]) => void;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
site_google_tracking_id?: string;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
site_google_tracking_id?: string;
|
||||
}
|
||||
|
||||
let { log_lvl = 0, site_google_tracking_id = $bindable('') }: Props = $props();
|
||||
let { log_lvl = 0, site_google_tracking_id = $bindable('') }: Props = $props();
|
||||
|
||||
$effect(() => {
|
||||
if (browser && site_google_tracking_id) {
|
||||
if (log_lvl) {
|
||||
console.log(`AE Analytics: site_google_tracking_id = `, site_google_tracking_id);
|
||||
}
|
||||
$effect(() => {
|
||||
if (browser && site_google_tracking_id) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`AE Analytics: site_google_tracking_id = `,
|
||||
site_google_tracking_id
|
||||
);
|
||||
}
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.gtag = window.gtag || function gtag() {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.gtag =
|
||||
window.gtag ||
|
||||
function gtag() {
|
||||
window.dataLayer.push(arguments);
|
||||
};
|
||||
window.gtag('js', new Date());
|
||||
window.gtag('config', site_google_tracking_id);
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`AE Analytics: Google Analytics Tracking ID = `, site_google_tracking_id);
|
||||
}
|
||||
window.gtag('js', new Date());
|
||||
window.gtag('config', site_google_tracking_id);
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`AE Analytics: Google Analytics Tracking ID = `,
|
||||
site_google_tracking_id
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
{#if site_google_tracking_id}
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={site_google_tracking_id}"></script>
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id={site_google_tracking_id}"></script>
|
||||
{/if}
|
||||
</svelte:head>
|
||||
|
||||
@@ -1,103 +1,120 @@
|
||||
<script lang="ts">
|
||||
import { Code, Eraser, LockOpen, RefreshCw, Settings, ShieldCheck, ShieldUser, Trash2, UserRound, Users } from '@lucide/svelte';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
import E_app_url_builder from '$lib/app_components/e_app_url_builder.svelte';
|
||||
import {
|
||||
Code,
|
||||
Eraser,
|
||||
LockOpen,
|
||||
RefreshCw,
|
||||
Settings,
|
||||
ShieldCheck,
|
||||
ShieldUser,
|
||||
Trash2,
|
||||
UserRound,
|
||||
Users
|
||||
} from '@lucide/svelte';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
import E_app_url_builder from '$lib/app_components/e_app_url_builder.svelte';
|
||||
|
||||
// import Element_theme from '$lib/e_app_theme.svelte';
|
||||
// import Element_theme from '$lib/e_app_theme.svelte';
|
||||
|
||||
let notes: null | string = null;
|
||||
let all: boolean = false;
|
||||
let notes: null | string = null;
|
||||
let all: boolean = false;
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
// export let theme_mode: null|string = null;
|
||||
// set_theme_mode?: null|boolean;
|
||||
// export let theme_name: null|string = null;
|
||||
// set_theme_name?: null|boolean;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
// export let theme_mode: null|string = null;
|
||||
// set_theme_mode?: null|boolean;
|
||||
// export let theme_name: null|string = null;
|
||||
// set_theme_name?: null|boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false)
|
||||
// set_theme_mode = null,
|
||||
// set_theme_name = null
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false)
|
||||
// set_theme_mode = null,
|
||||
// set_theme_name = null
|
||||
}: Props = $props();
|
||||
|
||||
// const dispatch = createEventDispatcher();
|
||||
// const dispatch = createEventDispatcher();
|
||||
|
||||
// onMount(() => {
|
||||
// // console.log('** Element Mounted: ** Element App Config');
|
||||
// if (set_theme_mode) {
|
||||
// $slct_trigger = 'set_theme_mode';
|
||||
// }
|
||||
// if (set_theme_name) {
|
||||
// $slct_trigger = 'set_theme_name';
|
||||
// }
|
||||
// });
|
||||
// onMount(() => {
|
||||
// // console.log('** Element Mounted: ** Element App Config');
|
||||
// if (set_theme_mode) {
|
||||
// $slct_trigger = 'set_theme_mode';
|
||||
// }
|
||||
// if (set_theme_name) {
|
||||
// $slct_trigger = 'set_theme_name';
|
||||
// }
|
||||
// });
|
||||
|
||||
// $: if ($slct_trigger == 'set_theme_mode' && $ae_loc?.app_cfg?.theme_mode) {
|
||||
// console.log(`$ae_loc.app_cfg.theme_mode=${$ae_loc?.app_cfg?.theme_mode}`);
|
||||
// $slct_trigger = null;
|
||||
// if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
// document.documentElement.classList.remove('dark');
|
||||
// document.documentElement.classList.add('light');
|
||||
// } else if ($ae_loc.app_cfg.theme_mode == 'dark') {
|
||||
// document.documentElement.classList.remove('light');
|
||||
// document.documentElement.classList.add('dark');
|
||||
// }
|
||||
// }
|
||||
// $: if ($slct_trigger == 'set_theme_mode' && $ae_loc?.app_cfg?.theme_mode) {
|
||||
// console.log(`$ae_loc.app_cfg.theme_mode=${$ae_loc?.app_cfg?.theme_mode}`);
|
||||
// $slct_trigger = null;
|
||||
// if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
// document.documentElement.classList.remove('dark');
|
||||
// document.documentElement.classList.add('light');
|
||||
// } else if ($ae_loc.app_cfg.theme_mode == 'dark') {
|
||||
// document.documentElement.classList.remove('light');
|
||||
// document.documentElement.classList.add('dark');
|
||||
// }
|
||||
// }
|
||||
|
||||
// $: if ($slct_trigger == 'set_theme_name' && $ae_loc?.app_cfg?.theme_name) {
|
||||
// console.log(`$ae_loc?.app_cfg?.theme_name=${$ae_loc?.app_cfg?.theme_name}`);
|
||||
// $slct_trigger = null;
|
||||
// // Update the body attribute named "data-theme" to the current theme name.
|
||||
// document.body.setAttribute('data-theme', $ae_loc?.app_cfg?.theme_name);
|
||||
// }
|
||||
// $: if ($slct_trigger == 'set_theme_name' && $ae_loc?.app_cfg?.theme_name) {
|
||||
// console.log(`$ae_loc?.app_cfg?.theme_name=${$ae_loc?.app_cfg?.theme_name}`);
|
||||
// $slct_trigger = null;
|
||||
// // Update the body attribute named "data-theme" to the current theme name.
|
||||
// document.body.setAttribute('data-theme', $ae_loc?.app_cfg?.theme_name);
|
||||
// }
|
||||
|
||||
// $: if (entered_passcode && entered_passcode.length >= 5) {
|
||||
// console.log(`entered_passcode=${entered_passcode}`);
|
||||
// handle_check_access_type_passcode();
|
||||
// }
|
||||
// $: if (entered_passcode && entered_passcode.length >= 5) {
|
||||
// console.log(`entered_passcode=${entered_passcode}`);
|
||||
// handle_check_access_type_passcode();
|
||||
// }
|
||||
|
||||
// $: if (trigger && $ae_loc.access_type) {
|
||||
// console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
|
||||
// $: if (trigger && $ae_loc.access_type) {
|
||||
// console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
|
||||
|
||||
// let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
|
||||
// let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
|
||||
|
||||
// $ae_loc = {...$ae_loc, ...access_checks_results};
|
||||
// } else if (trigger) {
|
||||
// console.log(`$ae_loc.access_type=not set`);
|
||||
// $ae_loc = {...$ae_loc, ...access_checks_results};
|
||||
// } else if (trigger) {
|
||||
// console.log(`$ae_loc.access_type=not set`);
|
||||
|
||||
// // Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
|
||||
// let access_checks_results = ae_util.process_permission_checks('');
|
||||
// // Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
|
||||
// let access_checks_results = ae_util.process_permission_checks('');
|
||||
|
||||
// $ae_loc = {...$ae_loc, ...access_checks_results};
|
||||
// }
|
||||
// $ae_loc = {...$ae_loc, ...access_checks_results};
|
||||
// }
|
||||
|
||||
function handle_something() {
|
||||
// console.log('*** handle_something() ***');
|
||||
}
|
||||
function handle_something() {
|
||||
// console.log('*** handle_something() ***');
|
||||
}
|
||||
|
||||
function handle_clear_storage(item: null | string) {
|
||||
// console.log('*** handle_clear_storage() ***');
|
||||
// window.localStorage.setItem('access_type', 'anonymous');
|
||||
// return true;
|
||||
}
|
||||
function handle_clear_storage(item: null | string) {
|
||||
// console.log('*** handle_clear_storage() ***');
|
||||
// window.localStorage.setItem('access_type', 'anonymous');
|
||||
// return true;
|
||||
}
|
||||
|
||||
// function dispatch_something_changed() {
|
||||
// console.log('*** dispatch_something_changed() ***');
|
||||
// function dispatch_something_changed() {
|
||||
// console.log('*** dispatch_something_changed() ***');
|
||||
|
||||
// console.log(ae_util);
|
||||
// console.log($ae_loc);
|
||||
// console.log(ae_util);
|
||||
// console.log($ae_loc);
|
||||
|
||||
// dispatch('access_type_changed', {
|
||||
// access_type: $ae_loc.access_type
|
||||
// });
|
||||
// }
|
||||
// dispatch('access_type_changed', {
|
||||
// access_type: $ae_loc.access_type
|
||||
// });
|
||||
// }
|
||||
</script>
|
||||
|
||||
<!-- transition duration-500 delay-1000 hover:duration-500 hover:delay-1000 hover:transition-all -->
|
||||
@@ -107,30 +124,28 @@
|
||||
ae_app_cfg
|
||||
hidden-print
|
||||
|
||||
bg-blue-100 text-gray-900
|
||||
dark:bg-blue-800 dark:text-gray-200
|
||||
flex w-72
|
||||
max-w-72 flex-col
|
||||
|
||||
flex flex-col flex-wrap gap-1
|
||||
items-end justify-center
|
||||
|
||||
w-72 max-w-72
|
||||
p-1
|
||||
flex-wrap items-end justify-center gap-1
|
||||
border-2 border-gray-200
|
||||
|
||||
duration-300 delay-150 hover:delay-1000 hover:ease-out
|
||||
transition-all
|
||||
bg-blue-100 p-1
|
||||
text-gray-900
|
||||
transition-all delay-150
|
||||
|
||||
duration-300 hover:delay-1000 hover:ease-out dark:bg-blue-800
|
||||
dark:text-gray-200
|
||||
"
|
||||
class:hidden={hide}
|
||||
>
|
||||
class:hidden={hide}>
|
||||
<header class:hidden={!expand} class="ae_header w-full">
|
||||
<h2 class="text-sm text-center font-semibold">Config</h2>
|
||||
<h2 class="text-center text-sm font-semibold">Config</h2>
|
||||
</header>
|
||||
|
||||
<div
|
||||
class="ae_cfg_content text-xs space-y-4 my-4"
|
||||
class="ae_cfg_content my-4 space-y-4 text-xs"
|
||||
class:hidden={!expand}
|
||||
data-sveltekit-preload-data="false"
|
||||
>
|
||||
data-sveltekit-preload-data="false">
|
||||
<section class="space-y-2">
|
||||
<div>
|
||||
<h2 class="strong">Access Type:</h2>
|
||||
@@ -172,12 +187,16 @@
|
||||
</a>
|
||||
|
||||
{#if $ae_loc.iframe}
|
||||
<a class="btn btn-sm preset-tonal-secondary" href="/?iframe=false">
|
||||
<a
|
||||
class="btn btn-sm preset-tonal-secondary"
|
||||
href="/?iframe=false">
|
||||
<Code size="1em" class="mx-1" />
|
||||
Exit iframe Mode
|
||||
</a>
|
||||
{:else}
|
||||
<a class="btn btn-sm preset-tonal-secondary" href="/?iframe=true">
|
||||
<a
|
||||
class="btn btn-sm preset-tonal-secondary"
|
||||
href="/?iframe=true">
|
||||
<Code size="1em" class="mx-1" />
|
||||
Use iframe Mode
|
||||
</a>
|
||||
@@ -190,8 +209,7 @@
|
||||
onclick={() => {
|
||||
// $ae_loc.
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<RefreshCw size="1em" class="mx-1" />
|
||||
Reload &
|
||||
<Trash2 size="1em" class="mx-1" />
|
||||
@@ -219,8 +237,7 @@
|
||||
|
||||
window.location.reload();
|
||||
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<Eraser size="1em" class="mx-1" />
|
||||
Clear Storage & DB
|
||||
</button>
|
||||
@@ -235,7 +252,7 @@
|
||||
|
||||
<!-- class:justify-between={expand}
|
||||
class:justify-end={!expand} -->
|
||||
<div class="flex flex-row gap-2 items-center justify-between w-full">
|
||||
<div class="flex w-full flex-row items-center justify-between gap-2">
|
||||
<!-- {#if !expand} -->
|
||||
<span>
|
||||
{#if $ae_loc.access_type && $ae_loc.access_type != 'anonymous'}
|
||||
@@ -270,14 +287,13 @@ class:justify-end={!expand} -->
|
||||
<button
|
||||
class="
|
||||
ae_cfg_btn
|
||||
btn btn-sm text-sm
|
||||
preset-tonal-warning
|
||||
group transition-all
|
||||
btn btn-sm preset-tonal-warning
|
||||
group
|
||||
text-sm transition-all
|
||||
"
|
||||
onclick={() => {
|
||||
expand = !expand;
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<!-- <span class="fas fa-cog m-1"></span> -->
|
||||
<span class="inline-block" title="Settings">
|
||||
<Settings class="m-1" />
|
||||
@@ -287,8 +303,7 @@ class:justify-end={!expand} -->
|
||||
cfg_text
|
||||
hidden
|
||||
group-hover:inline
|
||||
"
|
||||
>
|
||||
">
|
||||
Settings
|
||||
</span>
|
||||
</button>
|
||||
@@ -296,21 +311,21 @@ class:justify-end={!expand} -->
|
||||
</section>
|
||||
|
||||
<style lang="postcss">
|
||||
.ae_cfg_btn .cfg_text {
|
||||
/* display: none; */
|
||||
}
|
||||
.ae_cfg_btn .cfg_text {
|
||||
/* display: none; */
|
||||
}
|
||||
|
||||
.ae_cfg_btn:hover .cfg_text {
|
||||
/* display: initial; */
|
||||
/* outline: solid thin red; */
|
||||
}
|
||||
.ae_cfg_btn:hover .cfg_text {
|
||||
/* display: initial; */
|
||||
/* outline: solid thin red; */
|
||||
}
|
||||
|
||||
/* .access_type .current_text {
|
||||
/* .access_type .current_text {
|
||||
display: none;
|
||||
} */
|
||||
|
||||
/* .access_type:hover .current_text {
|
||||
/* .access_type:hover .current_text {
|
||||
display: initial;
|
||||
} */
|
||||
/* END: AE's Svelte App Config component */
|
||||
/* END: AE's Svelte App Config component */
|
||||
</style>
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet;
|
||||
log_lvl?: number;
|
||||
value: any;
|
||||
success?: boolean;
|
||||
btn_text?: string;
|
||||
btn_title?: string;
|
||||
btn_class?: string;
|
||||
hide_icon?: boolean;
|
||||
hide_text?: boolean;
|
||||
icon_name?: string;
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet;
|
||||
log_lvl?: number;
|
||||
value: any;
|
||||
success?: boolean;
|
||||
btn_text?: string;
|
||||
btn_title?: string;
|
||||
btn_class?: string;
|
||||
hide_icon?: boolean;
|
||||
hide_text?: boolean;
|
||||
icon_name?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
children,
|
||||
log_lvl = 0,
|
||||
value = $bindable(''),
|
||||
success = $bindable(false),
|
||||
btn_text = 'Copy to Clipboard',
|
||||
btn_title = 'Copy to Clipboard',
|
||||
btn_class = 'btn btn-sm preset-tonal-warning text-warning-500 m-1',
|
||||
hide_icon = false,
|
||||
hide_text = false,
|
||||
icon_name = 'copy' // copy, check, link
|
||||
}: Props = $props();
|
||||
|
||||
// *** Import Svelte specific
|
||||
// import { browser } from '$app/environment';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import {
|
||||
// ArrowBigRight,
|
||||
// CircleX,
|
||||
CircleCheck,
|
||||
Copy,
|
||||
// Eye, EyeOff,
|
||||
// Key,
|
||||
Link
|
||||
// LogIn, LogOut, LockKeyhole,
|
||||
// Mail, MailCheck,
|
||||
// Menu,
|
||||
// RefreshCw, RefreshCcw, RefreshCcwDot,
|
||||
// ShieldEllipsis, ShieldMinus, ShieldPlus, ShieldUser,
|
||||
// User, UserCheck
|
||||
} from '@lucide/svelte';
|
||||
|
||||
$effect(() => {
|
||||
if (log_lvl) {
|
||||
console.log(`Clipboard component initialized with value:`, value);
|
||||
}
|
||||
});
|
||||
|
||||
let {
|
||||
children,
|
||||
log_lvl = 0,
|
||||
value = $bindable(''),
|
||||
success = $bindable(false),
|
||||
btn_text = 'Copy to Clipboard',
|
||||
btn_title = 'Copy to Clipboard',
|
||||
btn_class = 'btn btn-sm preset-tonal-warning text-warning-500 m-1',
|
||||
hide_icon = false,
|
||||
hide_text = false,
|
||||
icon_name = 'copy' // copy, check, link
|
||||
}: Props = $props();
|
||||
// Select your trigger element
|
||||
// const elemButton: HTMLButtonElement | null = document.querySelector('[data-button]');
|
||||
|
||||
// *** Import Svelte specific
|
||||
// import { browser } from '$app/environment';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import {
|
||||
// ArrowBigRight,
|
||||
// CircleX,
|
||||
CircleCheck,
|
||||
Copy,
|
||||
// Eye, EyeOff,
|
||||
// Key,
|
||||
Link
|
||||
// LogIn, LogOut, LockKeyhole,
|
||||
// Mail, MailCheck,
|
||||
// Menu,
|
||||
// RefreshCw, RefreshCcw, RefreshCcwDot,
|
||||
// ShieldEllipsis, ShieldMinus, ShieldPlus, ShieldUser,
|
||||
// User, UserCheck
|
||||
} from '@lucide/svelte';
|
||||
|
||||
$effect(() => {
|
||||
if (log_lvl) {
|
||||
console.log(`Clipboard component initialized with value:`, value);
|
||||
}
|
||||
});
|
||||
|
||||
// Select your trigger element
|
||||
// const elemButton: HTMLButtonElement | null = document.querySelector('[data-button]');
|
||||
|
||||
// Add a click event handler to the trigger
|
||||
// elemButton?.addEventListener('click', () => {
|
||||
// // Call the Clipboard API
|
||||
// navigator.clipboard
|
||||
// // Use the `writeText` method write content to the clipboard
|
||||
// .writeText(value)
|
||||
// // Handle confirmation
|
||||
// .then(() => {
|
||||
// if (log_lvl) {
|
||||
// console.log(`Clipboard write successful: ${value}`);
|
||||
// }
|
||||
// success = true;
|
||||
// });
|
||||
// });
|
||||
// Add a click event handler to the trigger
|
||||
// elemButton?.addEventListener('click', () => {
|
||||
// // Call the Clipboard API
|
||||
// navigator.clipboard
|
||||
// // Use the `writeText` method write content to the clipboard
|
||||
// .writeText(value)
|
||||
// // Handle confirmation
|
||||
// .then(() => {
|
||||
// if (log_lvl) {
|
||||
// console.log(`Clipboard write successful: ${value}`);
|
||||
// }
|
||||
// success = true;
|
||||
// });
|
||||
// });
|
||||
</script>
|
||||
|
||||
<button
|
||||
@@ -93,15 +93,20 @@
|
||||
// }
|
||||
}}
|
||||
class={btn_class}
|
||||
title={btn_title}
|
||||
>
|
||||
title={btn_title}>
|
||||
<!-- {@render btn_text} -->
|
||||
{#if icon_name === 'link'}
|
||||
<Link class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}" size="1.2em" />
|
||||
<Link
|
||||
class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}"
|
||||
size="1.2em" />
|
||||
{:else if icon_name === 'check'}
|
||||
<CircleCheck class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}" size="1.2em" />
|
||||
<CircleCheck
|
||||
class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}"
|
||||
size="1.2em" />
|
||||
{:else}
|
||||
<Copy class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}" size="1.2em" />
|
||||
<Copy
|
||||
class="mx-1 {hide_icon ? 'hidden' : 'inline-block'}"
|
||||
size="1.2em" />
|
||||
{/if}
|
||||
<span class={hide_text ? 'hidden' : 'inline-block'}>
|
||||
{btn_text}
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
<script lang="ts">
|
||||
// *** Import Svelte specific
|
||||
// *** Import Svelte specific
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import { Bug, CircleX, Info, ToggleLeft, ToggleRight, X } from '@lucide/svelte';
|
||||
// *** Import other supporting libraries
|
||||
import { Bug, CircleX, Info, ToggleLeft, ToggleRight, X } from '@lucide/svelte';
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
// *** Import Aether specific variables and functions
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
|
||||
// *** Setup Svelte properties
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
}
|
||||
// *** Setup Svelte properties
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false)
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false)
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<!-- App Debug Menu -->
|
||||
@@ -31,28 +37,28 @@ hover:opacity-100 -->
|
||||
ae_app__debug_menu
|
||||
|
||||
hidden-print
|
||||
z-50
|
||||
absolute bottom-0 left-0
|
||||
md:text-md
|
||||
lg:text-md xl:text-md transition-delay-1000
|
||||
|
||||
flex
|
||||
text-sm sm:text-sm md:text-md lg:text-md xl:text-md 2xl:text-lg
|
||||
|
||||
dark:text-slate-400 dark:hover:text-slate-200
|
||||
bg-red-100/60 dark:bg-red-800/50
|
||||
hover:bg-red-200 hover:dark:bg-red-900
|
||||
|
||||
mx-1 my-2
|
||||
max-h-min
|
||||
max-w-lg
|
||||
transition-all
|
||||
transition-delay-1000
|
||||
transition-duration-1000
|
||||
absolute bottom-0 left-0 z-50 mx-1 my-2
|
||||
|
||||
flex max-h-min
|
||||
max-w-lg border-2
|
||||
border-red-300 bg-red-100/60
|
||||
|
||||
text-sm transition-all
|
||||
ease-in
|
||||
hover:border-red-500
|
||||
hover:bg-red-200
|
||||
sm:text-sm
|
||||
2xl:text-lg
|
||||
dark:border-red-700
|
||||
|
||||
|
||||
border-2
|
||||
border-red-300 dark:border-red-700
|
||||
hover:border-red-500 hover:dark:border-red-500
|
||||
dark:bg-red-800/50
|
||||
dark:text-slate-400 hover:dark:border-red-500
|
||||
hover:dark:bg-red-900 dark:hover:text-slate-200
|
||||
"
|
||||
class:top-0={expand}
|
||||
class:w-full={expand}
|
||||
@@ -60,29 +66,27 @@ hover:opacity-100 -->
|
||||
class:border-transparent={!expand}
|
||||
class:dark:border-transparent={!expand}
|
||||
class:hover:border-transparent={!expand}
|
||||
class:hover:bg-transparent={!expand}
|
||||
>
|
||||
class:hover:bg-transparent={!expand}>
|
||||
<div
|
||||
class:hidden={!expand}
|
||||
class:border-red-200={expand}
|
||||
class:dark:border-red-800={expand}
|
||||
class="
|
||||
|
||||
transition-all
|
||||
transition-delay-1000
|
||||
transition-duration-1000
|
||||
ease-in
|
||||
overflow-y-auto
|
||||
px-1 py-4
|
||||
opacity-50
|
||||
hover:opacity-100
|
||||
relative
|
||||
"
|
||||
>
|
||||
overflow-y-auto
|
||||
px-1
|
||||
py-4 opacity-50
|
||||
transition-all
|
||||
ease-in
|
||||
hover:opacity-100
|
||||
">
|
||||
<!-- flex flex-col items-center justify-center max-h-full outline -->
|
||||
<div>
|
||||
<!-- <span class="fas fa-bug mx-1"></span> -->
|
||||
<Bug class="inline-block mx-1" />
|
||||
<Bug class="mx-1 inline-block" />
|
||||
<span>Debug</span>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +95,8 @@ hover:opacity-100 -->
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<span class="absolute top-0 right-0 flex flex-row gap-1 items-center justify-center">
|
||||
<span
|
||||
class="absolute top-0 right-0 flex flex-row items-center justify-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
@@ -104,16 +109,21 @@ hover:opacity-100 -->
|
||||
hover:preset-tonal-success
|
||||
transition-all
|
||||
"
|
||||
title="Turn debug content and styles off and on"
|
||||
>
|
||||
title="Turn debug content and styles off and on">
|
||||
{#if $ae_loc?.debug_mode}
|
||||
<!-- <span class="fas fa-toggle-on mx-1"></span> -->
|
||||
<ToggleRight strokeWidth="2.5" color="green" class="inline-block mx-1" />
|
||||
<ToggleRight
|
||||
strokeWidth="2.5"
|
||||
color="green"
|
||||
class="mx-1 inline-block" />
|
||||
<span>Debug</span>
|
||||
<span class="hidden"> Mode On </span>
|
||||
{:else}
|
||||
<!-- <span class="fas fa-toggle-off mx-1"></span> -->
|
||||
<ToggleLeft strokeWidth="1" color="gray" class="inline-block mx-1" />
|
||||
<ToggleLeft
|
||||
strokeWidth="1"
|
||||
color="gray"
|
||||
class="mx-1 inline-block" />
|
||||
<span>Debug?</span>
|
||||
<span class="hidden"> Mode Off </span>
|
||||
{/if}
|
||||
@@ -137,10 +147,9 @@ hover:opacity-100 -->
|
||||
preset-outlined-surface-400-600 preset-filled-suface-200-800
|
||||
hover:preset-tonal-success
|
||||
transition-all
|
||||
"
|
||||
>
|
||||
">
|
||||
<!-- <span class="fas fa-info-circle mx-1"></span> -->
|
||||
<Info class="inline-block mx-1" />
|
||||
<Info class="mx-1 inline-block" />
|
||||
Quick Info
|
||||
</button>
|
||||
|
||||
@@ -157,11 +166,10 @@ hover:opacity-100 -->
|
||||
hover:preset-tonal-warning
|
||||
transition-all
|
||||
"
|
||||
title="Turn debug content and styles off and on"
|
||||
>
|
||||
title="Turn debug content and styles off and on">
|
||||
<!-- <span class="fas fa-toggle-on mx-1"></span> -->
|
||||
<!-- <ToggleRight class="inline-block mx-1" /> -->
|
||||
<CircleX class="inline-block mx-1" />
|
||||
<CircleX class="mx-1 inline-block" />
|
||||
<span class="hidden"> Close </span>
|
||||
<span>Debug</span>
|
||||
</button>
|
||||
@@ -177,18 +185,17 @@ hover:opacity-100 -->
|
||||
id="AE-Quick-Debug"
|
||||
class="
|
||||
btn btn-icon
|
||||
text-xs
|
||||
p-1
|
||||
preset-outlined-surface-100-900
|
||||
hover:preset-filled-warning-100-900
|
||||
fixed
|
||||
bottom-8
|
||||
|
||||
transition-all
|
||||
fixed bottom-8 left-2
|
||||
text-neutral-300 hover:text-neutral-800
|
||||
left-2
|
||||
p-1 text-xs text-neutral-300
|
||||
transition-all hover:text-neutral-800
|
||||
dark:text-neutral-700 dark:hover:text-neutral-200
|
||||
"
|
||||
title="Turn debug content and styles off and on"
|
||||
>
|
||||
title="Turn debug content and styles off and on">
|
||||
<!-- absolute bottom-2 left-2 -->
|
||||
<!-- fixed bottom-0 left-0 -->
|
||||
π
|
||||
|
||||
@@ -1,80 +1,87 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
additional_kv?: key_val;
|
||||
e_success?: boolean;
|
||||
e_class?: string;
|
||||
e_title?: string;
|
||||
e_text?: string;
|
||||
e_class_h1?: string;
|
||||
e_class_h2?: string;
|
||||
e_class_form_hidden?: string;
|
||||
e_class_form_showing?: string;
|
||||
btn_text?: string;
|
||||
btn_title?: string;
|
||||
btn_class?: string;
|
||||
show_btn_class?: string;
|
||||
hide_icon?: boolean;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
additional_kv?: key_val;
|
||||
e_success?: boolean;
|
||||
e_class?: string;
|
||||
e_title?: string;
|
||||
e_text?: string;
|
||||
e_class_h1?: string;
|
||||
e_class_h2?: string;
|
||||
e_class_form_hidden?: string;
|
||||
e_class_form_showing?: string;
|
||||
btn_text?: string;
|
||||
btn_title?: string;
|
||||
btn_class?: string;
|
||||
show_btn_class?: string;
|
||||
hide_icon?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
additional_kv = $bindable({}),
|
||||
e_success = $bindable(false),
|
||||
e_class = '',
|
||||
// e_title = 'Technical Help',
|
||||
// e_text = 'Request technical help for this application.',
|
||||
e_class_h1 = $bindable(''),
|
||||
e_class_h2 = $bindable(''),
|
||||
e_class_form_hidden = $bindable(''),
|
||||
e_class_form_showing = $bindable(''),
|
||||
btn_text = 'Technical Help',
|
||||
btn_title = 'Technical support help',
|
||||
btn_class = '',
|
||||
show_btn_class = '',
|
||||
hide_icon = false
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
additional_kv = $bindable({}),
|
||||
e_success = $bindable(false),
|
||||
e_class = '',
|
||||
// e_title = 'Technical Help',
|
||||
// e_text = 'Request technical help for this application.',
|
||||
e_class_h1 = $bindable(''),
|
||||
e_class_h2 = $bindable(''),
|
||||
e_class_form_hidden = $bindable(''),
|
||||
e_class_form_showing = $bindable(''),
|
||||
btn_text = 'Technical Help',
|
||||
btn_title = 'Technical support help',
|
||||
btn_class = '',
|
||||
show_btn_class = '',
|
||||
hide_icon = false
|
||||
}: Props = $props();
|
||||
|
||||
// *** Import Svelte specific
|
||||
import { goto } from '$app/navigation';
|
||||
// *** Import Svelte specific
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import { BadgeQuestionMark, ChevronDown, ChevronRight, LifeBuoy, RefreshCw, SquareX } from '@lucide/svelte';
|
||||
// *** Import Aether specific variables and functions
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger,
|
||||
type key_val
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
// *** Import other supporting libraries
|
||||
import {
|
||||
BadgeQuestionMark,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
LifeBuoy,
|
||||
RefreshCw,
|
||||
SquareX
|
||||
} from '@lucide/svelte';
|
||||
// *** Import Aether specific variables and functions
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger,
|
||||
type key_val
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`Help - technical support component loaded`);
|
||||
}
|
||||
|
||||
let help_tech_text: string = $state('');
|
||||
let hide_additional_info: boolean = $state(true);
|
||||
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
fn(event);
|
||||
};
|
||||
}
|
||||
|
||||
function send_help_tech_email() {
|
||||
if (log_lvl) {
|
||||
console.log(`Help - technical support component loaded`);
|
||||
console.log(`*** send_help_tech_email() ***`);
|
||||
}
|
||||
|
||||
let help_tech_text: string = $state('');
|
||||
let hide_additional_info: boolean = $state(true);
|
||||
let subject = `Technical Notification - ${$ae_loc.name}`;
|
||||
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
fn(event);
|
||||
};
|
||||
}
|
||||
|
||||
function send_help_tech_email() {
|
||||
if (log_lvl) {
|
||||
console.log(`*** send_help_tech_email() ***`);
|
||||
}
|
||||
|
||||
let subject = `Technical Notification - ${$ae_loc.name}`;
|
||||
|
||||
let body_html = `
|
||||
let body_html = `
|
||||
<div>
|
||||
Technical Notification,\n\n
|
||||
<ul>
|
||||
@@ -102,25 +109,24 @@
|
||||
</div>
|
||||
`;
|
||||
|
||||
api.send_email({
|
||||
api_cfg: $ae_api,
|
||||
from_email:
|
||||
$ae_loc.site_cfg_json?.noreply_email ??
|
||||
'noreply+tech@oneskyit.com',
|
||||
from_name: $ae_loc.site_cfg_json?.noreply_name ?? 'IT NoReply',
|
||||
// to_email: $ae_loc.site_cfg_json?.admin_email ?? 'admin+tech@oneskyit.com', // 'scott+idaabb@oneskyit.com',
|
||||
to_email: 'it+tech@oneskyit.com',
|
||||
// to_email: $idaa_slct.post_obj.email,
|
||||
// to_email: 'scott+idaabb@oneskyit.com',
|
||||
// to_name: $ae_loc.site_cfg_json?.admin_name ?? 'IT Tech',
|
||||
to_name: 'IT Tech',
|
||||
// to_name: $idaa_slct.post_obj.full_name ?? 'IDAA BB Poster',
|
||||
subject: subject,
|
||||
body_html: body_html
|
||||
});
|
||||
api.send_email({
|
||||
api_cfg: $ae_api,
|
||||
from_email:
|
||||
$ae_loc.site_cfg_json?.noreply_email ?? 'noreply+tech@oneskyit.com',
|
||||
from_name: $ae_loc.site_cfg_json?.noreply_name ?? 'IT NoReply',
|
||||
// to_email: $ae_loc.site_cfg_json?.admin_email ?? 'admin+tech@oneskyit.com', // 'scott+idaabb@oneskyit.com',
|
||||
to_email: 'it+tech@oneskyit.com',
|
||||
// to_email: $idaa_slct.post_obj.email,
|
||||
// to_email: 'scott+idaabb@oneskyit.com',
|
||||
// to_name: $ae_loc.site_cfg_json?.admin_name ?? 'IT Tech',
|
||||
to_name: 'IT Tech',
|
||||
// to_name: $idaa_slct.post_obj.full_name ?? 'IDAA BB Poster',
|
||||
subject: subject,
|
||||
body_html: body_html
|
||||
});
|
||||
|
||||
help_tech_text = ''; // Clear the text area after sending
|
||||
}
|
||||
help_tech_text = ''; // Clear the text area after sending
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- class:bg-radial-[at_55%_50%]={$ae_sess.show_help_tech}
|
||||
@@ -131,8 +137,8 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
class="
|
||||
flex flex-row
|
||||
items-center justify-center
|
||||
rounded-lg shadow-2xl
|
||||
border border-transparent
|
||||
rounded-lg border
|
||||
border-transparent shadow-2xl
|
||||
transition-all
|
||||
{e_class}
|
||||
{!$ae_sess.show_help_tech ? e_class_form_hidden : e_class_form_showing}
|
||||
@@ -148,48 +154,42 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
class:hover:shadow-blue-200={$ae_sess.show_help_tech}
|
||||
class:hover:dark:shadow-blue-800={$ae_sess.show_help_tech}
|
||||
class:bg-blue-100={$ae_sess.show_help_tech}
|
||||
class:dark:bg-blue-900={$ae_sess.show_help_tech}
|
||||
>
|
||||
class:dark:bg-blue-900={$ae_sess.show_help_tech}>
|
||||
{#if $ae_sess.show_help_tech}
|
||||
<div
|
||||
class="
|
||||
w-xl
|
||||
flex flex-col gap-1
|
||||
items-center justify-center
|
||||
flex
|
||||
w-xl flex-col items-center
|
||||
justify-center gap-1
|
||||
rounded-xl
|
||||
border border-gray-500/20 bg-blue-200
|
||||
p-2
|
||||
border rounded-xl border-gray-500/20
|
||||
bg-blue-200
|
||||
dark:bg-blue-800
|
||||
transition-all
|
||||
"
|
||||
>
|
||||
dark:bg-blue-800
|
||||
">
|
||||
<div
|
||||
class="
|
||||
d-flex align-items-center justify-content-between
|
||||
flex flex-row gap-1 items-center justify-between
|
||||
w-full
|
||||
"
|
||||
>
|
||||
flex w-full flex-row items-center justify-between
|
||||
gap-1
|
||||
">
|
||||
<h1
|
||||
class="
|
||||
h1
|
||||
text-base font-semibold text-gray-800 dark:text-gray-200
|
||||
w-fit
|
||||
w-fit text-base font-semibold text-gray-800
|
||||
dark:text-gray-200
|
||||
{e_class_h1}
|
||||
"
|
||||
>
|
||||
">
|
||||
{#if e_success}
|
||||
<span
|
||||
class="text-lg text-green-800 dark:text-green-200 font-semibold"
|
||||
>
|
||||
<BadgeQuestionMark class="inline-block mr-2" />
|
||||
class="text-lg font-semibold text-green-800 dark:text-green-200">
|
||||
<BadgeQuestionMark class="mr-2 inline-block" />
|
||||
Help Requested
|
||||
</span>
|
||||
{:else}
|
||||
<span
|
||||
class="text-lg text-gray-800 dark:text-gray-200 font-semibold"
|
||||
>
|
||||
<BadgeQuestionMark class="inline-block mr-2" />
|
||||
class="text-lg font-semibold text-gray-800 dark:text-gray-200">
|
||||
<BadgeQuestionMark class="mr-2 inline-block" />
|
||||
<!-- Request Technical Help -->
|
||||
Notify Technical Support
|
||||
</span>
|
||||
@@ -211,8 +211,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
transition-all
|
||||
{btn_class}
|
||||
"
|
||||
title="Close Help Request Form"
|
||||
>
|
||||
title="Close Help Request Form">
|
||||
<!-- <span class="fas fa-times"></span> -->
|
||||
<SquareX size="1em" />
|
||||
<span class="sr-only">Close</span>
|
||||
@@ -222,9 +221,9 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
<form
|
||||
class="
|
||||
m-1
|
||||
flex flex-col gap-1
|
||||
items-center justify-center
|
||||
w-md max-w-lg
|
||||
flex w-md max-w-lg
|
||||
flex-col items-center
|
||||
justify-center gap-1
|
||||
"
|
||||
onsubmit={prevent_default(() => {
|
||||
// Do stuff...
|
||||
@@ -234,40 +233,37 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
$ae_sess.show_help_tech = false;
|
||||
|
||||
alert('Notification sent to the IT team.');
|
||||
})}
|
||||
>
|
||||
})}>
|
||||
<textarea
|
||||
class="
|
||||
form-control
|
||||
w-full max-w-lg h-24 p-2
|
||||
border border-gray-300 rounded
|
||||
text-gray-950 dark:text-gray-50
|
||||
bg-white dark:bg-gray-500
|
||||
h-24 w-full max-w-lg rounded
|
||||
border border-gray-300 bg-white
|
||||
p-2 text-gray-950
|
||||
dark:bg-gray-500 dark:text-gray-50
|
||||
hover:dark:bg-gray-50
|
||||
hover:dark:text-gray-950
|
||||
"
|
||||
placeholder="Send with or without a description...."
|
||||
bind:value={help_tech_text}
|
||||
></textarea>
|
||||
bind:value={help_tech_text}></textarea>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="
|
||||
btn btn-lg
|
||||
m-1
|
||||
preset-tonal-warning
|
||||
preset-outlined-warning-100-900
|
||||
hover:preset-filled-warning-200-800
|
||||
m-1
|
||||
|
||||
|
||||
transition-all
|
||||
{btn_class}
|
||||
"
|
||||
title={btn_title}
|
||||
>
|
||||
title={btn_title}>
|
||||
{#if !hide_icon}
|
||||
<!-- <BadgeQuestionMark class="inline-block mr-2" /> -->
|
||||
<LifeBuoy class="inline-block m-1" />
|
||||
<LifeBuoy class="m-1 inline-block" />
|
||||
{/if}
|
||||
|
||||
{#if !help_tech_text}
|
||||
@@ -280,9 +276,8 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
|
||||
<div
|
||||
class="
|
||||
text-sm text-gray-700 dark:text-gray-300 text-center italic
|
||||
"
|
||||
>
|
||||
text-center text-sm text-gray-700 italic dark:text-gray-300
|
||||
">
|
||||
This is intended for technical issues only. Please contact your
|
||||
organization's staff if you have a question about your
|
||||
membership, recorded content, meetings, or posts.
|
||||
@@ -290,29 +285,25 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
|
||||
<div
|
||||
class="
|
||||
border border-gray-300 rounded p-2
|
||||
w-full
|
||||
max-w-2xl
|
||||
overflow-scroll
|
||||
"
|
||||
>
|
||||
w-full max-w-2xl overflow-scroll rounded
|
||||
border
|
||||
border-gray-300
|
||||
p-2
|
||||
">
|
||||
<div
|
||||
class="
|
||||
d-flex align-items-center justify-content-between
|
||||
flex flex-row gap-1 items-center justify-between
|
||||
w-full
|
||||
"
|
||||
>
|
||||
flex w-full flex-row items-center justify-between
|
||||
gap-1
|
||||
">
|
||||
<h2
|
||||
class="
|
||||
h2
|
||||
text-base font-semibold text-gray-800 dark:text-gray-200
|
||||
{e_class_h2}
|
||||
"
|
||||
>
|
||||
">
|
||||
<span
|
||||
class="text-base font-semibold text-gray-800 dark:text-gray-200"
|
||||
>
|
||||
class="text-base font-semibold text-gray-800 dark:text-gray-200">
|
||||
Additional Information Included
|
||||
</span>
|
||||
</h2>
|
||||
@@ -325,8 +316,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
"
|
||||
onclick={() =>
|
||||
(hide_additional_info = !hide_additional_info)}
|
||||
title="Toggle additional information"
|
||||
>
|
||||
title="Toggle additional information">
|
||||
<span>
|
||||
{#if hide_additional_info}
|
||||
<!-- <span class="fas fa-caret-right"></span> -->
|
||||
@@ -341,89 +331,75 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
</button>
|
||||
</div>
|
||||
<ul
|
||||
class="list-disc list-inside text-sm text-gray-800 dark:text-gray-200"
|
||||
class:hidden={hide_additional_info}
|
||||
>
|
||||
class="list-inside list-disc text-sm text-gray-800 dark:text-gray-200"
|
||||
class:hidden={hide_additional_info}>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Datetime =</span
|
||||
>
|
||||
>Datetime =</span>
|
||||
{new Date().toISOString()}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>URL =</span
|
||||
>
|
||||
>URL =</span>
|
||||
{window.location.href}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Browser =</span
|
||||
>
|
||||
>Browser =</span>
|
||||
{navigator.userAgent}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Viewport Size =</span
|
||||
>
|
||||
>Viewport Size =</span>
|
||||
{window.innerWidth} x {window.innerHeight}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Screen Resolution =</span
|
||||
>
|
||||
>Screen Resolution =</span>
|
||||
{window.screen.width} x {window.screen.height}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Dark mode =</span
|
||||
>
|
||||
>Dark mode =</span>
|
||||
{window?.matchMedia?.('(prefers-color-scheme:dark)')
|
||||
?.matches ?? false}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>In iframe =</span
|
||||
>
|
||||
>In iframe =</span>
|
||||
{$ae_loc?.iframe}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Theme Mode =</span
|
||||
>
|
||||
>Theme Mode =</span>
|
||||
{$ae_loc?.theme_mode}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Theme Name =</span
|
||||
>
|
||||
>Theme Name =</span>
|
||||
{$ae_loc?.theme_name}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Account ID =</span
|
||||
>
|
||||
>Account ID =</span>
|
||||
{$slct.account_id}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>Access Type =</span
|
||||
>
|
||||
>Access Type =</span>
|
||||
{$ae_loc?.access_type}
|
||||
</li>
|
||||
{#if $ae_loc?.person_id}
|
||||
<li>
|
||||
<span
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>person_id =</span
|
||||
>
|
||||
>person_id =</span>
|
||||
{$ae_loc?.person_id}
|
||||
</li>
|
||||
<li>
|
||||
<span
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>full_name =</span
|
||||
>
|
||||
>full_name =</span>
|
||||
{$ae_loc?.full_name}
|
||||
</li>
|
||||
{/if}
|
||||
@@ -431,29 +407,25 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
<li>
|
||||
<span
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>user_id =</span
|
||||
>
|
||||
>user_id =</span>
|
||||
{$ae_loc?.user_id}
|
||||
</li>
|
||||
<li>
|
||||
<span
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>username =</span
|
||||
>
|
||||
>username =</span>
|
||||
{$ae_loc?.username}
|
||||
</li>
|
||||
<li>
|
||||
<span
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>email =</span
|
||||
>
|
||||
>email =</span>
|
||||
{$ae_loc?.email}
|
||||
</li>
|
||||
{/if}
|
||||
<li>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>API Base URL =</span
|
||||
>
|
||||
>API Base URL =</span>
|
||||
{$ae_api.base_url}
|
||||
</li>
|
||||
|
||||
@@ -461,13 +433,12 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
<h2 class="text-base font-semibold text-gray-800">
|
||||
Component Info:
|
||||
</h2>
|
||||
<ul class="list-disc list-inside text-gray-800 text-sm">
|
||||
<ul class="list-inside list-disc text-sm text-gray-800">
|
||||
{#each Object.entries(additional_kv) as [key, value] (key)}
|
||||
<li>
|
||||
<span
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
>{key} =</span
|
||||
>
|
||||
>{key} =</span>
|
||||
{value ?? '-- not set --'}
|
||||
</li>
|
||||
{/each}
|
||||
@@ -475,8 +446,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
{/if}
|
||||
</ul>
|
||||
<div
|
||||
class="text-sm text-gray-700 dark:text-gray-300 text-center italic"
|
||||
>
|
||||
class="text-center text-sm text-gray-700 italic dark:text-gray-300">
|
||||
This information will be included in the help request to
|
||||
assist technical support in diagnosing the issue.
|
||||
</div>
|
||||
@@ -484,11 +454,10 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
|
||||
<div
|
||||
class="
|
||||
flex flex-row gap-2 items-center justify-around
|
||||
w-full
|
||||
mt-2
|
||||
"
|
||||
>
|
||||
mt-2 flex w-full flex-row items-center
|
||||
justify-around
|
||||
gap-2
|
||||
">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
@@ -562,8 +531,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
transition-all
|
||||
{btn_class}
|
||||
"
|
||||
title="Clear App Data & Settings: Clear IndexedDB and reload. If in edit mode localStorage and sessionStorage will also be cleared."
|
||||
>
|
||||
title="Clear App Data & Settings: Clear IndexedDB and reload. If in edit mode localStorage and sessionStorage will also be cleared.">
|
||||
<!-- <span class="fas fa-eraser mx-1"></span> -->
|
||||
<!-- <span class="fas fa-sync mx-1"></span> -->
|
||||
<RefreshCw size="1em" class="inline-block" />
|
||||
@@ -582,8 +550,7 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
transition-all
|
||||
{btn_class}
|
||||
"
|
||||
title="Close Help Request Form"
|
||||
>
|
||||
title="Close Help Request Form">
|
||||
<!-- <span class="fas fa-times"></span> -->
|
||||
<SquareX size="1em" class="inline-block" />
|
||||
<span class="">Cancel</span>
|
||||
@@ -603,10 +570,9 @@ class:to-90%={$ae_sess.show_help_tech} -->
|
||||
{btn_class}
|
||||
{show_btn_class}
|
||||
"
|
||||
title={btn_title}
|
||||
>
|
||||
title={btn_title}>
|
||||
{#if !hide_icon}
|
||||
<BadgeQuestionMark class="inline-block m-0.5" />
|
||||
<BadgeQuestionMark class="m-0.5 inline-block" />
|
||||
{/if}
|
||||
<span class="hidden">
|
||||
{btn_text}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,56 +1,63 @@
|
||||
<script lang="ts">
|
||||
// *** Import Svelte specific
|
||||
// import { tick } from 'svelte';
|
||||
// import { goto, invalidateAll } from '$app/navigation';
|
||||
// *** Import Svelte specific
|
||||
// import { tick } from 'svelte';
|
||||
// import { goto, invalidateAll } from '$app/navigation';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import {
|
||||
// ArrowBigRight,
|
||||
// Bug,
|
||||
CircleX,
|
||||
// Eye, EyeOff,
|
||||
// Key,
|
||||
// LogIn, LogOut, LockKeyhole,
|
||||
// Mail, MailCheck,
|
||||
Menu,
|
||||
// RefreshCw, RefreshCcwDot,
|
||||
ShieldEllipsis,
|
||||
ShieldMinus,
|
||||
ShieldPlus,
|
||||
ShieldUser,
|
||||
ToggleLeft, ToggleRight,
|
||||
User,
|
||||
UserCheck,
|
||||
UserCog,
|
||||
Wand2,
|
||||
X
|
||||
} from '@lucide/svelte';
|
||||
// *** Import other supporting libraries
|
||||
import {
|
||||
// ArrowBigRight,
|
||||
// Bug,
|
||||
CircleX,
|
||||
// Eye, EyeOff,
|
||||
// Key,
|
||||
// LogIn, LogOut, LockKeyhole,
|
||||
// Mail, MailCheck,
|
||||
Menu,
|
||||
// RefreshCw, RefreshCcwDot,
|
||||
ShieldEllipsis,
|
||||
ShieldMinus,
|
||||
ShieldPlus,
|
||||
ShieldUser,
|
||||
ToggleLeft,
|
||||
ToggleRight,
|
||||
User,
|
||||
UserCheck,
|
||||
UserCog,
|
||||
Wand2,
|
||||
X
|
||||
} from '@lucide/svelte';
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
// *** Import Aether specific variables and functions
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
|
||||
import Element_access_type from '$lib/app_components/e_app_access_type.svelte';
|
||||
import Element_app_cfg from '$lib/app_components/e_app_cfg.svelte';
|
||||
import Element_sign_in_out from '$lib/app_components/e_app_sign_in_out.svelte';
|
||||
import Element_theme from '$lib/app_components/e_app_theme.svelte';
|
||||
import Element_access_type from '$lib/app_components/e_app_access_type.svelte';
|
||||
import Element_app_cfg from '$lib/app_components/e_app_cfg.svelte';
|
||||
import Element_sign_in_out from '$lib/app_components/e_app_sign_in_out.svelte';
|
||||
import Element_theme from '$lib/app_components/e_app_theme.svelte';
|
||||
|
||||
// *** Setup Svelte properties
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
data: any;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
}
|
||||
// *** Setup Svelte properties
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
data: any;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
data = null,
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false)
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
data = null,
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false)
|
||||
}: Props = $props();
|
||||
|
||||
let trigger_clear_access: null | boolean = $state(null);
|
||||
let trigger_clear_access: null | boolean = $state(null);
|
||||
</script>
|
||||
|
||||
<!-- App System Menu -->
|
||||
@@ -93,38 +100,37 @@ max-w-max -->
|
||||
ae_app__sys_menu
|
||||
|
||||
hidden-print
|
||||
md:text-md
|
||||
lg:text-md xl:text-md absolute
|
||||
|
||||
right-0
|
||||
bottom-6
|
||||
|
||||
z-50
|
||||
absolute bottom-6 right-0
|
||||
flex
|
||||
|
||||
opacity-90
|
||||
hover:opacity-100
|
||||
|
||||
w-min
|
||||
max-w-md
|
||||
|
||||
flex flex-col-reverse gap-1
|
||||
w-min max-w-md flex-col-reverse
|
||||
items-end justify-center
|
||||
|
||||
text-sm sm:text-sm md:text-md lg:text-md xl:text-md 2xl:text-lg
|
||||
gap-1 rounded-lg border-2 border-blue-300/20 bg-blue-200/90 text-sm
|
||||
|
||||
bg-blue-200/90
|
||||
opacity-90
|
||||
|
||||
border-2 rounded-lg
|
||||
border-blue-300/20 dark:border-blue-700/20
|
||||
hover:border-blue-500/20 hover:dark:border-blue-500/20
|
||||
transition-all delay-500
|
||||
duration-500 ease-in-out
|
||||
hover:border-blue-500/20 hover:opacity-100
|
||||
|
||||
transition-all
|
||||
delay-500 hover:delay-200
|
||||
duration-500 hover:duration-200
|
||||
ease-in-out
|
||||
hover:delay-200
|
||||
hover:duration-200 sm:text-sm
|
||||
2xl:text-lg dark:border-blue-700/20
|
||||
hover:dark:border-blue-500/20
|
||||
"
|
||||
class:top-0={expand && (1 as any) == 3}
|
||||
class:opacity-100={expand}
|
||||
class:w-full={expand}
|
||||
class:hidden={hide}
|
||||
class:border-transparent={!expand}
|
||||
class:bg-transparent={!expand}
|
||||
>
|
||||
class:bg-transparent={!expand}>
|
||||
<!-- class:hidden={!expand} -->
|
||||
<!-- class:preset-filled-warning-100-900={expand} -->
|
||||
<div
|
||||
@@ -134,38 +140,40 @@ max-w-max -->
|
||||
class:dark:bg-blue-500={expand}
|
||||
class="
|
||||
hidden-print
|
||||
flex flex-col items-end justify-end
|
||||
light:bg-blue-200/10 relative flex w-full
|
||||
flex-col
|
||||
|
||||
items-end
|
||||
justify-end
|
||||
|
||||
gap-1
|
||||
|
||||
overflow-y-auto
|
||||
p-1
|
||||
|
||||
w-full
|
||||
|
||||
light:bg-blue-200/10
|
||||
dark:bg-blue-800/10
|
||||
hover:opacity-100
|
||||
|
||||
relative
|
||||
|
||||
transition-all
|
||||
delay-1000 hover:delay-500
|
||||
duration-200 hover:duration-200
|
||||
ease-in-out
|
||||
|
||||
delay-1000
|
||||
|
||||
duration-200
|
||||
ease-in-out hover:opacity-100
|
||||
hover:delay-500 hover:duration-200
|
||||
dark:bg-blue-800/10
|
||||
"
|
||||
title="
|
||||
ID: {$ae_loc?.person_id ?? '-- not set --'} / {$ae_loc?.user_id ?? '-- not set --'}
|
||||
ID: {$ae_loc?.person_id ?? '-- not set --'} / {$ae_loc?.user_id ??
|
||||
'-- not set --'}
|
||||
Name: {$ae_loc?.person?.full_name ?? '-- not set --'}
|
||||
Username: {$ae_loc?.user?.username ?? '-- not set --'}
|
||||
Email: {$ae_loc?.user?.email ?? '-- not set --'}
|
||||
Access Type: {$ae_loc?.access_type ?? '-- not set --'}
|
||||
"
|
||||
>
|
||||
">
|
||||
{#if $ae_loc?.person_id}
|
||||
<div class="flex flex-row gap-1 items-center justify-end transition-all w-full group">
|
||||
<div
|
||||
class="group flex w-full flex-row items-center justify-end gap-1 transition-all">
|
||||
<User size="1em" class="mx-1 inline-block text-gray-500" />
|
||||
<span class:hidden={!expand} class="group-hover:inline-block">
|
||||
{$ae_loc?.person?.informal_name ?? $ae_loc?.person?.given_name}
|
||||
{$ae_loc?.person?.informal_name ??
|
||||
$ae_loc?.person?.given_name}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -174,54 +182,60 @@ max-w-max -->
|
||||
<!-- This is currently not set to show if not expanded. Saving space. -->
|
||||
<div
|
||||
class:hidden={!expand}
|
||||
class="flex flex-row gap-1 items-center justify-end transition-all w-full group"
|
||||
>
|
||||
<ShieldUser size="1em" class="mx-1 inline-block text-gray-500" />
|
||||
class="group flex w-full flex-row items-center justify-end gap-1 transition-all">
|
||||
<ShieldUser
|
||||
size="1em"
|
||||
class="mx-1 inline-block text-gray-500" />
|
||||
<span class:hidden={!expand} class="group-hover:inline-block">
|
||||
{$ae_loc?.user?.username ?? '-- not set --'}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-row gap-1 items-center justify-end transition-all w-full group">
|
||||
<div
|
||||
class="group flex w-full flex-row items-center justify-end gap-1 transition-all">
|
||||
{#if $ae_loc.access_type && $ae_loc.access_type != 'anonymous'}
|
||||
<span
|
||||
class="flex flex-row-reverse gap-1 group text-base"
|
||||
title={`Current access type/level: ${$ae_loc.access_type}`}
|
||||
>
|
||||
class="group flex flex-row-reverse gap-1 text-base"
|
||||
title={`Current access type/level: ${$ae_loc.access_type}`}>
|
||||
<!-- <span class="fas fa-unlock mx-1"></span> -->
|
||||
<!-- <ShieldPlus class="inline-block" /> -->
|
||||
|
||||
{#if $ae_loc.access_type == 'super'}
|
||||
<Wand2 size="1em" class="m-1 inline-block" />
|
||||
<span class:hidden={!expand} class="hidden group-hover:inline-block"
|
||||
>Super</span
|
||||
>
|
||||
<span
|
||||
class:hidden={!expand}
|
||||
class="hidden group-hover:inline-block">Super</span>
|
||||
{:else if $ae_loc.access_type == 'manager'}
|
||||
<ShieldUser size="1em" class="m-1 inline-block" />
|
||||
<span class:hidden={!expand} class="hidden group-hover:inline-block"
|
||||
>Manager</span
|
||||
>
|
||||
<span
|
||||
class:hidden={!expand}
|
||||
class="hidden group-hover:inline-block"
|
||||
>Manager</span>
|
||||
{:else if $ae_loc.access_type == 'administrator'}
|
||||
<UserCog size="1em" class="m-1 inline-block" />
|
||||
<span class:hidden={!expand} class="hidden group-hover:inline-block"
|
||||
>Administrator</span
|
||||
>
|
||||
<span
|
||||
class:hidden={!expand}
|
||||
class="hidden group-hover:inline-block"
|
||||
>Administrator</span>
|
||||
{:else if $ae_loc.access_type == 'trusted'}
|
||||
<UserCheck size="1em" class="m-1 inline-block" />
|
||||
<span class:hidden={!expand} class="hidden group-hover:inline-block"
|
||||
>Trusted Access</span
|
||||
>
|
||||
<span
|
||||
class:hidden={!expand}
|
||||
class="hidden group-hover:inline-block"
|
||||
>Trusted Access</span>
|
||||
{:else if $ae_loc.access_type == 'public'}
|
||||
Public
|
||||
<span class:hidden={!expand} class="hidden group-hover:inline-block"
|
||||
>Access</span
|
||||
>
|
||||
<span
|
||||
class:hidden={!expand}
|
||||
class="hidden group-hover:inline-block"
|
||||
>Access</span>
|
||||
{:else if $ae_loc.access_type == 'authenticated'}
|
||||
Authenticated
|
||||
<span class:hidden={!expand} class="hidden group-hover:inline-block"
|
||||
>Access</span
|
||||
>
|
||||
<span
|
||||
class:hidden={!expand}
|
||||
class="hidden group-hover:inline-block"
|
||||
>Access</span>
|
||||
{:else if $ae_loc.access_type == 'anonymous'}
|
||||
Anonymous Access
|
||||
{:else}
|
||||
@@ -254,13 +268,13 @@ max-w-max -->
|
||||
// $ae_loc.sys_menu.expand_btn = true;
|
||||
}
|
||||
}}
|
||||
class="btn btn-sm text-xs variant-outline-surface hover:variant-ghost-warning transition-all group"
|
||||
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}
|
||||
>
|
||||
class="btn btn-sm variant-outline-surface hover:variant-ghost-warning group text-xs transition-all"
|
||||
title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}>
|
||||
<!-- <span class="fas fa-lock mx-1"></span> -->
|
||||
<!-- <ShieldMinus /> -->
|
||||
<ShieldEllipsis size="2em" class="inline-block" />
|
||||
<span class="hidden group-hover:inline-block">Passcode?</span>
|
||||
<span class="hidden group-hover:inline-block"
|
||||
>Passcode?</span>
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
@@ -291,16 +305,17 @@ max-w-max -->
|
||||
}
|
||||
}}
|
||||
class="
|
||||
btn btn-sm text-xs
|
||||
flex-row-reverse
|
||||
variant-outline-surface hover:variant-ghost-warning
|
||||
transition-all group
|
||||
btn btn-sm variant-outline-surface
|
||||
hover:variant-ghost-warning
|
||||
group flex-row-reverse
|
||||
text-xs transition-all
|
||||
"
|
||||
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}
|
||||
>
|
||||
title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}>
|
||||
<!-- <span class="fas fa-lock mx-1"></span> Lock? -->
|
||||
<ShieldMinus class="inline-block" />
|
||||
<span class="hidden group-hover:inline-block"> Clear? </span>
|
||||
<span class="hidden group-hover:inline-block">
|
||||
Clear?
|
||||
</span>
|
||||
</button>
|
||||
{/if}
|
||||
{:else}
|
||||
@@ -320,19 +335,22 @@ max-w-max -->
|
||||
// $ae_loc.app_cfg.show_element__access_type = true;
|
||||
// $ae_loc.app_cfg.show_element__passcode_input = true;
|
||||
// await tick();
|
||||
console.log('Layout button click: Focus on passcode input!');
|
||||
console.log(
|
||||
'Layout button click: Focus on passcode input!'
|
||||
);
|
||||
/** @type {HTMLElement | null} */
|
||||
const to_focus = document.getElementById('access_passcode_input');
|
||||
const to_focus = document.getElementById(
|
||||
'access_passcode_input'
|
||||
);
|
||||
to_focus?.focus();
|
||||
}}
|
||||
class="
|
||||
btn btn-sm text-xs
|
||||
flex-row-reverse
|
||||
variant-outline-surface hover:variant-ghost-success
|
||||
transition-all group
|
||||
btn btn-sm variant-outline-surface
|
||||
hover:variant-ghost-success
|
||||
group flex-row-reverse
|
||||
text-xs transition-all
|
||||
"
|
||||
title="Anonymous public access is currently set. You must Sign In or use a passcode to change your access level."
|
||||
>
|
||||
title="Anonymous public access is currently set. You must Sign In or use a passcode to change your access level.">
|
||||
<!-- <span class="fas fa-lock mx-1 lock_icon"></span> -->
|
||||
<!-- <span class="">Unlock?</span> -->
|
||||
<ShieldUser class="inline-block" />
|
||||
@@ -349,19 +367,21 @@ max-w-max -->
|
||||
// dispatch_edit_mode_changed();
|
||||
}}
|
||||
class="
|
||||
btn btn-base text-sm
|
||||
preset-tonal-warning
|
||||
btn btn-base preset-tonal-warning
|
||||
preset-outlined-warning-800-200
|
||||
hover:preset-tonal-success
|
||||
transition-all group
|
||||
min-w-22 md:min-w-30 w-full max-w-fit
|
||||
gap-1
|
||||
group
|
||||
w-full max-w-fit
|
||||
min-w-22 gap-1 text-sm transition-all
|
||||
md:min-w-30
|
||||
"
|
||||
title="Click to turn off edit mode. Edit mode is currently on."
|
||||
>
|
||||
title="Click to turn off edit mode. Edit mode is currently on.">
|
||||
<ToggleRight size="1em" class="m-1 inline-block" />
|
||||
<span class="text-xs">Edit</span>
|
||||
<span class="hidden group-hover:inline-block group-hover:text-xs"> Off </span>
|
||||
<span
|
||||
class="hidden group-hover:inline-block group-hover:text-xs">
|
||||
Off
|
||||
</span>
|
||||
</button>
|
||||
{:else if $ae_loc.authenticated_access}
|
||||
<button
|
||||
@@ -371,19 +391,21 @@ max-w-max -->
|
||||
// dispatch_edit_mode_changed();
|
||||
}}
|
||||
class="
|
||||
btn btn-base text-sm
|
||||
preset-tonal-surface
|
||||
btn btn-base preset-tonal-surface
|
||||
preset-outlined-warning-400-600
|
||||
hover:preset-tonal-warning
|
||||
transition-all group
|
||||
min-w-22 md:min-w-30 w-full max-w-fit
|
||||
gap-1
|
||||
group
|
||||
w-full max-w-fit
|
||||
min-w-22 gap-1 text-sm transition-all
|
||||
md:min-w-30
|
||||
"
|
||||
title="Click to torn on/enable edit mode. Edit mode is currently off/disabled."
|
||||
>
|
||||
title="Click to torn on/enable edit mode. Edit mode is currently off/disabled.">
|
||||
<ToggleLeft size="1em" class="m-1 inline-block" />
|
||||
<span class="text-xs">Edit</span>
|
||||
<span class="hidden group-hover:inline-block group-hover:text-xs"> On? </span>
|
||||
<span
|
||||
class="hidden group-hover:inline-block group-hover:text-xs">
|
||||
On?
|
||||
</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -392,12 +414,12 @@ max-w-max -->
|
||||
type="button"
|
||||
class:w-full={expand}
|
||||
class="
|
||||
btn btn-base text-sm
|
||||
preset-tonal-surface
|
||||
btn btn-base preset-tonal-surface
|
||||
hover:preset-tonal-primary
|
||||
px-1 py-1
|
||||
min-w-22 md:min-w-30 w-full max-w-fit
|
||||
transition-all group
|
||||
group
|
||||
w-full max-w-fit
|
||||
min-w-22 px-1 py-1 text-sm
|
||||
transition-all md:min-w-30
|
||||
"
|
||||
title="Cycle font size: default → larger → smaller"
|
||||
onclick={() => {
|
||||
@@ -409,17 +431,19 @@ max-w-max -->
|
||||
} else {
|
||||
$ae_loc.font_size_mode = 'default';
|
||||
}
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{#if !$ae_loc.font_size_mode || $ae_loc.font_size_mode === 'default'}
|
||||
<span class="font-bold text-sm leading-none">A</span>
|
||||
<span class="hidden group-hover:inline-block text-xs">Font: Normal</span>
|
||||
<span class="text-sm leading-none font-bold">A</span>
|
||||
<span class="hidden text-xs group-hover:inline-block"
|
||||
>Font: Normal</span>
|
||||
{:else if $ae_loc.font_size_mode === 'larger'}
|
||||
<span class="font-bold text-base leading-none">A+</span>
|
||||
<span class="hidden group-hover:inline-block text-xs">Font: Larger</span>
|
||||
<span class="text-base leading-none font-bold">A+</span>
|
||||
<span class="hidden text-xs group-hover:inline-block"
|
||||
>Font: Larger</span>
|
||||
{:else}
|
||||
<span class="font-bold text-xs leading-none">A−</span>
|
||||
<span class="hidden group-hover:inline-block text-xs">Font: Smaller</span>
|
||||
<span class="text-xs leading-none font-bold">A−</span>
|
||||
<span class="hidden text-xs group-hover:inline-block"
|
||||
>Font: Smaller</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
@@ -432,13 +456,13 @@ max-w-max -->
|
||||
type="button"
|
||||
class:w-full={expand}
|
||||
class="
|
||||
btn btn-base text-sm
|
||||
preset-filled-tertiary-400-600
|
||||
btn btn-base preset-filled-tertiary-400-600
|
||||
preset-outlined-tertiary-400-600
|
||||
hover:preset-filled-success active:preset-filled-success
|
||||
px-1 py-1
|
||||
min-w-22 md:min-w-30 w-full max-w-fit
|
||||
transition-all group
|
||||
hover:preset-filled-success
|
||||
active:preset-filled-success group
|
||||
w-full max-w-fit
|
||||
min-w-22 px-1 py-1 text-sm
|
||||
transition-all md:min-w-30
|
||||
"
|
||||
title="Show/Hide the system menu"
|
||||
onclick={async () => {
|
||||
@@ -472,15 +496,14 @@ max-w-max -->
|
||||
// $ae_loc.app_cfg.show_element__passcode_input = false;
|
||||
}
|
||||
// $ae_loc.sys_menu.expand_btn = !expand_btn;
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<!-- <span class=""> -->
|
||||
{#if expand}
|
||||
<CircleX class="m-1 inline-block" />
|
||||
{:else}
|
||||
<Menu class="m-1 inline-block" />
|
||||
{/if}
|
||||
<span class="text-xs hidden group-hover:inline-block"> Menu </span>
|
||||
<span class="hidden text-xs group-hover:inline-block"> Menu </span>
|
||||
<!-- </span> -->
|
||||
</button>
|
||||
<!-- </div> -->
|
||||
@@ -499,27 +522,26 @@ max-w-max -->
|
||||
ae_app__sys_menu
|
||||
|
||||
hidden-print
|
||||
flex flex-col
|
||||
items-end
|
||||
justify-end
|
||||
gap-2
|
||||
|
||||
z-20 flex
|
||||
min-w-48
|
||||
flex-col
|
||||
items-end
|
||||
|
||||
bg-white dark:bg-gray-800
|
||||
justify-end
|
||||
|
||||
border border-gray-200 dark:border-gray-700
|
||||
rounded-lg
|
||||
px-1 py-2
|
||||
gap-2 rounded-lg
|
||||
|
||||
transition-all
|
||||
delay-1000 hover:delay-100
|
||||
duration-100 hover:duration-200
|
||||
ease-in-out
|
||||
border border-gray-200 bg-white
|
||||
px-1
|
||||
py-2 transition-all
|
||||
|
||||
z-20 hover:z-30
|
||||
"
|
||||
>
|
||||
delay-1000
|
||||
duration-100 ease-in-out
|
||||
hover:z-30 hover:delay-100
|
||||
hover:duration-200
|
||||
|
||||
dark:border-gray-700 dark:bg-gray-800
|
||||
">
|
||||
<button
|
||||
type="button"
|
||||
class:w-full={expand}
|
||||
@@ -528,8 +550,8 @@ max-w-max -->
|
||||
preset-filled-tertiary-400-600
|
||||
preset-outlined-tertiary-400-600
|
||||
hover:preset-filled-success active:preset-filled-success
|
||||
px-6 py-1
|
||||
transition-all group
|
||||
group px-6
|
||||
py-1 transition-all
|
||||
"
|
||||
title="Show/Hide the system menu"
|
||||
onclick={() => {
|
||||
@@ -549,8 +571,7 @@ max-w-max -->
|
||||
}
|
||||
// $ae_loc.sys_menu.expand_btn = !expand_btn;
|
||||
// $ae_loc.sys_menu.expand = !expand;
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{#if expand}
|
||||
<CircleX class="m-1 inline-block" />
|
||||
<span class="hidden group-hover:inline-block"> Hide Menu </span>
|
||||
@@ -564,16 +585,14 @@ max-w-max -->
|
||||
<span class:hidden={!$ae_loc.edit_mode}>
|
||||
<Element_app_cfg
|
||||
hide={$ae_loc.sys_menu.hide_app_cfg}
|
||||
expand={$ae_loc.sys_menu.expand_app_cfg}
|
||||
/>
|
||||
expand={$ae_loc.sys_menu.expand_app_cfg} />
|
||||
</span>
|
||||
<span class:hidden={!$ae_loc.edit_mode}>
|
||||
<Element_theme
|
||||
hide={$ae_loc.sys_menu.hide_app_cfg}
|
||||
expand={$ae_loc.sys_menu.expand_app_cfg}
|
||||
set_theme_mode={true}
|
||||
set_theme_name={true}
|
||||
/>
|
||||
set_theme_name={true} />
|
||||
</span>
|
||||
<!-- {/if} -->
|
||||
|
||||
@@ -582,8 +601,8 @@ max-w-max -->
|
||||
<!-- expand={$ae_loc.sys_menu.expand_user} -->
|
||||
<Element_sign_in_out
|
||||
{data}
|
||||
hidden={$ae_loc.iframe || !$ae_loc.app_cfg?.show_element__sign_in_out}
|
||||
/>
|
||||
hidden={$ae_loc.iframe ||
|
||||
!$ae_loc.app_cfg?.show_element__sign_in_out} />
|
||||
{/if}
|
||||
|
||||
{#if !$ae_loc?.sys_menu?.hide_access_type && !$ae_loc?.iframe}
|
||||
@@ -592,9 +611,10 @@ max-w-max -->
|
||||
bind:hide={$ae_loc.sys_menu.hide_access_type}
|
||||
bind:focus_input={$ae_sess.sys_menu.focus_passcode_input}
|
||||
bind:expand={$ae_loc.sys_menu.expand_access_type}
|
||||
bind:show_passcode_input={$ae_sess.app_cfg.show_element__passcode_input}
|
||||
bind:trigger_clear_access
|
||||
/>
|
||||
bind:show_passcode_input={
|
||||
$ae_sess.app_cfg.show_element__passcode_input
|
||||
}
|
||||
bind:trigger_clear_access />
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
<script lang="ts">
|
||||
import { Minimize2, Moon, Sun } from '@lucide/svelte';
|
||||
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
import { Minimize2, Moon, Sun } from '@lucide/svelte';
|
||||
import {
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
slct,
|
||||
slct_trigger
|
||||
} from '$lib/stores/ae_stores';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
set_theme_mode: any;
|
||||
set_theme_name: any;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hide?: null | boolean;
|
||||
expand?: boolean;
|
||||
set_theme_mode: any;
|
||||
set_theme_name: any;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false),
|
||||
set_theme_mode,
|
||||
set_theme_name
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = $bindable(0),
|
||||
hide = $bindable(false),
|
||||
expand = $bindable(false),
|
||||
set_theme_mode,
|
||||
set_theme_name
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<!-- Change light and dark mode -->
|
||||
@@ -37,25 +43,23 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
|
||||
bg-surface-100 dark:bg-surface-800
|
||||
text-surface-900 dark:text-surface-100
|
||||
border border-surface-200 dark:border-surface-700
|
||||
border-surface-200 dark:border-surface-700 flex
|
||||
|
||||
flex flex-col flex-wrap gap-1
|
||||
w-72 max-w-72 flex-col flex-wrap
|
||||
items-end justify-center
|
||||
|
||||
w-72 max-w-72
|
||||
gap-1 rounded-lg
|
||||
border
|
||||
p-1
|
||||
rounded-lg
|
||||
shadow-md
|
||||
|
||||
duration-300 delay-150 hover:delay-1000 hover:ease-out
|
||||
transition-all
|
||||
transition-all delay-150 duration-300 hover:delay-1000
|
||||
hover:ease-out
|
||||
"
|
||||
class:hidden={hide}
|
||||
>
|
||||
class:hidden={hide}>
|
||||
<div
|
||||
class:hidden={!expand}
|
||||
class="flex flex-row flex-wrap gap-2 items-center justify-between w-full"
|
||||
>
|
||||
class="flex w-full flex-row flex-wrap items-center justify-between gap-2">
|
||||
<!-- Theme Name: -->
|
||||
<span class="text-sm font-semibold">
|
||||
{$ae_loc.theme_name}
|
||||
@@ -74,7 +78,10 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
// document.body.setAttribute('data-theme', $ae_loc?.theme_name);
|
||||
|
||||
// NEW for Tailwind v4: Update the html attribute named "data-theme" to the current theme name.
|
||||
document.documentElement.setAttribute('data-theme', new_theme_name);
|
||||
document.documentElement.setAttribute(
|
||||
'data-theme',
|
||||
new_theme_name
|
||||
);
|
||||
|
||||
// if ($ae_loc.theme_mode == 'light') {
|
||||
// document.documentElement.classList.remove('dark');
|
||||
@@ -86,8 +93,7 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
}}
|
||||
bind:value={$ae_loc.theme_name}
|
||||
class="select w-32"
|
||||
title="Theme name"
|
||||
>
|
||||
title="Theme name">
|
||||
<option value="">-- None --</option>
|
||||
<option value="cerberus">Cerberus</option>
|
||||
<option value="concord">Concord</option>
|
||||
@@ -112,41 +118,38 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-row flex-wrap gap-2 items-center w-full"
|
||||
class="flex w-full flex-row flex-wrap items-center gap-2"
|
||||
class:justify-between={expand}
|
||||
class:justify-end={!expand}
|
||||
>
|
||||
class:justify-end={!expand}>
|
||||
{#if expand}
|
||||
<!-- Hide theme options -->
|
||||
<button
|
||||
class="
|
||||
btn btn-sm text-xs
|
||||
preset-tonal-secondary hover:preset-filled-secondary-500
|
||||
transition-all group
|
||||
btn btn-sm preset-tonal-secondary
|
||||
hover:preset-filled-secondary-500 group
|
||||
text-xs transition-all
|
||||
"
|
||||
onclick={() => {
|
||||
expand = !expand;
|
||||
}}
|
||||
title="Hide Theme Options"
|
||||
>
|
||||
title="Hide Theme Options">
|
||||
<!-- <span class="fas fa-compress-alt"></span> -->
|
||||
<Minimize2 size="1em" class="m-1" />
|
||||
<span
|
||||
class="
|
||||
hidden
|
||||
group-hover:inline-block
|
||||
text-xs
|
||||
"
|
||||
>
|
||||
group-hover:inline-block
|
||||
">
|
||||
Hide Theme Options
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="
|
||||
btn btn-sm text-xs
|
||||
preset-tonal-secondary hover:preset-filled-secondary-500
|
||||
transition-all group
|
||||
btn btn-sm preset-tonal-secondary
|
||||
hover:preset-filled-secondary-500 group
|
||||
text-xs transition-all
|
||||
"
|
||||
onclick={() => {
|
||||
if ($ae_loc.theme_mode == 'light') {
|
||||
@@ -157,23 +160,24 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
|
||||
// DOM sync is handled reactively by the layout effect in +layout.svelte
|
||||
}}
|
||||
title="Change light and dark mode"
|
||||
>
|
||||
title="Change light and dark mode">
|
||||
<!-- <span class="fas fa-adjust"></span> -->
|
||||
{#if $ae_loc.theme_mode == 'light'}
|
||||
<Sun class="m-1" />
|
||||
<span class="hidden md:inline-block group-hover:inline-block">Light Mode</span>
|
||||
<span
|
||||
class="hidden group-hover:inline-block md:inline-block"
|
||||
>Light Mode</span>
|
||||
{:else if $ae_loc.theme_mode == 'dark'}
|
||||
<Moon class="m-1" />
|
||||
<span class="hidden group-hover:inline-block">Dark Mode</span>
|
||||
<span class="hidden group-hover:inline-block"
|
||||
>Dark Mode</span>
|
||||
{/if}
|
||||
<span
|
||||
class="
|
||||
hidden
|
||||
group-hover:inline-block
|
||||
text-xs
|
||||
"
|
||||
>
|
||||
group-hover:inline-block
|
||||
">
|
||||
Change
|
||||
</span>
|
||||
</button>
|
||||
@@ -197,18 +201,19 @@ if ($ae_loc.app_cfg.theme_mode == 'light') {
|
||||
|
||||
expand = !expand;
|
||||
}}
|
||||
title="Change light and dark mode"
|
||||
>
|
||||
title="Change light and dark mode">
|
||||
{#if $ae_loc.theme_mode == 'light'}
|
||||
<span class="inline-block" title="Light Mode">
|
||||
<Sun />
|
||||
</span>
|
||||
<span class="hidden group-hover:inline-block">Light Mode</span>
|
||||
<span class="hidden group-hover:inline-block"
|
||||
>Light Mode</span>
|
||||
{:else if $ae_loc.theme_mode == 'dark'}
|
||||
<span class="inline-block" title="Dark Mode">
|
||||
<Moon />
|
||||
</span>
|
||||
<span class="hidden group-hover:inline-block">Dark Mode</span>
|
||||
<span class="hidden group-hover:inline-block"
|
||||
>Dark Mode</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -1,120 +1,136 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* e_app_url_builder.svelte
|
||||
* URL Param Builder — lets admins construct and copy shareable URLs
|
||||
* with any combination of the supported URL params applied.
|
||||
*
|
||||
* Core params:
|
||||
* ?iframe=true|false — persist kiosk mode (stays in URL)
|
||||
* ?theme=<name> — set theme name on load (stripped after apply)
|
||||
* ?theme_mode=light|dark — set light/dark mode on load (stripped after apply)
|
||||
* ?key=<access_key> — site access key
|
||||
*
|
||||
* Launcher params (all stripped from URL after apply):
|
||||
* ?launcher_menu=hide|show
|
||||
* ?launcher_header=hide|show
|
||||
* ?launcher_footer=hide|show
|
||||
*/
|
||||
import { page } from '$app/stores';
|
||||
import { Copy, Check, Link } from '@lucide/svelte';
|
||||
/**
|
||||
* e_app_url_builder.svelte
|
||||
* URL Param Builder — lets admins construct and copy shareable URLs
|
||||
* with any combination of the supported URL params applied.
|
||||
*
|
||||
* Core params:
|
||||
* ?iframe=true|false — persist kiosk mode (stays in URL)
|
||||
* ?theme=<name> — set theme name on load (stripped after apply)
|
||||
* ?theme_mode=light|dark — set light/dark mode on load (stripped after apply)
|
||||
* ?key=<access_key> — site access key
|
||||
*
|
||||
* Launcher params (all stripped from URL after apply):
|
||||
* ?launcher_menu=hide|show
|
||||
* ?launcher_header=hide|show
|
||||
* ?launcher_footer=hide|show
|
||||
*/
|
||||
import { page } from '$app/stores';
|
||||
import { Copy, Check, Link } from '@lucide/svelte';
|
||||
|
||||
// --- Per-param: include this param in the output URL?
|
||||
let use_iframe = $state(false);
|
||||
let use_theme = $state(false);
|
||||
let use_theme_mode = $state(false);
|
||||
let use_key = $state(false);
|
||||
let use_launcher_menu = $state(false);
|
||||
let use_launcher_header = $state(false);
|
||||
let use_launcher_footer = $state(false);
|
||||
// --- Per-param: include this param in the output URL?
|
||||
let use_iframe = $state(false);
|
||||
let use_theme = $state(false);
|
||||
let use_theme_mode = $state(false);
|
||||
let use_key = $state(false);
|
||||
let use_launcher_menu = $state(false);
|
||||
let use_launcher_header = $state(false);
|
||||
let use_launcher_footer = $state(false);
|
||||
|
||||
// --- Param values
|
||||
let val_iframe = $state<'true' | 'false'>('true');
|
||||
let val_theme = $state('nouveau');
|
||||
let val_theme_mode = $state<'light' | 'dark'>('dark');
|
||||
let val_key = $state('');
|
||||
let val_launcher_menu = $state<'hide' | 'show'>('hide');
|
||||
let val_launcher_header = $state<'hide' | 'show'>('hide');
|
||||
let val_launcher_footer = $state<'hide' | 'show'>('hide');
|
||||
// --- Param values
|
||||
let val_iframe = $state<'true' | 'false'>('true');
|
||||
let val_theme = $state('nouveau');
|
||||
let val_theme_mode = $state<'light' | 'dark'>('dark');
|
||||
let val_key = $state('');
|
||||
let val_launcher_menu = $state<'hide' | 'show'>('hide');
|
||||
let val_launcher_header = $state<'hide' | 'show'>('hide');
|
||||
let val_launcher_footer = $state<'hide' | 'show'>('hide');
|
||||
|
||||
// Build the output URL reactively
|
||||
let built_url = $derived.by(() => {
|
||||
const base = $page.url;
|
||||
const u = new URL(base.pathname + base.search + base.hash, base.origin);
|
||||
// Build the output URL reactively
|
||||
let built_url = $derived.by(() => {
|
||||
const base = $page.url;
|
||||
const u = new URL(base.pathname + base.search + base.hash, base.origin);
|
||||
|
||||
// Remove all known params first so we start clean each time
|
||||
u.searchParams.delete('iframe');
|
||||
u.searchParams.delete('theme');
|
||||
u.searchParams.delete('theme_mode');
|
||||
u.searchParams.delete('key');
|
||||
u.searchParams.delete('launcher_menu');
|
||||
u.searchParams.delete('launcher_header');
|
||||
u.searchParams.delete('launcher_footer');
|
||||
// Remove all known params first so we start clean each time
|
||||
u.searchParams.delete('iframe');
|
||||
u.searchParams.delete('theme');
|
||||
u.searchParams.delete('theme_mode');
|
||||
u.searchParams.delete('key');
|
||||
u.searchParams.delete('launcher_menu');
|
||||
u.searchParams.delete('launcher_header');
|
||||
u.searchParams.delete('launcher_footer');
|
||||
|
||||
if (use_iframe) u.searchParams.set('iframe', val_iframe);
|
||||
if (use_theme) u.searchParams.set('theme', val_theme);
|
||||
if (use_theme_mode) u.searchParams.set('theme_mode', val_theme_mode);
|
||||
if (use_key && val_key.trim()) u.searchParams.set('key', val_key.trim());
|
||||
if (use_launcher_menu) u.searchParams.set('launcher_menu', val_launcher_menu);
|
||||
if (use_launcher_header) u.searchParams.set('launcher_header', val_launcher_header);
|
||||
if (use_launcher_footer) u.searchParams.set('launcher_footer', val_launcher_footer);
|
||||
if (use_iframe) u.searchParams.set('iframe', val_iframe);
|
||||
if (use_theme) u.searchParams.set('theme', val_theme);
|
||||
if (use_theme_mode) u.searchParams.set('theme_mode', val_theme_mode);
|
||||
if (use_key && val_key.trim()) u.searchParams.set('key', val_key.trim());
|
||||
if (use_launcher_menu)
|
||||
u.searchParams.set('launcher_menu', val_launcher_menu);
|
||||
if (use_launcher_header)
|
||||
u.searchParams.set('launcher_header', val_launcher_header);
|
||||
if (use_launcher_footer)
|
||||
u.searchParams.set('launcher_footer', val_launcher_footer);
|
||||
|
||||
return u.toString();
|
||||
return u.toString();
|
||||
});
|
||||
|
||||
// Output mode: full URL (default) or params-only string
|
||||
let params_only = $state(false);
|
||||
|
||||
let output = $derived.by(() => {
|
||||
if (!params_only) return built_url;
|
||||
const u = new URL(built_url);
|
||||
return u.search || '(no params set)';
|
||||
});
|
||||
|
||||
let copied = $state(false);
|
||||
|
||||
function copy_url() {
|
||||
navigator.clipboard.writeText(output).then(() => {
|
||||
copied = true;
|
||||
setTimeout(() => (copied = false), 2000);
|
||||
});
|
||||
}
|
||||
|
||||
// Output mode: full URL (default) or params-only string
|
||||
let params_only = $state(false);
|
||||
|
||||
let output = $derived.by(() => {
|
||||
if (!params_only) return built_url;
|
||||
const u = new URL(built_url);
|
||||
return u.search || '(no params set)';
|
||||
});
|
||||
|
||||
let copied = $state(false);
|
||||
|
||||
function copy_url() {
|
||||
navigator.clipboard.writeText(output).then(() => {
|
||||
copied = true;
|
||||
setTimeout(() => copied = false, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
const theme_options = [
|
||||
{ value: 'cerberus', label: 'Cerberus' },
|
||||
{ value: 'concord', label: 'Concord' },
|
||||
{ value: 'crimson', label: 'Crimson' },
|
||||
{ value: 'hamlindigo', label: 'Hamlindigo' },
|
||||
{ value: 'modern', label: 'Modern' },
|
||||
{ value: 'nouveau', label: 'Nouveau' },
|
||||
{ value: 'rocket', label: 'Rocket' },
|
||||
{ value: 'terminus', label: 'Terminus' },
|
||||
{ value: 'vintage', label: 'Vintage' },
|
||||
{ value: 'wintry', label: 'Wintry' },
|
||||
{ value: 'AE_OSIT_default', label: 'OSIT' },
|
||||
{ value: 'AE_Firefly', label: 'Firefly ✦' },
|
||||
{ value: 'AE_Firefly_SteelBlue', label: 'Firefly SteelBlue ✦' },
|
||||
{ value: 'AE_Firefly_Indigo', label: 'Firefly Indigo ✦' },
|
||||
{ value: 'AE_Firefly_Rainbow', label: 'Firefly Rainbow ✨' },
|
||||
{ value: 'AE_c_IDAA_light', label: 'IDAA – light' },
|
||||
{ value: 'AE_c_LCI', label: 'LCI' },
|
||||
];
|
||||
const theme_options = [
|
||||
{ value: 'cerberus', label: 'Cerberus' },
|
||||
{ value: 'concord', label: 'Concord' },
|
||||
{ value: 'crimson', label: 'Crimson' },
|
||||
{ value: 'hamlindigo', label: 'Hamlindigo' },
|
||||
{ value: 'modern', label: 'Modern' },
|
||||
{ value: 'nouveau', label: 'Nouveau' },
|
||||
{ value: 'rocket', label: 'Rocket' },
|
||||
{ value: 'terminus', label: 'Terminus' },
|
||||
{ value: 'vintage', label: 'Vintage' },
|
||||
{ value: 'wintry', label: 'Wintry' },
|
||||
{ value: 'AE_OSIT_default', label: 'OSIT' },
|
||||
{ value: 'AE_Firefly', label: 'Firefly ✦' },
|
||||
{ value: 'AE_Firefly_SteelBlue', label: 'Firefly SteelBlue ✦' },
|
||||
{ value: 'AE_Firefly_Indigo', label: 'Firefly Indigo ✦' },
|
||||
{ value: 'AE_Firefly_Rainbow', label: 'Firefly Rainbow ✨' },
|
||||
{ value: 'AE_c_IDAA_light', label: 'IDAA – light' },
|
||||
{ value: 'AE_c_LCI', label: 'LCI' }
|
||||
];
|
||||
</script>
|
||||
|
||||
<section class="space-y-3 text-sm">
|
||||
|
||||
<h2 class="text-xs font-semibold uppercase tracking-widest text-surface-500 dark:text-surface-400 flex items-center gap-1">
|
||||
<h2
|
||||
class="text-surface-500 dark:text-surface-400 flex items-center gap-1 text-xs font-semibold tracking-widest uppercase">
|
||||
<Link size="0.9em" /> URL Param Builder
|
||||
</h2>
|
||||
|
||||
<!-- ── Core params ─────────────────────────────────────────────────── -->
|
||||
<div class="space-y-1.5">
|
||||
<p class="text-[9px] font-bold uppercase tracking-widest opacity-40 ml-0.5">Core</p>
|
||||
<p
|
||||
class="ml-0.5 text-[9px] font-bold tracking-widest uppercase opacity-40">
|
||||
Core
|
||||
</p>
|
||||
|
||||
<!-- iframe -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_iframe" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_iframe} />
|
||||
<label for="ubld_iframe" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_iframe}>iframe</label>
|
||||
<select bind:value={val_iframe} disabled={!use_iframe} class="select select-sm text-xs flex-1 disabled:opacity-40">
|
||||
<input
|
||||
id="ubld_iframe"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_iframe} />
|
||||
<label
|
||||
for="ubld_iframe"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_iframe}>iframe</label>
|
||||
<select
|
||||
bind:value={val_iframe}
|
||||
disabled={!use_iframe}
|
||||
class="select select-sm flex-1 text-xs disabled:opacity-40">
|
||||
<option value="true">true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
@@ -122,9 +138,19 @@
|
||||
|
||||
<!-- theme -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_theme" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_theme} />
|
||||
<label for="ubld_theme" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_theme}>theme</label>
|
||||
<select bind:value={val_theme} disabled={!use_theme} class="select select-sm text-xs flex-1 disabled:opacity-40">
|
||||
<input
|
||||
id="ubld_theme"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_theme} />
|
||||
<label
|
||||
for="ubld_theme"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_theme}>theme</label>
|
||||
<select
|
||||
bind:value={val_theme}
|
||||
disabled={!use_theme}
|
||||
class="select select-sm flex-1 text-xs disabled:opacity-40">
|
||||
{#each theme_options as opt}
|
||||
<option value={opt.value}>{opt.label}</option>
|
||||
{/each}
|
||||
@@ -133,9 +159,19 @@
|
||||
|
||||
<!-- theme_mode -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_theme_mode" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_theme_mode} />
|
||||
<label for="ubld_theme_mode" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_theme_mode}>theme_mode</label>
|
||||
<select bind:value={val_theme_mode} disabled={!use_theme_mode} class="select select-sm text-xs flex-1 disabled:opacity-40">
|
||||
<input
|
||||
id="ubld_theme_mode"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_theme_mode} />
|
||||
<label
|
||||
for="ubld_theme_mode"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_theme_mode}>theme_mode</label>
|
||||
<select
|
||||
bind:value={val_theme_mode}
|
||||
disabled={!use_theme_mode}
|
||||
class="select select-sm flex-1 text-xs disabled:opacity-40">
|
||||
<option value="light">light</option>
|
||||
<option value="dark">dark</option>
|
||||
</select>
|
||||
@@ -143,27 +179,46 @@
|
||||
|
||||
<!-- key -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_key" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_key} />
|
||||
<label for="ubld_key" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_key}>key</label>
|
||||
<input
|
||||
id="ubld_key"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_key} />
|
||||
<label
|
||||
for="ubld_key"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_key}>key</label>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={val_key}
|
||||
disabled={!use_key}
|
||||
placeholder="access key"
|
||||
class="input input-sm text-xs font-mono flex-1 disabled:opacity-40"
|
||||
/>
|
||||
class="input input-sm flex-1 font-mono text-xs disabled:opacity-40" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Launcher params ─────────────────────────────────────────────── -->
|
||||
<div class="space-y-1.5 border-t border-surface-500/20 pt-2.5">
|
||||
<p class="text-[9px] font-bold uppercase tracking-widest opacity-40 ml-0.5">Launcher</p>
|
||||
<div class="border-surface-500/20 space-y-1.5 border-t pt-2.5">
|
||||
<p
|
||||
class="ml-0.5 text-[9px] font-bold tracking-widest uppercase opacity-40">
|
||||
Launcher
|
||||
</p>
|
||||
|
||||
<!-- launcher_menu -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_launcher_menu" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_launcher_menu} />
|
||||
<label for="ubld_launcher_menu" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_launcher_menu}>menu</label>
|
||||
<select bind:value={val_launcher_menu} disabled={!use_launcher_menu} class="select select-sm text-xs flex-1 disabled:opacity-40">
|
||||
<input
|
||||
id="ubld_launcher_menu"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_launcher_menu} />
|
||||
<label
|
||||
for="ubld_launcher_menu"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_launcher_menu}>menu</label>
|
||||
<select
|
||||
bind:value={val_launcher_menu}
|
||||
disabled={!use_launcher_menu}
|
||||
class="select select-sm flex-1 text-xs disabled:opacity-40">
|
||||
<option value="hide">hide</option>
|
||||
<option value="show">show</option>
|
||||
</select>
|
||||
@@ -171,9 +226,19 @@
|
||||
|
||||
<!-- launcher_header -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_launcher_header" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_launcher_header} />
|
||||
<label for="ubld_launcher_header" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_launcher_header}>header</label>
|
||||
<select bind:value={val_launcher_header} disabled={!use_launcher_header} class="select select-sm text-xs flex-1 disabled:opacity-40">
|
||||
<input
|
||||
id="ubld_launcher_header"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_launcher_header} />
|
||||
<label
|
||||
for="ubld_launcher_header"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_launcher_header}>header</label>
|
||||
<select
|
||||
bind:value={val_launcher_header}
|
||||
disabled={!use_launcher_header}
|
||||
class="select select-sm flex-1 text-xs disabled:opacity-40">
|
||||
<option value="hide">hide</option>
|
||||
<option value="show">show</option>
|
||||
</select>
|
||||
@@ -181,9 +246,19 @@
|
||||
|
||||
<!-- launcher_footer -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_launcher_footer" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={use_launcher_footer} />
|
||||
<label for="ubld_launcher_footer" class="w-24 text-xs font-mono cursor-pointer select-none" class:opacity-35={!use_launcher_footer}>footer</label>
|
||||
<select bind:value={val_launcher_footer} disabled={!use_launcher_footer} class="select select-sm text-xs flex-1 disabled:opacity-40">
|
||||
<input
|
||||
id="ubld_launcher_footer"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={use_launcher_footer} />
|
||||
<label
|
||||
for="ubld_launcher_footer"
|
||||
class="w-24 cursor-pointer font-mono text-xs select-none"
|
||||
class:opacity-35={!use_launcher_footer}>footer</label>
|
||||
<select
|
||||
bind:value={val_launcher_footer}
|
||||
disabled={!use_launcher_footer}
|
||||
class="select select-sm flex-1 text-xs disabled:opacity-40">
|
||||
<option value="hide">hide</option>
|
||||
<option value="show">show</option>
|
||||
</select>
|
||||
@@ -191,26 +266,33 @@
|
||||
</div>
|
||||
|
||||
<!-- ── Output ──────────────────────────────────────────────────────── -->
|
||||
<div class="border-t border-surface-500/20 pt-2.5 space-y-1.5">
|
||||
<div class="border-surface-500/20 space-y-1.5 border-t pt-2.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<input id="ubld_params_only" type="checkbox" class="checkbox checkbox-sm shrink-0" bind:checked={params_only} />
|
||||
<label for="ubld_params_only" class="text-xs cursor-pointer select-none" class:opacity-35={!params_only}>Params only</label>
|
||||
<input
|
||||
id="ubld_params_only"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm shrink-0"
|
||||
bind:checked={params_only} />
|
||||
<label
|
||||
for="ubld_params_only"
|
||||
class="cursor-pointer text-xs select-none"
|
||||
class:opacity-35={!params_only}>Params only</label>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1 items-stretch">
|
||||
<div class="flex items-stretch gap-1">
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
value={output}
|
||||
class="input input-sm text-xs font-mono flex-1 bg-surface-50/50 dark:bg-surface-700/50 cursor-text"
|
||||
class="input input-sm bg-surface-50/50 dark:bg-surface-700/50 flex-1 cursor-text font-mono text-xs"
|
||||
onclick={(e) => (e.target as HTMLInputElement).select()}
|
||||
title="Click to select all"
|
||||
/>
|
||||
title="Click to select all" />
|
||||
<button
|
||||
class="btn btn-sm {copied ? 'preset-filled-success' : 'preset-tonal-primary'} shrink-0 transition-all"
|
||||
class="btn btn-sm {copied
|
||||
? 'preset-filled-success'
|
||||
: 'preset-tonal-primary'} shrink-0 transition-all"
|
||||
onclick={copy_url}
|
||||
title="Copy URL to clipboard"
|
||||
>
|
||||
title="Copy URL to clipboard">
|
||||
{#if copied}
|
||||
<Check size="1em" />
|
||||
{:else}
|
||||
@@ -219,5 +301,4 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -1,57 +1,62 @@
|
||||
<script lang="ts" module>
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
||||
import { type VariantProps, tv } from 'tailwind-variants';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type {
|
||||
HTMLAnchorAttributes,
|
||||
HTMLButtonAttributes
|
||||
} from 'svelte/elements';
|
||||
import { type VariantProps, tv } from 'tailwind-variants';
|
||||
|
||||
export const buttonVariants = tv({
|
||||
base: 'ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline:
|
||||
'border-input bg-background hover:bg-accent hover:text-accent-foreground border',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline'
|
||||
},
|
||||
size: {
|
||||
default: 'h-10 px-4 py-2',
|
||||
sm: 'h-9 rounded-md px-3',
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10'
|
||||
}
|
||||
export const buttonVariants = tv({
|
||||
base: 'ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline:
|
||||
'border-input bg-background hover:bg-accent hover:text-accent-foreground border',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline'
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default'
|
||||
size: {
|
||||
default: 'h-10 px-4 py-2',
|
||||
sm: 'h-9 rounded-md px-3',
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10'
|
||||
}
|
||||
});
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
|
||||
export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
|
||||
export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
|
||||
export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
|
||||
|
||||
export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
|
||||
WithElementRef<HTMLAnchorAttributes> & {
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
class?: any;
|
||||
};
|
||||
export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
|
||||
WithElementRef<HTMLAnchorAttributes> & {
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
class?: any;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
class: className,
|
||||
variant = 'default',
|
||||
size = 'default',
|
||||
ref = $bindable(null),
|
||||
href = undefined,
|
||||
type = 'button',
|
||||
children,
|
||||
...restProps
|
||||
}: ButtonProps = $props();
|
||||
let {
|
||||
class: className,
|
||||
variant = 'default',
|
||||
size = 'default',
|
||||
ref = $bindable(null),
|
||||
href = undefined,
|
||||
type = 'button',
|
||||
children,
|
||||
...restProps
|
||||
}: ButtonProps = $props();
|
||||
</script>
|
||||
|
||||
{#if href}
|
||||
@@ -59,8 +64,7 @@
|
||||
bind:this={ref}
|
||||
class={cn(buttonVariants({ variant, size, className }))}
|
||||
{href}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{@render children?.()}
|
||||
</a>
|
||||
{:else}
|
||||
@@ -68,8 +72,7 @@
|
||||
bind:this={ref}
|
||||
class={cn(buttonVariants({ variant, size, className }))}
|
||||
{type}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
||||
import Check from 'lucide-svelte/icons/check';
|
||||
import Minus from 'lucide-svelte/icons/minus';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import type { Snippet } from 'svelte';
|
||||
import {
|
||||
DropdownMenu as DropdownMenuPrimitive,
|
||||
type WithoutChildrenOrChild
|
||||
} from 'bits-ui';
|
||||
import Check from 'lucide-svelte/icons/check';
|
||||
import Minus from 'lucide-svelte/icons/minus';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
checked = $bindable(false),
|
||||
indeterminate = $bindable(false),
|
||||
class: className,
|
||||
children: childrenProp,
|
||||
...restProps
|
||||
}: WithoutChildrenOrChild<DropdownMenuPrimitive.CheckboxItemProps> & {
|
||||
children?: Snippet;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
checked = $bindable(false),
|
||||
indeterminate = $bindable(false),
|
||||
class: className,
|
||||
children: childrenProp,
|
||||
...restProps
|
||||
}: WithoutChildrenOrChild<DropdownMenuPrimitive.CheckboxItemProps> & {
|
||||
children?: Snippet;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
@@ -22,11 +25,10 @@
|
||||
bind:checked
|
||||
bind:indeterminate
|
||||
class={cn(
|
||||
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{#snippet children({ checked, indeterminate })}
|
||||
<span class="absolute left-2 flex size-3.5 items-center justify-center">
|
||||
{#if indeterminate}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
sideOffset = 4,
|
||||
portalProps,
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.ContentProps & {
|
||||
portalProps?: DropdownMenuPrimitive.PortalProps;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
sideOffset = 4,
|
||||
portalProps,
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.ContentProps & {
|
||||
portalProps?: DropdownMenuPrimitive.PortalProps;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Portal {...portalProps}>
|
||||
@@ -21,6 +21,5 @@
|
||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md outline-hidden',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.GroupHeadingProps & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.GroupHeadingProps & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.GroupHeading
|
||||
bind:ref
|
||||
class={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.ItemProps & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.ItemProps & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Item
|
||||
bind:ref
|
||||
class={cn(
|
||||
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
class={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChild } from 'bits-ui';
|
||||
import Circle from 'lucide-svelte/icons/circle';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import {
|
||||
DropdownMenu as DropdownMenuPrimitive,
|
||||
type WithoutChild
|
||||
} from 'bits-ui';
|
||||
import Circle from 'lucide-svelte/icons/circle';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children: childrenProp,
|
||||
...restProps
|
||||
}: WithoutChild<DropdownMenuPrimitive.RadioItemProps> = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children: childrenProp,
|
||||
...restProps
|
||||
}: WithoutChild<DropdownMenuPrimitive.RadioItemProps> = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
bind:ref
|
||||
class={cn(
|
||||
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{#snippet children({ checked })}
|
||||
<span class="absolute left-2 flex size-3.5 items-center justify-center">
|
||||
{#if checked}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SeparatorProps = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SeparatorProps = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Separator
|
||||
bind:ref
|
||||
class={cn('bg-muted -mx-1 my-1 h-px', className)}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
|
||||
</script>
|
||||
|
||||
<span
|
||||
bind:this={ref}
|
||||
class={cn('ml-auto text-xs tracking-widest opacity-60', className)}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{@render children?.()}
|
||||
</span>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SubContentProps = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SubContentProps = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
@@ -15,5 +15,4 @@
|
||||
'bg-popover text-popover-foreground z-50 min-w-32 rounded-md border p-1 shadow-lg focus:outline-hidden',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import ChevronRight from 'lucide-svelte/icons/chevron-right';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import ChevronRight from 'lucide-svelte/icons/chevron-right';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
children,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SubTriggerProps & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
inset,
|
||||
children,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SubTriggerProps & {
|
||||
inset?: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
bind:ref
|
||||
class={cn(
|
||||
'data-[highlighted]:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'data-[highlighted]:bg-accent data-[state=open]:bg-accent flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
>
|
||||
{...restProps}>
|
||||
{@render children?.()}
|
||||
<ChevronRight class="ml-auto" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLInputAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import type { HTMLInputAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
value = $bindable(),
|
||||
class: className,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLInputAttributes> = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
value = $bindable(),
|
||||
class: className,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLInputAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<input
|
||||
bind:this={ref}
|
||||
class={cn(
|
||||
'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
bind:value
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { Popover as PopoverPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { Popover as PopoverPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
sideOffset = 4,
|
||||
align = 'center',
|
||||
portalProps,
|
||||
...restProps
|
||||
}: PopoverPrimitive.ContentProps & {
|
||||
portalProps?: PopoverPrimitive.PortalProps;
|
||||
} = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
sideOffset = 4,
|
||||
align = 'center',
|
||||
portalProps,
|
||||
...restProps
|
||||
}: PopoverPrimitive.ContentProps & {
|
||||
portalProps?: PopoverPrimitive.PortalProps;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<PopoverPrimitive.Portal {...portalProps}>
|
||||
@@ -23,6 +23,5 @@
|
||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-hidden',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
</PopoverPrimitive.Portal>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { Separator as SeparatorPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
import { Separator as SeparatorPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
orientation = 'horizontal',
|
||||
...restProps
|
||||
}: SeparatorPrimitive.RootProps = $props();
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
orientation = 'horizontal',
|
||||
...restProps
|
||||
}: SeparatorPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<SeparatorPrimitive.Root
|
||||
@@ -18,5 +18,4 @@
|
||||
className
|
||||
)}
|
||||
{orientation}
|
||||
{...restProps}
|
||||
/>
|
||||
{...restProps} />
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user