Work on general clean up. Better export and email of sponsor data

This commit is contained in:
Scott Idem
2024-05-03 17:07:08 -04:00
parent a3a32e188d
commit f72d7be5b2
11 changed files with 984 additions and 5 deletions

View File

@@ -36,7 +36,7 @@ export type key_val = {
// *** BEGIN *** Longer-term app data. This should be stored to local storage.
export let ae_app_local_data_struct: key_val = {
'ver': '2024-03-06_18',
'ver': '2024-05-01_15',
'name': 'Aether - App Hub (SvelteKit 2.x Svelte 4.x)',
'theme': 'light',
'iframe': false,
@@ -66,6 +66,8 @@ export let ae_app_local_data_struct: key_val = {
'authenticated_access': false,
'anonymous_access': true,
'user_email': null,
'qry__enabled': 'enabled', // all, disabled, enabled
'qry__hidden': 'not_hidden', // all, hidden, not_hidden
'qry__limit': 20,
@@ -73,6 +75,11 @@ export let ae_app_local_data_struct: key_val = {
qr_scanner_version: 'one',
'admin': {
show_element__sql_qry: false,
show_element__sql_qry_results: false,
},
'ds': {},
'hub': {
'show_element__cfg': true,

View File

@@ -610,6 +610,234 @@ function count_words(text: string) {
}
/* Adapted from: To Title Case © 2018 David Gouch | https://github.com/gouch/to-title-case */
// eslint-disable-next-line no-extend-native
function to_title_case (text_string) {
// console.log('*** to_title_case() ***');
let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|v.?|vs.?|via)$/i
let alphanumericPattern = /([A-Za-z0-9\u00C0-\u00FF])/
let wordSeparators = /([ :–—-])/
return text_string.split(wordSeparators)
.map(function (current, index, array) {
if (
/* Check for small words */
current.search(smallWords) > -1 &&
/* Skip first and last word */
index !== 0 &&
index !== array.length - 1 &&
/* Ignore title end and subtitle start */
array[index - 3] !== ':' &&
array[index + 1] !== ':' &&
/* Ignore small words that start a hyphenated phrase */
(array[index + 1] !== '-' ||
(array[index - 1] === '-' && array[index + 1] === '-'))
) {
return current.toLowerCase()
}
/* Ignore intentional capitalization */
if (current.substr(1).search(/[A-Z]|\../) > -1) {
return current
}
/* Ignore URLs */
if (array[index + 1] === ':' && array[index + 2] !== '') {
return current
}
/* Capitalize the first letter */
return current.replace(alphanumericPattern, function (match) {
return match.toUpperCase()
})
})
.join('')
}
// Updated 2023-08-18
function set_obj_prop_display_name({prop_name, obj_type=null, prefix_w_obj_type=true, prefix_all_w_obj_type=false, replace_underscores=true, title_case=true, override=null}) {
console.log('*** set_obj_prop_display_name() ***');
if (override) {
return override;
}
let known_obj_type_li = ['account', 'address', 'contact', 'event_badge', 'event_exhibit', 'event_file', 'event_location', 'event_person', 'event_presentation', 'event_presenter', 'event_registration', 'event_session', 'event', 'hosted_file', 'order_line', 'order', 'person', 'user'];
let known_obj_type_li_dict = [
{name: 'account', display: 'Account'},
{name: 'address', display: 'Address'},
{name: 'contact', display: 'Contact'},
{name: 'event_badge', display: 'Event Badge'},
{name: 'event_exhibit', display: 'Event Exhibit'},
{name: 'event_file', display: 'Event File'},
{name: 'event_location', display: 'Event Location'},
{name: 'event_person', display: 'Event Person'},
{name: 'event_presentation', display: 'Event Presentation'},
{name: 'event_presenter', display: 'Event Presenter'},
{name: 'event_registration', display: 'Event Registration'},
{name: 'event_session', display: 'Event Session'},
{name: 'event', display: 'Event'},
{name: 'hosted_file', display: 'Hosted File'},
{name: 'order_line', display: 'Order Line'},
{name: 'order', display: 'Order'},
{name: 'person', display: 'Person'},
{name: 'user', display: 'User'},
];
let prop_display_name = prop_name;
if (!prefix_w_obj_type) {
if (obj_type) {
prop_display_name = prop_name.replace(obj_type, '');
} else {
for (let i = 0; i < known_obj_type_li_dict.length; i++) {
// 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, '');
break;
}
}
// for (let i = 0; i < known_obj_type_li.length; i++) {
// // console.log(known_obj_type_li[i]);
// if (prop_name.startsWith(known_obj_type_li[i])) {
// console.log(`Found ${known_obj_type_li[i]}`);
// prop_display_name = prop_name.replace(known_obj_type_li[i], '');
// break;
// }
// }
}
} else {
if (!prefix_all_w_obj_type) {
for (let i = 0; i < known_obj_type_li.length; i++) {
// console.log(known_obj_type_li[i]);
let found_obj_type = null;
if (prop_name.startsWith(known_obj_type_li_dict[i].name)) {
// if (prop_name.startsWith(known_obj_type_li[i])) {
// 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, '');
}
break;
}
}
// if (obj_type) {
// prop_display_name = prop_name.replace(obj_type, '');
// } else {
}
}
// console.log(prop_display_name);
if (prop_display_name.search('ID')) {
}
prop_display_name = prop_display_name.replace('id_random', 'ID');
if (replace_underscores) {
prop_display_name = prop_display_name.replaceAll('_', ' ');
}
if (title_case) {
prop_display_name = to_title_case(prop_display_name);
}
// console.log(prop_display_name);
return prop_display_name;
}
function return_obj_type_path({obj_type=null, obj_type_prop_name=null}) {
console.log('*** set_obj_prop_display_name() ***');
let obj_type_path = null;
let known_obj_type_li = ['account', 'address', 'archive', 'archive_content', 'contact', 'event_badge', 'event_exhibit', 'event_file', 'event_location', 'event_person', 'event_presentation', 'event_presenter', 'event_registration', 'event_session', 'event', 'hosted_file', 'order_line', 'order', 'person', 'post', 'post_comment', 'user'];
let known_obj_type_li_dict = [
{name: 'account', display: 'Account', path: 'account'},
{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: '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_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_file', display: 'Event File', path: 'event/file'},
{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', 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: '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: 'user', display: 'User', path: 'user'},
];
if (obj_type) {
// Need to loop through known for safety?
obj_type_path = obj_type_prop_name.replaceAll('_', '/');
} else if (obj_type_prop_name) {
let found_obj_type_name = null;
let found_obj_type_path = null;
for (let i = 0; i < known_obj_type_li_dict.length; i++) {
// console.log(known_obj_type_li_dict[i]);
// let guessed_obj_type = prop_name.startsWith(known_obj_type_li_dict[i]
if (obj_type_prop_name.startsWith(known_obj_type_li_dict[i].name)) {
console.log(`Found ${known_obj_type_li_dict[i].name}`);
found_obj_type_name = known_obj_type_li_dict[i].name;
found_obj_type_path = known_obj_type_li_dict[i].path;
// obj_type_path = obj_type_prop_name.replaceAll('_', '/');
obj_type_path = found_obj_type_path;
break;
}
}
} else {
console.log('Missing required parameters');
return false;
}
return obj_type_path;
}
export let ae_util = {
iso_datetime_formatter: iso_datetime_formatter,
number_w_commas: number_w_commas,
@@ -621,5 +849,8 @@ export let ae_util = {
create_img_element: create_img_element,
create_video_element: create_video_element,
count_words: count_words,
to_title_case: to_title_case,
set_obj_prop_display_name: set_obj_prop_display_name,
return_obj_type_path: return_obj_type_path,
};
// export default ae_util;

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { createEventDispatcher, onMount, tick } from 'svelte';
import { createEventDispatcher, onMount } from 'svelte';
import { RadioGroup, RadioItem } from '@skeletonlabs/skeleton';
import { ae_util } from '$lib/ae_utils';

View File

@@ -40,7 +40,7 @@ let ds_submit_results: Promise<any>|key_val;
let val_json: key_val;
let val_html: key_val;
let val_md: key_val;
let val_sql: key_val;
export let val_sql: key_val;
let val_text: string;
@@ -597,6 +597,7 @@ async function handle_update__data_store({
Type: {ae_ds_tmp.type}
{/if}
<!-- Handle HTML type -->
{#if ae_ds_tmp.type == 'html' || ae_ds_tmp.type == null}
<textarea
name="ds_value"
@@ -605,6 +606,17 @@ async function handle_update__data_store({
rows="25"
placeholder="Enter the HTML here"
>{ae_ds_tmp.type == 'html' && ae_ds_tmp.html ? ae_ds_tmp.html : ''}</textarea>
<!-- Handle SQL type -->
{:else if ae_ds_tmp.type == 'sql'}
<textarea
name="ds_value"
class="textarea type_sql font-mono text-sm"
cols="75"
rows="25"
placeholder="Enter the SQL here"
>{ae_ds_tmp.type == 'sql' && ae_ds_tmp.text ? ae_ds_tmp.text : ''}</textarea>
<!-- Handle text type -->
{:else if ae_ds_tmp.type == 'text'}
<textarea
name="ds_value"

View File

@@ -0,0 +1,148 @@
<script lang="ts">
import { onMount } from 'svelte';
// This (ae) is only used for utilities
// import { ae } from 'aether_npm_lib';
import { ae_util } from '$lib/ae_utils';
// These (slct_*) are only used internally for this component. Not needed???
// import { slct_obj_id, slct_obj_li_type, slct_obj_type } from '../admin/stores_admin.js';
// Should these slct_* be exported???
let slct_obj_id = null;
let slct_obj_li_type = null;
let slct_obj_type = null;
export let row_header: boolean = false;
export let primary_obj_li_type: string = slct_obj_li_type; // account, person, user, event, event_session, membership_person
export let obj = null;
console.log(obj);
console.log(typeof obj);
/* BEGIN: Lifecycle functions (onMount, beforeUpdate, afterUpdate,
onDestroy, tick) */
onMount(() => {
console.log('** Element Mounted: ** Element Object Table Row');
if (obj) {
console.log('Table Row Object:', obj);
// console.log(typeof obj);
} else {
return false;
}
});
/* END: Lifecycle functions (onMount, beforeUpdate, afterUpdate,
onDestroy, tick) */
/* BEGIN: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
/* END: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
/* BEGIN: Handle other local actions (show/hide form, process data) */
/* END: Handle other local actions (show/hide form, process data) */
/* BEGIN: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
/* END: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
</script>
<tr>
{#if obj != null && typeof obj == 'object'}
{#each Object.entries(obj) as [obj_prop_name, obj_prop_value]}
<!-- NEED TO ADD A CHECK IF:
NOTE:
NOTE:
obj.id_random and obj.name then replace the ID field column with a link using obj.name
This should probably go outside/before this tr loop.
NOTE:
NOTE:
-->
{#if obj_prop_name.endsWith('_id_random') || obj_prop_name == 'for_type' || obj_prop_name == 'for_id'}
{#if row_header}
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name} on:click={() => primary_obj_li_type=obj_prop_name.replace('_id_random', '')}>
{ae_util.set_obj_prop_display_name({prop_name: obj_prop_name, obj_type: primary_obj_li_type})}
</th>
{:else}
<td
data-obj_type={primary_obj_li_type}
data-obj_prop_name={obj_prop_name}
on:click={() => {
slct_obj_type=obj_prop_name.replace('_id_random', '');
slct_obj_id=obj_prop_value;
}}
on:keypress={() => {
slct_obj_type=obj_prop_name.replace('_id_random', '');
slct_obj_id=obj_prop_value;
}}
>
<!-- {obj_prop_value} -->
<!-- {#if (obj_prop_value && obj_prop_value.length > 25)}
{obj_prop_value.substring(0,25)}
{:else} -->
{#if obj_prop_value}
<a href="/{ae_util.return_obj_type_path({obj_type_prop_name: obj_prop_name})}/{obj_prop_value}">
{obj_prop_value.substring(0,25)}
</a>
{:else}
<!-- {obj_prop_value} -->
<span class="fs_smaller">-- None --</span>
{/if}
</td>
{/if}
{:else if obj_prop_name.endsWith('[URL]')}
{#if row_header}
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name} on:click={() => primary_obj_li_type=obj_prop_name.replaceAll('[URL]', '')}>
{ae_util.set_obj_prop_display_name({prop_name: obj_prop_name.replaceAll('[URL]', ''), obj_type: primary_obj_li_type})}
</th>
{:else}
<td
data-obj_type={primary_obj_li_type}
data-obj_prop_name={obj_prop_name}
on:click={() => {
slct_obj_type=obj_prop_name.replaceAll('[URL]', '');
slct_obj_id=obj_prop_value;
}}
on:keypress={() => {
slct_obj_type=obj_prop_name.replaceAll('[URL]', '');
slct_obj_id=obj_prop_value;
}}
>
<a href="{obj_prop_value}">{obj_prop_value}</a>
</td>
{/if}
{:else}
{#if row_header}
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
{ae_util.set_obj_prop_display_name({prop_name: obj_prop_name, obj_type: primary_obj_li_type})}
</th>
{:else}
<td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
{#if (obj_prop_value)}
{#if (obj_prop_value && obj_prop_value.length > 25)}
{obj_prop_value.substring(0,25)} ...
{:else}
{obj_prop_value}
{/if}
{:else}
<span class="fs_smaller">-- None --</span>
{/if}
</td>
{/if}
{/if}
<!-- <td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>{obj_prop_value}</td> -->
{/each}
{:else}
-- Not Set --
{/if}
</tr>
<style lang="postcss">
</style>

View File

@@ -0,0 +1,146 @@
<script lang="ts">
import { onMount } from 'svelte';
// *** Import Aether core variables and functions
import type { key_val } from '$lib/ae_stores';
// import { api, Element_obj_tbl_row } from 'aether_npm_lib';
import Element_obj_tbl_row from '$lib/element_obj_tbl_row.svelte';
import { post_object } from './api.js';
// *** Import Aether core components
// import Element_obj_tbl_row from './element_obj_tbl_row.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let api_cfg: any;
export let show_textarea = true;
export let button_label = 'Run SQL!';
export let show_record_count = true;
export let remove_breaks = false;
export let run_on_load = false;
export let sql_statement: string;
export let sql_data = null;
export let as_list = false;
export let log_lvl = 1;
// *** Set initial variables
let ae_promises: key_val = {};
let sql_qry_result: any = null;
onMount(() => {
console.log('** Element Mounted: ** Element SQL Query');
if (run_on_load) {
console.log('Run On Load');
let result = handle_run_sql(sql_statement, sql_data, as_list, log_lvl)
.then((qry_result) => {
console.log('SQL Query Result:', qry_result);
sql_qry_result = qry_result;
return qry_result;
});
}
});
// const dispatch = createEventDispatcher();
async function handle_run_sql(qry, data, as_list=false, log_lvl=0) {
console.log('*** handle_run_sql() ***');
let sql_qry_data: key_val = {};
let endpoint = '/sql/select';
let params: key_val = {};
if (as_list) {
params['as_list'] = true;
}
if (log_lvl) {
console.log('Params:', params);
}
if (qry) {
} else {
return false;
}
if (log_lvl>1) {
console.log('Qry:', qry);
}
if (remove_breaks) {
sql_qry_data['sql_qry'] = qry.replace(/(\r\n|\n|\r)/gm, "");
} else {
sql_qry_data['sql_qry'] = qry;
}
sql_qry_data['sql_data'] = data;
if (log_lvl) {
console.log('SQL Qry Data:', sql_qry_data);
}
ae_promises.sql_qry_promise = await post_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: sql_qry_data, log_lvl: log_lvl});
if (log_lvl) {
console.log('SQL Query Results', ae_promises.sql_qry_promise);
}
return ae_promises.sql_qry_promise;
}
</script>
<section id="sql_qry" class="sql_qry">
{#if show_textarea}
<textarea
class="textarea"
bind:value={sql_statement}></textarea>
{/if}
<div class="text-center">
<button
type="button"
on:click={async () => {
sql_qry_result = await handle_run_sql(sql_statement, sql_data, as_list, log_lvl);
}}
class="btn btn-md variant-soft-primary hover:variant-ghost-primary"
>
{button_label}
</button>
</div>
{#if show_record_count && sql_qry_result && sql_qry_result.length}
<div>
Record count: <strong>{sql_qry_result.length}</strong>
</div>
{/if}
<div class="sql_statement_result">
{#await ae_promises.sql_qry_promise}
Getting results...
{:then}
{#if sql_qry_result && sql_qry_result.length}
<table class="table table-compact table-bordered table-striped table-hover min-w-min sql_qry_result text-xs">
<Element_obj_tbl_row row_header={true} obj={sql_qry_result[0]} primary_obj_li_type='' />
{#each sql_qry_result as record}
<Element_obj_tbl_row obj={record} primary_obj_li_type='' />
{/each}
</table>
{:else}
<div>Nothing to show yet...</div>
{/if}
{/await}
</div>
</section>
<style lang="postcss">
/* .sql_qry textarea {
width: 100%;
height: 8em;
} */
</style>