import { reactive, watch } from 'vue'; import vista from './vista.mjs'; import cookie from './cookie.mjs'; import { debounce, pipe, aflow } from './util.mjs'; import { lab_parse, lab_reparse_results, measurement_parse, orderinfo_parse, orderoverrides_parse, orderoptions_parse } from './reportparser.mjs'; import { TplFS, EncFS, randpassword as tplfs_randpassword } from './tplfs.mjs'; export const localstate = reactive(cookie.get('state') ? JSON.parse(cookie.get('state')) : {}); window.addEventListener('storage', function(evt) { if((evt.storageArea == window.localStorage) && (evt.key == 'state') && (evt.newValue)) Object.assign(localstate, JSON.parse(evt.newValue)); }); watch(localstate, function(value) { cookie.set('state', value = JSON.stringify(value), 45); window.localStorage.setItem('state', value); }, { immediate: true, deep: true }); function RPCError(type, ...args) { this.name = type; this.message = args; } RPCError.prototype = Object.create(Error.prototype); export const d_log = data => (console.log(data._request.method, ...(data._request.params || []), '=>', data), data); export const d_unwrap = data => { if(data.error) throw new RPCError(data.error.type, ...data.error.args); if(data.ts) try { data.result._ts = data.ts; if(data.cached) data.result._cached = data.cached; } catch(ex) {} return data.result; }; export const f_emit = (fn=console.log, ...args) => data => (fn(...args, data), data); export const f_split = (delimiter='^', ...columns) => columns.length > 0 ? data => data.map(row => columns.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), row.split(delimiter))) : data => data.map(row => row.split(delimiter)); export const f_split1 = (delimiter='^', ...columns) => columns.length > 0 ? data => columns.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), data.split(delimiter)) : data => data.split(delimiter); export const d_split = (data, delimiter='^', ...columns) => columns.length > 0 ? data.map(row => columns.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), row.split(delimiter))) : data.map(row => row.split(delimiter)); export const d_split1 = (data, delimiter='^', ...columns) => columns.length > 0 ? columns.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), data.split(delimiter)) : data.split(delimiter); export const f_slice = (start, end) => data => data.slice(start, end); export const f_key = (key='id') => typeof key === 'function' ? data => data.reduce((acc, val) => (acc[key(val)] = val, acc), data) : data => data.reduce((acc, val) => (acc[val[key]] = val, acc), data); export const d_parse_boolean = data => data != '0'; export const d_parse_text = data => data !== '' ? data.join('\r\n') : data; export const d_parse_array = data => data !== '' ? data : []; export const d_parse_authinfo = data => data ? { duz: data[0] != '0' ? data[0] : null, device_lock: data[1] != '0', change_verify: data[2] != '0', message: data[3], reserved: data[4], greeting_lines: data[5], greeting: data.slice(6), success: (data[0] != '0') && (data[2] == '0') } : { success: false } export const d_parse_imagelist = data => { var descriptor = d_split1(data[0], '^', 'success', 'filter', 'more'), res; if(descriptor.success == '1') { var headers = d_split1(data[1], '^'); res = data.slice(2).map(function(row) { row = row.split('|'); var values = headers.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), row[0].split('^')) values.Info = d_split1(row[1], '^', 'IEN', 'Image Path', 'Abstract Path', 'Short Desc', 'Procedure Time', 'Object Type', 'Procedure', 'Display Date', 'Pointer', 'Abs Type', 'Availability', 'DICOM Series', 'DICOM Image', 'Count', 'Site IEN', 'Site', 'Error', 'BIGPath', 'Patient DFN', 'Patient Name', 'Image Class', 'Cap Dt', 'Document Date', 'Group IEN', 'Group Ch1', 'RPC Server', 'RPC Port', 'Controlled Image', 'Viewable Status', 'Status', 'Image Annotated', 'Image TIU Note Completed', 'Annotation Operation Status', 'Annotation Operation Status Description', 'Package'); values.Info['Group Ch1'] = values.Info['Group Ch1'] ? d_split1(':', 'IEN', 'Type') : null return values; }); res.descriptor = descriptor; } else { res = data.slice(1); res.descriptor = descriptor; } return res; }; export const d_parse_imageinfo = data => { var res = d_split1(data[0], '^', 'Code', 'IEN', 'Image Path', 'Abstract Path', 'Short Desc', 'Procedure Time', 'Object Type', 'Procedure', 'Display Date', 'Pointer', 'Abs Type', 'Availability', 'DICOM Series', 'DICOM Image', 'Count', 'Site IEN', 'Site', 'Error', 'BIGPath', 'Patient DFN', 'Patient Name', 'Image Class', 'Cap Dt', 'Document Date', 'Group IEN', 'Group Ch1', 'RPC Server', 'RPC Port', 'Controlled Image', 'Viewable Status', 'Status', 'Image Annotated', 'Image TIU Note Completed', 'Annotation Operation Status', 'Annotation Operation Status Description', 'Package'); res.Patient = d_split1(data[1], '^', 'IEN', 'name'); return res; }; export const d_parse_imagegroup = data => { var res = d_split(data.slice(1), '^', 'B2', 'IEN', 'Image Path', 'Abstract Path', 'Short Desc', 'Procedure Time', 'Object Type', 'Procedure', 'Display Date', 'Pointer', 'Abs Type', 'Availability', 'DICOM Series', 'DICOM Image', 'Count', 'Site IEN', 'Site', 'Error', 'BIGPath', 'Patient DFN', 'Patient Name', 'Image Class', 'Cap Dt', 'Document Date', 'Group IEN', 'Group Ch1', 'RPC Server', 'RPC Port', 'Controlled Image', 'Viewable Status', 'Status', 'Image Annotated', 'Image TIU Note Completed', 'Annotation Operation Status', 'Annotation Operation Status Description', 'Package'); res.Result = d_split1(data[0], '^', 'code', 'count'); return res; }; export const d_parse_orderdialogs = (data, columns=['IEN', 'windowFormId', 'displayGroupId', 'type', 'displayText']) => data.map(function(row) { row = row.split('^'); row = [...row[0].split(';'), row[1]]; return columns.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), row); }); export const d_parse_ordermenu = data => { var res = d_split1(data[0], '^', 'name', 'columns', 'path_switch'); res.children = d_split(data.slice(1), '^', 'col', 'row', 'type', 'IEN', 'formid', 'autoaccept', 'display_text', 'mnemonic', 'displayonly'); return res; }; export const f_parse_caretseparated_detail = (columns, detailcolumn) => { if(!detailcolumn) detailcolumn = 'detail'; return columns ? data => { var res = [], item = {}; for(var i = 0; i < data.length; ++i) { var row = data[i], prefix = row.charAt(0); if(prefix == '~') res.push(item = columns.reduce((acc, val, idx) => (acc[val] = acc[idx], acc), row.substring(1).split('^'))); else if(prefix == 't') { if(item[detailcolumn]) item[detailcolumn] += '\r\n' + data[i].substring(1); else item[detailcolumn] = data[i].substring(1); } } return res; } : data => { var res = [], item = {}; for(var i = 0; i < data.length; ++i) { var row = data[i], prefix = row.charAt(0); if(prefix == '~') res.push(item = row.substring(1).split('^')); else if(prefix == 't') { if(item[detailcolumn]) item[detailcolumn] += '\r\n' + data[i].substring(1); else item[detailcolumn] = data[i].substring(1); } } return res; } }; export const d_parse_orderoptions_scheduling = data => { var res = orderoptions_parse(data); for(var k in res) if(res.hasOwnProperty(k)) { if(res[k].items) res[k].items = res[k].items.split('^'); res['~' + k.toUpperCase()] = res[k]; } return res; }; export const d_parse_orderoptions_labfacility = data => { var res = orderoptions_parse(data), val, defaultvalue; for(var k in res) if(res.hasOwnProperty(k)) { val = res[k]; if(val.default) { val.default = d_split1(val.default, '^', 'value', 'text'); defaultvalue = val.default.value; } else defaultvalue = null; if(val.items) val.items = val.items.split('\r\n').map(x => x ? (x = d_split1(x, '^', 'value', 'text'), x.default = x.value == defaultvalue, x) : null); res['~' + k.toUpperCase()] = val; } return res; }; export const d_parse_orderoptions_labtest = data => { var res = orderoptions_parse(data), val, defaultvalue; if(res.hasOwnProperty('Test Name')) res['Test Name'].default = res['Test Name'].default.replace(/^\s+|\s+$/, ''); if(res.hasOwnProperty('Item ID')) res['Item ID'].default = d_split1(res['Item ID'].default, '^', 'value', 'text'); if(res.hasOwnProperty('ReqCom')) res['ReqCom'].default = res['ReqCom'].default.replace(/^\s+|\s+$/, ''); if(res.hasOwnProperty('CollSamp')) res['CollSamp'].items = res['CollSamp'].items.split('\r\n').map(x => d_split1(x, '^', 'n', 'SampIEN', 'SampName', 'SpecPtr', 'TubeTop', 'unk_5', 'unk_6', 'LabCollect', 'unk_8', 'SpecName')); res['Derived CollSamp'] = res['Unique CollSamp'] || res['Lab CollSamp'] || res['Default CollSamp']; if(res.hasOwnProperty('Specimens')) res['Specimens'].items = res['Specimens'].items.split('\r\n').map(x => d_split1(x, '^', 'value', 'text')); if(res.hasOwnProperty('Default Urgency')) res['Default Urgency'].default = res['Default Urgency'].default.split('\r\n').map(x => d_split1(x, '^', 'value', 'text', 'x')); if(res.hasOwnProperty('Urgencies')) res['Urgencies'].items = res['Urgencies'].items.split('\r\n').map(x => d_split1(x, '^', 'value', 'text')); return res; }; export const d_parse_orderoptions_medfill = data => { var res = orderoptions_parse(data); if(res.hasOwnProperty('Pickup')) { if(res['Pickup'].default) res['Pickup'].default = d_split1(res['Pickup'].default, '^', 'value', 'text'); if(res['Pickup'].items) res['Pickup'].items = d_split(res['Pickup'].items.split('\r\n'), '^', 'value', 'text'); } if(res.hasOwnProperty('Priority')) { if(res['Priority'].default) res['Priority'].default = d_split1(res['Priority'].default, '^', 'value', 'text'); if(res['Priority'].items) res['Priority'].items = d_split(res['Priority'].items.split('\r\n'), '^', 'value', 'text'); } if(res.hasOwnProperty('Refills')) { if(res['Refills'].default) res['Refills'].default = d_split1(res['Refills'].default, '^', 'value', 'text'); if(res['Refills'].items) res['Refills'].items = d_split(res['Refills'].items.split('\r\n'), '^', 'value', 'text'); } return res; }; export const d_parse_orderoptions_meddose = data => { var res = orderoptions_parse(data); if(res.hasOwnProperty('AllDoses')) res['AllDoses'].items = d_split(res['AllDoses'].items.split('\r\n'), '^', 'text', 'id', 'dosefields'); if(res.hasOwnProperty('Dispense')) res['Dispense'].items = d_split(res['Dispense'].items.split('\r\n'), '^', 'id', 'dose', 'unit', 'text', 'split'); if(res.hasOwnProperty('Dosage')) res['Dosage'].items = d_split(res['Dosage'].items.split('\r\n'), '^', 'medication', '_', '_', 'value', 'text', 'tier', '_', 'form'); if(res.hasOwnProperty('Indication')) res['Indication'].items = res['Indication'].items.split('\r\n'); if((res.hasOwnProperty('Medication')) && (res['Medication'].default)) res['Medication'].default = d_split1(res['Medication'].default, '^', 'value', 'text'); if(res.hasOwnProperty('Route')) { if(res['Route'].default) res['Route'].default = d_split1(res['Route'].default, '^', 'value', 'abbr'); res['Route'].items = d_split(res['Route'].items.split('\r\n'), '^', 'value', 'text', 'abbr', 'sig', '_'); } return res; }; export const d_parse_notifications_fastuser = data => d_split(data, '^', 'info', 'patient', 'location', 'urgency', 'time', 'message', 'unk_6', 'meta', 'unk_7', 'unk_8').map(row => { if(row.meta) { var meta = row.meta.split(';'); var xqaid = row.meta_xqaid = meta[0]; row.meta_duz = meta[1]; row.meta_time = +meta[2]; if(xqaid.startsWith('OR,')) { xqaid = xqaid.split(','); row.meta_source = xqaid[0]; row.meta_dfn = xqaid[1]; row.meta_ien = xqaid[2]; // file 100.9 IEN } else if(xqaid.startsWith('TIU')) { row.meta_source = 'TIU'; row.meta_ien = xqaid.substring(3); // document IEN (DA) } } return row; }); export const d_parse_multireport = data => { if(data.length < 1) return []; var brk, max = 0, grp, _ts = data._ts; for(var i = 0; i < data.length; ++i) { brk = (grp = data[i]).indexOf('^'); if(brk >= 0) { grp = +grp.substring(0, brk); if(grp >= max) max = grp; else break; } else return (data = [data], data._ts = _ts, data); } var res = [], data = data.slice(), max = max + '^', grp = x => x.startsWith(max); while(((brk = data.findIndex(grp)) >= 0) || (brk = data.length)) res.push(data.splice(0, brk + 1)); return (res._ts = _ts, res); }; export const d_parse_tiurecordtiux = data => { var res = {}; if(data.length < 1) return res; var brk = data.indexOf('$TXT'), text = undefined; if(brk >= 0) { text = data.slice(brk + 1).join('\r\n'); data = data.slice(0, brk); } data = d_split(data, '^', 'field', 'value', 'description'); data = data.reduce((acc, val) => (acc['~' + val.field] = val, acc), data); if(text) data.text = text; return data; }; export const d_parse_tiudocumentlist = data => d_split(data, '^', 'IEN', 'title', 'time', 'patient', 'author', 'location', 'status', 'visit').map(row => { row.author = row.author ? d_split1(row.author, ';', 'IEN', 'byline', 'name') : null; row.visit = row.visit ? d_split1(row.visit, ';', 'date', 'time') : null; return row; }); export function memoized(fn) { var cache = {}; return async function(...args) { var key = JSON.stringify(args); return cache.hasOwnProperty(key) ? cache[key] : (cache[key] = await fn(...args)); } } export function Client(cid, secret) { var heartbeat = null; this.secret = secret; this.cid = cid; this.status = reactive({ connected: true, busy: 0 }); this.close = function() { console.log('CLOSE', cid); if(heartbeat) window.clearInterval(heartbeat); this.status.connected = false; return vista.close(cid); }; this.call = async function(body, ...params) { body = (typeof body === 'string') || (body instanceof String) ? { method: body, params, id: Date.now() } : Object.assign({ id: Date.now() }, body); if(params.length > 0) { if(body.params) Array.prototype.push.apply(body.params, params); else body.params = params; } this.status.busy++; try { var res = await vista.call(cid, body); } finally { this.status.busy--; } if((res.error) && (res.error.type == 'ConnectionResetError')) this.close(); res._request = body; return res; }; this.callctx = function(context, method, ...params) { return this.call({ context, method, params, id: Date.now() }); }; this.heartbeat = async function(interval=null) { if(!interval) interval = 0.45*1000*(await this.XWB_GET_BROKER_INFO())[0]; if(heartbeat) window.clearInterval(heartbeat); this.XWB_IM_HERE(); return heartbeat = window.setInterval(this.XWB_IM_HERE, interval); } this.serverinfo = () => vista.serverinfo(cid); this.authinfo = aflow(() => vista.authinfo(cid), d_unwrap, d_parse_authinfo); this.authenticate = aflow((avcode=null) => vista.authenticate(cid, avcode), d_unwrap, d_parse_authinfo); if(!localstate.encfs) localstate.encfs = tplfs_randpassword(); this.tplfs = async () => this._tplfs ? this._tplfs : (this._tplfs = await TplFS.fromUser(this, (await this.authinfo()).duz)); this.encfs = async () => this._encfs ? this._encfs : (this._encfs = await EncFS.fromPassword(await this.tplfs(), localstate.encfs)); this.remotestate = reactive({}); this.setup_remotestate = async () => { var fs = await this.encfs(), file; try { file = await fs.open('state'); Object.assign(this.remotestate, JSON.parse(await file.cat(null))); } catch(ex) { console.error(ex); file = await fs.create('state', JSON.stringify(this.remotestate)); } watch(this.remotestate, debounce(function(value) { file.update(null, JSON.stringify(value)); }, 1000), { deep: true }); if((!this.remotestate.resources) && (localstate.resources)) this.remotestate.resources = localstate.resources; if((!this.remotestate.practitioner) && (localstate.practitioner)) this.remotestate.practitioner = localstate.practitioner; if(localstate.resources) delete localstate.resources; if(localstate.practitioner) delete localstate.practitioner; }; this.XWB_IM_HERE = aflow(() => this.call({ method: 'XWB_IM_HERE', ttl: 30, stale: false }), d_log, d_unwrap); this.XUS_INTRO_MSG = memoized(aflow(() => this.callctx(['XUCOMMAND'], 'XUS_INTRO_MSG'), d_log, d_unwrap)); this.XWB_GET_BROKER_INFO = memoized(aflow(() => this.call({ method: 'XWB_GET_BROKER_INFO', context: ['XUCOMMAND'], ttl: 0, stale: false }), d_log, d_unwrap)); this.XUS_GET_USER_INFO = memoized(aflow(() => this.call({ method: 'XUS_GET_USER_INFO', ttl: 0, stale: false }), d_log, d_unwrap)); this.SDEC_RESOURCE = memoized(aflow(() => this.call({ method: 'SDEC_RESOURCE', context: ['SDECRPC'], ttl: 2592000, stale: true }), d_log, d_unwrap)); this.SDEC_CLINLET = aflow((...args) => this.call({ method: 'SDEC_CLINLET', context: ['SDECRPC'], ttl: 30, stale: false }, ...args), d_log, d_unwrap); this.SDEC_CRSCHED = aflow((...args) => this.call({ method: 'SDEC_CRSCHED', context: ['SDECRPC'], ttl: 30, stale: false }, ...args), d_log, d_unwrap); this.ORWPT_FULLSSN = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT_FULLSSN', ...args), d_log, d_unwrap, f_split('^', 'dfn', 'name', 'date', 'pid'))); this.ORWPT_LAST5 = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT_LAST5', ...args), d_log, d_unwrap, f_split('^', 'dfn', 'name', 'date', 'pid'))); this.ORWPT_ID_INFO = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT_ID_INFO', ...args), d_log, d_unwrap, f_split1('^', 'pid', 'dob', 'sex', 'vet', 'sc_percentage', 'ward', 'room_bed', 'name'))); this.ORWPT_SELCHK = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT_SELCHK', ...args), d_log, d_unwrap, d_parse_boolean)); this.ORWPT16_LOOKUP = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT16_LOOKUP', ...args), d_log, d_unwrap, f_split('^', 'dfn', 'name', 'pid'))); this.ORWPT16_ID_INFO = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT16_ID_INFO', ...args), d_log, d_unwrap, f_split1('^', 'pid', 'dob', 'age', 'sex', 'sc_percentage', 'type', 'ward', 'room_bed', 'name'))); this.ORQQVI_VITALS = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORQQVI_VITALS', ...args), d_log, d_unwrap, f_split('^', 'measurement_ien', 'type', 'value', 'datetime', 'value_american', 'value_metric'))); this.ORQQVI_VITALS_FOR_DATE_RANGE = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORQQVI_VITALS_FOR_DATE_RANGE', ...args), d_log, d_unwrap, f_split('^', 'measurement_ien', 'type', 'value', 'datetime'))); this.GMV_EXTRACT_REC = async (dfn, oredt, orsdt) => pipe(await this.call({ method: 'GMV_EXTRACT_REC', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, `${dfn}^${oredt}^^${orsdt}`), d_log, d_unwrap, measurement_parse); this.ORWLRR_INTERIM = aflow((...args) => this.call({ method: 'ORWLRR_INTERIM', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, lab_parse); this.ORWLRR_INTERIM_RESULTS = async (...args) => lab_reparse_results(await this.ORWLRR_INTERIM(...args)); this.ORWRP_REPORT_TEXT = aflow((...args) => this.call({ method: 'ORWRP_REPORT_TEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_multireport); this.ORWRP_REPORT_TEXT_LONGCACHE = aflow((...args) => this.call({ method: 'ORWRP_REPORT_TEXT', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap, d_parse_array, d_parse_multireport); this.ORWORDG_ALLTREE = memoized(aflow(() => this.callctx(['OR CPRS GUI CHART'], 'ORWORDG_ALLTREE'), d_log, d_unwrap, f_split('^', 'ien', 'name', 'parent', 'has_children'))); this.ORWORDG_REVSTS = memoized(aflow(() => this.callctx(['OR CPRS GUI CHART'], 'ORWORDG_REVSTS'), d_log, d_unwrap, f_split('^', 'ien', 'name', 'parent', 'has_children'))); this.ORWORR_AGET = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWORR_AGET', ...args), d_log, d_unwrap, f_slice(1), f_split('^', 'ifn', 'dgrp', 'time'))); this.ORWORR_GET4LST = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWORR_GET4LST', ...args), d_log, d_unwrap, orderinfo_parse)); this.TIU_TEMPLATE_GETROOTS = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_GETROOTS', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value')); this.TIU_TEMPLATE_GETPROOT = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_GETPROOT', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value')); this.TIU_TEMPLATE_GETBOIL = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_GETBOIL', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_text); this.TIU_TEMPLATE_GETITEMS = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_GETITEMS', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_array, f_split('^', 'IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value')); this.TIU_TEMPLATE_SET_ITEMS = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_SET_ITEMS', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_TEMPLATE_CREATE_MODIFY = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_CREATE/MODIFY', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_TEMPLATE_DELETE = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_DELETE', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_TEMPLATE_LOCK = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_LOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_TEMPLATE_UNLOCK = aflow((...args) => this.call({ method: 'TIU_TEMPLATE_UNLOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_DOCUMENTS_BY_CONTEXT = aflow((...args) => this.call({ method: 'TIU_DOCUMENTS_BY_CONTEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_tiudocumentlist); this.TIU_DOCUMENTS_BY_CONTEXT_FLUSH = aflow((...args) => this.call({ method: 'TIU_DOCUMENTS_BY_CONTEXT', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_tiudocumentlist); this.TIU_GET_RECORD_TEXT = aflow((...args) => this.call({ method: 'TIU_GET_RECORD_TEXT', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_text); this.TIU_GET_RECORD_TEXT_FLUSH = aflow((...args) => this.call({ method: 'TIU_GET_RECORD_TEXT', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_text); this.TIU_LONG_LIST_OF_TITLES = memoized(aflow((...args) => this.call({ method: 'TIU_LONG_LIST_OF_TITLES', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true, ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'IEN', 'name'))); this.TIU_CREATE_RECORD = aflow((...args) => this.call({ method: 'TIU_CREATE_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_AUTHORIZATION = aflow((...args) => this.call({ method: 'TIU_AUTHORIZATION', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_LOAD_RECORD_FOR_EDIT = aflow((...args) => this.call({ method: 'TIU_LOAD_RECORD_FOR_EDIT', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, d_parse_tiurecordtiux); this.TIU_UPDATE_RECORD = aflow((...args) => this.call({ method: 'TIU_UPDATE_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_DELETE_RECORD = aflow((...args) => this.call({ method: 'TIU_DELETE_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.TIU_SIGN_RECORD = aflow((...args) => this.call({ method: 'TIU_SIGN_RECORD', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.ORQQCN_LIST = aflow((...args) => this.call({ method: 'ORQQCN_LIST', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, f_split('^', 'IEN', 'time', 'status', 'orderable', 'type', 'has_children', 'text', 'order_ifn', 'type_abbr')); this.ORQQCN_DETAIL = aflow((...args) => this.call({ method: 'ORQQCN_DETAIL', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_text); this.ORWPCE_NOTEVSTR = aflow((...args) => this.call({ method: 'ORWPCE_NOTEVSTR', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap); this.ORWPCE_DELETE = aflow((...args) => this.call({ method: 'ORWPCE_DELETE', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.MAG4_IMAGE_LIST = memoized(aflow((...args) => this.call({ method: 'MAG4_IMAGE_LIST', context: ['MAG WINDOWS'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_imagelist)); this.MAG4_GET_IMAGE_INFO = memoized(aflow((...args) => this.call({ method: 'MAG4_GET_IMAGE_INFO', context: ['MAG WINDOWS'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_text)); this.MAGG_IMAGE_INFO = memoized(aflow((...args) => this.call({ method: 'MAGG_IMAGE_INFO', context: ['MAG WINDOWS'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_imageinfo)); this.MAGG_GROUP_IMAGES = memoized(aflow((...args) => this.call({ method: 'MAGG_GROUP_IMAGES', context: ['MAG WINDOWS'], ttl: 60, stale: false }, ...args), d_log, d_unwrap, d_parse_array, d_parse_imagegroup)); this.ORWCV_VST = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWCV_VST', ...args), d_log, d_unwrap, d_parse_array, f_split('^', 'apptinfo', 'datetime', 'location', 'status'))); this.ORWU_NEWPERS = memoized(aflow((...args) => this.call({ method: 'ORWU_NEWPERS', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'DUZ', 'name', 'description'))); this.ORWU_VALIDSIG = memoized(aflow((...args) => this.call({ method: 'ORWU_VALIDSIG', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap)); this.ORWU1_NEWLOC = memoized(aflow((...args) => this.call({ method: 'ORWU1_NEWLOC', context: ['OR CPRS GUI CHART'], ttl: 86400, stale: true }, ...args), d_log, d_unwrap, f_split('^', 'IEN', 'name'))); this.ORWDX_DGNM = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DGNM', ...args), d_log, d_unwrap)); this.ORWDX_DGRP = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DGRP', ...args), d_log, d_unwrap)); this.ORWDX_WRLST = memoized(aflow(() => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_WRLST'), d_log, d_unwrap, d_parse_orderdialogs)); this.ORWDX_ORDITM = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_ORDITM', ...args), d_log, d_unwrap, f_split('^', 'IEN', 'synonym', 'name'))); this.ORWDX_DLGID = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DLGID', ...args), d_log, d_unwrap)); this.ORWDX_DLGDEF = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DLGDEF', ...args), d_log, d_unwrap, f_split('^', 'promptID', 'promptIEN', 'fmtSeq', 'fmtCode', 'omit', 'lead', 'trail', 'newLine', 'wrap', 'children', 'isChild'), f_key('promptID'))); this.ORWDX_LOADRSP = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_LOADRSP', ...args), d_log, d_unwrap, orderoverrides_parse, f_key('promptID'))); this.ORWDX_SAVE = aflow((...args) => this.call({ method: 'ORWDX_SAVE', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap); this.ORWDXM_MENU = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM_MENU', ...args), d_log, d_unwrap, d_parse_ordermenu)); this.ORWDXM_DLGNAME = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM_DLGNAME', ...args), d_log, d_unwrap, f_split1('^', 'InternalName', 'DisplayName', 'BaseDialogIEN', 'BaseDialogName'))); this.ORWDXM_PROMPTS = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM_PROMPTS', ...args), d_log, d_unwrap, f_parse_caretseparated_detail(['id', 'req', 'hid', 'prompt', 'type', 'domain', 'default', 'idflt', 'help']), f_key('id'))); this.ORWDXM1_BLDQRSP = aflow((...args) => this.call({ method: 'ORWDXM1_BLDQRSP', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), d_log, d_unwrap, f_split('^', 'QuickLevel', 'ResponseID', 'Dialog', 'Type', 'FormID', 'DGrpLST')); this.ORWUL_FV4DG = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWUL_FV4DG', ...args), d_log, d_unwrap, f_split1('^', 'IEN', 'count'))); this.ORWUL_FVSUB = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWUL_FVSUB', ...args), d_log, d_unwrap, f_split('^', 'IEN', 'description'))); this.ORWUL_FVIDX = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWUL_FVIDX', ...args), d_log, d_unwrap, f_split1('^', 'index', 'description'))); this.ORWDSD1_ODSLCT = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDSD1_ODSLCT', ...args), d_log, d_unwrap, d_parse_orderoptions_scheduling)); this.ORWDLR32_DEF = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDLR32_DEF', ...args), d_log, d_unwrap, d_parse_orderoptions_labfacility)); this.ORWDLR32_LOAD = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDLR32_LOAD', ...args), d_log, d_unwrap, d_parse_orderoptions_labtest)); this.ORWDPS1_SCHALL = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDPS1_SCHALL', ...args), d_log, d_unwrap, f_split('^', 'value', 'text', '_', 'times'), f_key('value'))); this.ORWDPS1_ODSLCT = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDPS1_ODSLCT', ...args), d_log, d_unwrap, d_parse_orderoptions_medfill)); this.ORWDPS2_OISLCT = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDPS2_OISLCT', ...args), d_log, d_unwrap, d_parse_orderoptions_meddose)); this.ORWDPS2_DAY2QTY = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDPS2_DAY2QTY', ...args), d_log, d_unwrap)); this.ORWDPS2_QTY2DAY = memoized(aflow((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDPS2_QTY2DAY', ...args), d_log, d_unwrap)); this.ORWORB_FASTUSER = aflow(() => this.call({ method: 'ORWORB_FASTUSER', context: ['OR CPRS GUI CHART'], ttl: 60, stale: false }), d_log, d_unwrap, d_parse_notifications_fastuser); return this; } Client._registry = {}; Client.fromID = function(cid, secret) { if(Client._registry[cid]) return Client._registry[cid]; return Client._registry[cid] = new Client(cid, secret); }; Client.fromScratch = async function(secret, host='vista.northport.med.va.gov', port=19209) { var data = await vista.connect(secret, host, port); if(data.result) return Client.fromID(data.result, secret); }; Client.fromCookie = async function(secret, defaulthost='vista.northport.med.va.gov:19209') { if(!secret) secret = localstate.secret; if(secret) { var host = localstate.host; host = (host || defaulthost).split(':'); if(secret != localstate.secret) { console.log('Using new secret', secret); var client = await Client.fromScratch(secret, host[0], host[1]); if(client) { localstate.host = host.join(':'); localstate.secret = secret; localstate.cid = client.cid; console.log('Established connection', client.cid); return client; } else { delete localstate.secret; delete localstate.cid; console.log('Failed to connect'); return null; } } else if(!localstate.cid) { console.log('Using saved secret', secret); var client = await Client.fromScratch(secret, host[0], host[1]); if(client) { localstate.host = host.join(':'); localstate.secret = secret; localstate.cid = client.cid; console.log('Established connection', client.cid); return client; } else { delete localstate.secret; delete localstate.cid; console.log('Failed connection'); return null; } } else { console.log('Using saved secret and connection', secret); var cid = localstate.cid; var client = Client.fromID(cid, secret); if((await vista.call(cid, { method: 'XWB_IM_HERE', ttl: 0, stale: false, id: Date.now() })).result == '1') { var server = await client.serverinfo(); if((host[0] == server.result.host) && (host[1] == server.result.port)) { localstate.host = host.join(':'); return client; } else console.log('Rejecting previous connection to different server', server); } delete localstate.cid; return await Client.fromCookie(secret, host.join(':')); } } }; export default window.vistax = { localstate, RPCError, Client, connect: Client.fromCookie };