346 lines
13 KiB
PHP
346 lines
13 KiB
PHP
<style>
|
|
.meta-dashboard-demo .filter-bar {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 12px 20px;
|
|
align-items: flex-end;
|
|
background: #eef5fa;
|
|
border-radius: 10px;
|
|
padding: 10px 14px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.meta-dashboard-demo .filter-field {
|
|
flex: 1 1 140px;
|
|
min-width: 120px;
|
|
max-width: 220px;
|
|
}
|
|
.meta-dashboard-demo .filter-field label {
|
|
display: block;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
margin-bottom: 4px;
|
|
color: #111;
|
|
}
|
|
.meta-dashboard-demo .filter-field .select2-container {
|
|
width: 100% !important;
|
|
}
|
|
.meta-dashboard-demo .filter-field .select2-selection--single {
|
|
height: 32px !important;
|
|
min-height: 32px;
|
|
border: 1px solid #d8e2ea !important;
|
|
border-radius: 8px !important;
|
|
font-size: 12px;
|
|
}
|
|
.meta-dashboard-demo .filter-field .select2-selection__rendered {
|
|
line-height: 30px !important;
|
|
padding-left: 10px !important;
|
|
color: #333;
|
|
}
|
|
.meta-dashboard-demo .filter-field .select2-selection__arrow {
|
|
height: 30px !important;
|
|
}
|
|
.meta-dashboard-demo .filter-field .select2-container--disabled .select2-selection--single {
|
|
background-color: #f5f7f9 !important;
|
|
cursor: not-allowed;
|
|
opacity: 0.85;
|
|
}
|
|
.meta-dashboard-demo .dashboard-status {
|
|
font-size: 12px;
|
|
color: #5c6b7a;
|
|
padding: 4px 0 10px;
|
|
min-height: 20px;
|
|
}
|
|
.meta-dashboard-demo .dashboard-status.is-error { color: #c0392b; }
|
|
.meta-dashboard-demo .dashboard-status.is-loading { color: #0a8794; }
|
|
.meta-dashboard-demo #dashboard-container {
|
|
min-height: 480px;
|
|
}
|
|
.meta-dashboard-demo #dashboard-container metabase-dashboard {
|
|
display: block;
|
|
width: 100%;
|
|
min-height: 480px;
|
|
}
|
|
.meta-dashboard-demo .dashboard-placeholder {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 200px;
|
|
color: #7a8a99;
|
|
font-size: 13px;
|
|
background: #fff;
|
|
border: 1px dashed #d0dce6;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.emotion-65tole {
|
|
display: none !important;
|
|
}
|
|
</style>
|
|
|
|
<div class="row meta-dashboard-demo">
|
|
<div class="col-xl-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<!-- <h4 class="mb-3"><?= esc($page_name ?? 'Metabase Dashboard') ?></h4> -->
|
|
|
|
<div class="filter-bar">
|
|
<div class="filter-field">
|
|
<label for="filter-client">Client</label>
|
|
<select id="filter-client" class="form-control form-control-sm meta-filter-select2">
|
|
<option value="">Select</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-field">
|
|
<label for="filter-branch">Branch</label>
|
|
<select id="filter-branch" class="form-control form-control-sm meta-filter-select2" disabled>
|
|
<option value="">Select</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-field">
|
|
<label for="filter-policy">Policy</label>
|
|
<select id="filter-policy" class="form-control form-control-sm meta-filter-select2" disabled>
|
|
<option value="">Select</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="dashboard-status" class="dashboard-status"></div>
|
|
|
|
<div id="dashboard-container">
|
|
<div class="dashboard-placeholder" id="dashboard-placeholder">
|
|
Select client, branch, and policy to load the dashboard.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function defineMetabaseConfig(config) {
|
|
window.metabaseConfig = config;
|
|
}
|
|
|
|
defineMetabaseConfig({
|
|
theme: { preset: "light" },
|
|
isGuest: true,
|
|
instanceUrl: "<?= esc($metabaseUrl ?? '') ?>"
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
$(function () {
|
|
const CLIENTS_API = <?= json_encode(base_url('/util/getClientAndBranchAndPolicy')) ?>;
|
|
const DASHBOARD_API = <?= json_encode($dashboardApiUrl ?? base_url('/metaTpaDashboardDemo')) ?>;
|
|
const METABASE_URL = <?= json_encode($metabaseUrl ?? '') ?>;
|
|
|
|
const select2Options = {
|
|
placeholder: 'Select',
|
|
allowClear: true,
|
|
width: '100%',
|
|
minimumResultsForSearch: 0,
|
|
dropdownParent: $(document.body)
|
|
};
|
|
|
|
let branchByClient = {};
|
|
let policyByClient = {};
|
|
let embedScriptPromise = null;
|
|
|
|
const $elClient = $('#filter-client');
|
|
const $elBranch = $('#filter-branch');
|
|
const $elPolicy = $('#filter-policy');
|
|
const elStatus = document.getElementById('dashboard-status');
|
|
const elContainer = document.getElementById('dashboard-container');
|
|
const elPlaceholder = document.getElementById('dashboard-placeholder');
|
|
|
|
function setStatus(message, type) {
|
|
elStatus.textContent = message || '';
|
|
elStatus.className = 'dashboard-status' + (type ? ' is-' + type : '');
|
|
}
|
|
|
|
function initSelect2($select, disabled) {
|
|
if ($select.hasClass('select2-hidden-accessible')) {
|
|
$select.select2('destroy');
|
|
}
|
|
$select.prop('disabled', false);
|
|
$select.select2(select2Options);
|
|
if (disabled) {
|
|
$select.prop('disabled', true);
|
|
}
|
|
}
|
|
|
|
function rebuildSelect($select, placeholder, disabled, items, getValue, getLabel) {
|
|
if ($select.hasClass('select2-hidden-accessible')) {
|
|
$select.select2('destroy');
|
|
}
|
|
$select.empty().append($('<option>', { value: '', text: placeholder }));
|
|
(items || []).forEach(function (item) {
|
|
$select.append($('<option>', {
|
|
value: String(getValue(item)),
|
|
text: getLabel(item)
|
|
}));
|
|
});
|
|
$select.val('');
|
|
initSelect2($select, disabled);
|
|
}
|
|
|
|
function filtersComplete() {
|
|
return !!($elClient.val() && $elBranch.val() && $elPolicy.val());
|
|
}
|
|
|
|
function loadMetabaseEmbedScript() {
|
|
if (window.customElements && window.customElements.get('metabase-dashboard')) {
|
|
return Promise.resolve();
|
|
}
|
|
if (embedScriptPromise) {
|
|
return embedScriptPromise;
|
|
}
|
|
embedScriptPromise = new Promise(function (resolve, reject) {
|
|
const existing = document.querySelector('script[data-metabase-embed]');
|
|
if (existing) {
|
|
existing.addEventListener('load', function () { resolve(); }, { once: true });
|
|
existing.addEventListener('error', reject, { once: true });
|
|
return;
|
|
}
|
|
const script = document.createElement('script');
|
|
script.src = METABASE_URL + '/app/embed.js';
|
|
script.defer = true;
|
|
script.dataset.metabaseEmbed = '1';
|
|
script.onload = function () { resolve(); };
|
|
script.onerror = reject;
|
|
document.head.appendChild(script);
|
|
});
|
|
return embedScriptPromise;
|
|
}
|
|
|
|
function clearDashboard() {
|
|
const existing = elContainer.querySelector('metabase-dashboard');
|
|
if (existing) {
|
|
existing.remove();
|
|
}
|
|
if (elPlaceholder) {
|
|
elPlaceholder.style.display = '';
|
|
}
|
|
}
|
|
|
|
async function renderDashboard(token) {
|
|
clearDashboard();
|
|
if (!token) {
|
|
return;
|
|
}
|
|
await loadMetabaseEmbedScript();
|
|
if (elPlaceholder) {
|
|
elPlaceholder.style.display = 'none';
|
|
}
|
|
const dash = document.createElement('metabase-dashboard');
|
|
dash.setAttribute('token', token);
|
|
dash.setAttribute('with-title', 'true');
|
|
dash.setAttribute('with-downloads', 'true');
|
|
elContainer.appendChild(dash);
|
|
}
|
|
|
|
async function loadFilterData() {
|
|
setStatus('Loading clients…', 'loading');
|
|
try {
|
|
const res = await fetch(CLIENTS_API, { credentials: 'same-origin' });
|
|
const json = await res.json();
|
|
if (!json.status) {
|
|
setStatus('Could not load client list.', 'error');
|
|
return;
|
|
}
|
|
branchByClient = json.branch_data || {};
|
|
policyByClient = json.policyListByClient || {};
|
|
|
|
rebuildSelect($elClient, 'Select', false, json.client_data || [], function (c) { return c.id; }, function (c) {
|
|
return c.client_name || c.client_short_name || ('Client ' + c.id);
|
|
});
|
|
rebuildSelect($elBranch, 'Select', true);
|
|
rebuildSelect($elPolicy, 'Select', true);
|
|
setStatus('');
|
|
} catch (e) {
|
|
setStatus('Failed to load filter options.', 'error');
|
|
}
|
|
}
|
|
|
|
async function fetchDashboard(policyId) {
|
|
if (!filtersComplete()) {
|
|
clearDashboard();
|
|
setStatus('Select client, branch, and policy to load the dashboard.');
|
|
return;
|
|
}
|
|
if (!policyId) {
|
|
clearDashboard();
|
|
setStatus('Select client, branch, and policy to load the dashboard.');
|
|
return;
|
|
}
|
|
setStatus('Loading dashboard…', 'loading');
|
|
try {
|
|
const url = DASHBOARD_API + '?api=1&client_policy=' + encodeURIComponent(policyId);
|
|
const res = await fetch(url, { credentials: 'same-origin' });
|
|
const json = await res.json();
|
|
if (json.status !== 'success' || !json.data || !json.data.metabaseToken) {
|
|
clearDashboard();
|
|
setStatus(json.message || 'No dashboard available for this policy.', 'error');
|
|
return;
|
|
}
|
|
renderDashboard(json.data.metabaseToken);
|
|
setStatus('');
|
|
} catch (e) {
|
|
clearDashboard();
|
|
setStatus('Failed to load dashboard.', 'error');
|
|
}
|
|
}
|
|
|
|
$elClient.on('change', function () {
|
|
const clientId = $(this).val();
|
|
rebuildSelect($elBranch, 'Select', !clientId);
|
|
rebuildSelect($elPolicy, 'Select', true);
|
|
clearDashboard();
|
|
setStatus(clientId ? '' : 'Select client, branch, and policy to load the dashboard.');
|
|
|
|
if (!clientId) {
|
|
return;
|
|
}
|
|
const branches = branchByClient[clientId] || [];
|
|
rebuildSelect($elBranch, 'Select', branches.length === 0, branches, function (b) { return b.id; }, function (b) {
|
|
return b.branch_name || ('Branch ' + b.id);
|
|
});
|
|
});
|
|
|
|
$elBranch.on('change', function () {
|
|
const branchId = $(this).val();
|
|
const clientId = $elClient.val();
|
|
rebuildSelect($elPolicy, 'Select', !branchId);
|
|
clearDashboard();
|
|
setStatus(branchId ? '' : 'Select branch and policy to load the dashboard.');
|
|
|
|
if (!branchId || !clientId) {
|
|
return;
|
|
}
|
|
|
|
const policiesForClient = policyByClient[clientId] || [];
|
|
const policies = policiesForClient.filter(function (p) {
|
|
return String(p.client_branch_id) === String(branchId);
|
|
});
|
|
|
|
rebuildSelect($elPolicy, 'Select', policies.length === 0, policies, function (p) { return p.id; }, function (p) {
|
|
const type = p.policy_type || '';
|
|
const no = p.policy_no || '';
|
|
return (type && no) ? (type + ' - ' + no) : (no || type || ('Policy ' + p.id));
|
|
});
|
|
if (policies.length === 0) {
|
|
setStatus('No policies found for this branch.', 'error');
|
|
}
|
|
});
|
|
|
|
$elPolicy.on('change', function () {
|
|
fetchDashboard($(this).val());
|
|
});
|
|
|
|
initSelect2($elClient, false);
|
|
initSelect2($elBranch, true);
|
|
initSelect2($elPolicy, true);
|
|
loadFilterData();
|
|
});
|
|
</script>
|