Files
kane-diagnostics/hubzilla/addon/assoc_profile/assoc_profile_manage.php
2026-06-06 08:12:49 -04:00

199 lines
11 KiB
PHP

<?php
/**
* Association Profile — Management Renderer
* Render functions for /assoc_profile/manage interface.
* Operator-only. Called from assoc_profile.php content router.
*/
function assoc_render_manage_index() {
$registry = assoc_load_registry();
$out = '<div class="assoc-manage">';
$out .= '<h2>Association Profile — Management</h2>';
$out .= '<div class="mb-3">';
$out .= '<a href="' . z_root() . '/assoc_profile/manage/assoc" class="btn btn-primary btn-sm me-2">Add Association</a>';
$out .= '<a href="' . z_root() . '/assoc_profile/manage/fields" class="btn btn-outline-secondary btn-sm">Manage Fields</a>';
$out .= '</div>';
if (empty($registry)) {
$out .= '<p class="text-muted">No associations registered.</p>';
} else {
$out .= '<table class="table table-sm table-hover">';
$out .= '<thead><tr><th>Slug</th><th>Legal Name</th><th>Type</th><th>Units</th><th>Updated</th><th></th></tr></thead><tbody>';
foreach ($registry as $slug => $entry) {
$out .= '<tr>';
$out .= '<td><code>' . assoc_h($slug) . '</code></td>';
$out .= '<td>' . assoc_h($entry['assoc_legal_name'] ?? '—') . '</td>';
$out .= '<td>' . assoc_h($entry['assoc_type'] ?? '—') . '</td>';
$out .= '<td>' . assoc_h($entry['assoc_units'] ?? '—') . '</td>';
$out .= '<td>' . assoc_h($entry['assoc_updated'] ?? '—') . '</td>';
$out .= '<td><a href="' . z_root() . '/assoc_profile/manage/assoc/' . assoc_h($slug) . '" class="btn btn-sm btn-outline-primary">Edit</a></td>';
$out .= '</tr>';
}
$out .= '</tbody></table>';
}
$out .= '</div>';
return $out;
}
function assoc_render_add_association_form() {
$out = '<div class="assoc-manage">';
$out .= '<h2>Add Association</h2>';
$out .= '<form method="post" action="' . z_root() . '/assoc_profile/manage">';
$out .= assoc_csrf_token();
$out .= '<input type="hidden" name="assoc_action" value="add_association">';
$out .= '<div class="mb-3">';
$out .= '<label class="form-label">Slug <small class="text-muted">(lowercase, hyphens only — cannot be changed after creation)</small></label>';
$out .= '<input type="text" class="form-control" name="new_slug" placeholder="e.g. arbors-bgca" required pattern="[a-z0-9\-]+">';
$out .= '</div>';
$out .= '<button type="submit" class="btn btn-primary">Create Association</button> ';
$out .= '<a href="' . z_root() . '/assoc_profile/manage" class="btn btn-outline-secondary">Cancel</a>';
$out .= '</form></div>';
return $out;
}
function assoc_render_edit_association_form($slug) {
$registry = assoc_load_registry();
if (!isset($registry[$slug])) {
return '<div class="alert alert-warning">Association not found: ' . assoc_h($slug) . '</div>';
}
$entry = $registry[$slug];
$def = assoc_load_fields();
$groups = $def['groups'] ?? [];
$fields = $def['fields'] ?? [];
$by_group = [];
foreach ($fields as $f) {
$by_group[$f['group']][] = $f;
}
$out = '<div class="assoc-manage">';
$out .= '<h2>' . assoc_h($entry['assoc_legal_name'] ?? $slug) . '</h2>';
$out .= '<p class="text-muted"><code>' . assoc_h($slug) . '</code></p>';
$out .= '<form method="post" action="' . z_root() . '/assoc_profile/manage">';
$out .= assoc_csrf_token();
$out .= '<input type="hidden" name="assoc_action" value="save_association">';
$out .= '<input type="hidden" name="assoc_slug" value="' . assoc_h($slug) . '">';
foreach ($groups as $group) {
$group_fields = $by_group[$group] ?? [];
if (empty($group_fields)) continue;
$out .= '<h5 class="assoc-group-label mt-4">' . assoc_h($group) . '</h5>';
foreach ($group_fields as $f) {
$nick = $f['nickname'];
$val = $entry[$nick] ?? ($f['default'] ?? '');
$type = $f['type'] ?? 'text';
$label = $f['label'] ?? $nick;
$help = $f['help'] ?? '';
if ($type === 'readonly') {
$out .= '<div class="mb-2">';
$out .= '<label class="form-label text-muted">' . assoc_h($label) . '</label>';
$out .= '<div class="form-control-plaintext ps-0">' . assoc_h($val ?: '—') . '</div>';
$out .= '</div>';
continue;
}
$out .= '<div class="mb-2">';
$out .= '<label class="form-label" for="' . assoc_h($nick) . '">' . assoc_h($label) . '</label>';
if ($help) $out .= '<small class="text-muted d-block mb-1">' . assoc_h($help) . '</small>';
if ($type === 'select' && !empty($f['options'])) {
$out .= '<select class="form-select form-select-sm" id="' . assoc_h($nick) . '" name="' . assoc_h($nick) . '">';
foreach ($f['options'] as $opt) {
$sel = ($val === $opt) ? 'selected' : '';
$disp = ($opt === 'UNK') ? 'Unknown — not yet verified' : $opt;
$out .= '<option value="' . assoc_h($opt) . '" ' . $sel . '>' . assoc_h($disp) . '</option>';
}
$out .= '</select>';
} else {
$out .= '<input type="text" class="form-control form-control-sm"
id="' . assoc_h($nick) . '" name="' . assoc_h($nick) . '"
value="' . assoc_h($val) . '">';
}
$out .= '</div>';
}
}
$out .= '<div class="mt-4">';
$out .= '<button type="submit" class="btn btn-primary">Save</button> ';
$out .= '<a href="' . z_root() . '/assoc_profile/manage" class="btn btn-outline-secondary">Back</a>';
$out .= '</div></form></div>';
return $out;
}
function assoc_render_fields_form() {
$def = assoc_load_fields();
$groups = $def['groups'] ?? [];
$fields = $def['fields'] ?? [];
$out = '<div class="assoc-manage">';
$out .= '<h2>Manage Fields</h2>';
$out .= '<p class="text-muted small">Changes to labels and groups take effect immediately. Adding a field backfills all existing associations with the default value. Removing a field deletes its data from all associations — this cannot be undone.</p>';
$out .= '<form method="post" action="' . z_root() . '/assoc_profile/manage">';
$out .= assoc_csrf_token();
$out .= '<input type="hidden" name="assoc_action" value="save_fields">';
$out .= '<table class="table table-sm">';
$out .= '<thead><tr><th>Nickname</th><th>Label</th><th>Type</th><th>Group</th><th>Help</th><th></th></tr></thead><tbody>';
foreach ($fields as $f) {
$nick = $f['nickname'];
$out .= '<tr>';
$out .= '<td><code>' . assoc_h($nick) . '</code></td>';
$out .= '<td><input type="text" class="form-control form-control-sm" name="label_' . assoc_h($nick) . '" value="' . assoc_h($f['label'] ?? '') . '"></td>';
$out .= '<td>' . assoc_h($f['type'] ?? 'text') . '</td>';
$out .= '<td><input type="text" class="form-control form-control-sm" name="group_' . assoc_h($nick) . '" value="' . assoc_h($f['group'] ?? '') . '"></td>';
$out .= '<td><input type="text" class="form-control form-control-sm" name="help_' . assoc_h($nick) . '" value="' . assoc_h($f['help'] ?? '') . '"></td>';
$out .= '<td>';
if (($f['type'] ?? '') !== 'readonly') {
$out .= '<button type="submit" form="rm-' . assoc_h($nick) . '" class="btn btn-danger btn-sm"
onclick="return confirm(\'Remove field ' . assoc_h($nick) . ' from ALL associations? Cannot be undone.\')">Remove</button>';
}
$out .= '</td></tr>';
}
$out .= '</tbody></table>';
$out .= '<button type="submit" class="btn btn-primary btn-sm">Save Label/Group Changes</button>';
$out .= '</form>';
foreach ($fields as $f) {
if (($f['type'] ?? '') === 'readonly') continue;
$nick = $f['nickname'];
$out .= '<form id="rm-' . assoc_h($nick) . '" method="post" action="' . z_root() . '/assoc_profile/manage">';
$out .= assoc_csrf_token();
$out .= '<input type="hidden" name="assoc_action" value="remove_field">';
$out .= '<input type="hidden" name="remove_nickname" value="' . assoc_h($nick) . '">';
$out .= '</form>';
}
$out .= '<hr class="mt-4"><h5>Add New Field</h5>';
$out .= '<form method="post" action="' . z_root() . '/assoc_profile/manage">';
$out .= assoc_csrf_token();
$out .= '<input type="hidden" name="assoc_action" value="add_field">';
$out .= '<div class="row g-2">';
$out .= '<div class="col-md-2"><label class="form-label">Nickname</label><input type="text" class="form-control form-control-sm" name="new_nickname" placeholder="assoc_fieldname"></div>';
$out .= '<div class="col-md-2"><label class="form-label">Label</label><input type="text" class="form-control form-control-sm" name="new_label"></div>';
$out .= '<div class="col-md-1"><label class="form-label">Type</label>
<select class="form-select form-select-sm" name="new_type">
<option value="text">text</option>
<option value="select">select</option>
</select></div>';
$out .= '<div class="col-md-2"><label class="form-label">Group</label><input type="text" class="form-control form-control-sm" name="new_group"></div>';
$out .= '<div class="col-md-1"><label class="form-label">Default</label><input type="text" class="form-control form-control-sm" name="new_default" placeholder="UNK"></div>';
$out .= '<div class="col-md-2"><label class="form-label">Options <small>(select only, one per line)</small></label><textarea class="form-control form-control-sm" name="new_options" rows="3"></textarea></div>';
$out .= '<div class="col-md-2"><label class="form-label">Help text</label><input type="text" class="form-control form-control-sm" name="new_help"></div>';
$out .= '</div>';
$out .= '<div class="mt-2"><button type="submit" class="btn btn-success btn-sm">Add Field</button></div>';
$out .= '</form>';
$out .= '<hr class="mt-4"><h5>Group Order</h5>';
$out .= '<form method="post" action="' . z_root() . '/assoc_profile/manage">';
$out .= assoc_csrf_token();
$out .= '<input type="hidden" name="assoc_action" value="save_fields">';
$out .= '<div class="mb-2"><label class="form-label">Groups <small class="text-muted">(one per line)</small></label>';
$out .= '<textarea class="form-control form-control-sm" name="groups" rows="' . count($groups) . '">' . assoc_h(implode("\n", $groups)) . '</textarea></div>';
$out .= '<button type="submit" class="btn btn-primary btn-sm">Save Group Order</button>';
$out .= '</form>';
$out .= '<div class="mt-3"><a href="' . z_root() . '/assoc_profile/manage" class="btn btn-outline-secondary btn-sm">Back</a></div>';
$out .= '</div>';
return $out;
}