x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<div class="w-full max-w-4xl"> <div id="lui-loopos_ui/extra_data_viewer-d32ce8121616f1f1" class="lui-extra_data_viewer" data-controller="extra-data-viewer" data-action="change->extra-data-viewer#toggleView" data-extra-data-viewer-default-view-value="human" data-extra-data-viewer-persist-field-value="extra_data_viewer_default_view"> <div class="lui-extra_data_viewer__toggle"> <div class="flex items-center gap-2 flex-row" data-controller="toggle" data-view-toggle="json" data-extra-data-viewer-target="jsonToggle"> <label class="lui-toggle relative"> <input name="" type="checkbox" value="false" data-toggle-target="input" data-action=" " data-method="patch" data-turbo_frame="" > <span class="lui-slider" style=""> <span class="lui-toggle__spinner" data-toggle-target="spinner"> <i class="absolute origin-center animate-spin text-[9px] top-px left-px fa-solid fa-spinner"></i> </span> </span> </label> <p class="text-general-global-black text-primary-xs-regular"> JSON View </p> </div> </div> <div data-extra-data-viewer-target="humanPanel" class="lui-extra_data_viewer__panel lui-extra_data_viewer__panel--human "> <div class="lui-human_view" data-controller="human-view" data-human-view-icon-behavior-value="rotate"> <div class="lui-human_view__content"> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__leaf"> <i class="fa-solid fa-chevron-right lui-human_view-tree_node__icon lui-human_view-tree_node__icon--placeholder"></i> <span class="lui-human_view-tree_node__key">origin:</span> <span class="lui-human_view-tree_node__value lui-human_view-tree_node__value--string">core</span> </div> </div> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__leaf"> <i class="fa-solid fa-chevron-right lui-human_view-tree_node__icon lui-human_view-tree_node__icon--placeholder"></i> <span class="lui-human_view-tree_node__key">retry_count:</span> <span class="lui-human_view-tree_node__value lui-human_view-tree_node__value--number">2</span> </div> </div> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__branch"> <button type="button" class="lui-human_view-tree_node__trigger" data-action="click->human-view#toggleTree" aria-expanded="false" aria-controls="extra-data-tree-318d0bb301be"> <i data-tree-icon data-tree-icon-closed="fa-chevron-right" data-tree-icon-open="fa-chevron-down" class="fa-solid fa-chevron-right lui-human_view-tree_node__icon"></i> <span class="lui-human_view-tree_node__key">metadata</span> </button> <div id="extra-data-tree-318d0bb301be" data-tree-content data-state="closed" class="lui-human_view-tree_node__children" hidden> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__leaf"> <i class="fa-solid fa-chevron-right lui-human_view-tree_node__icon lui-human_view-tree_node__icon--placeholder"></i> <span class="lui-human_view-tree_node__key">source:</span> <span class="lui-human_view-tree_node__value lui-human_view-tree_node__value--string">manual</span> </div> </div> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__branch"> <button type="button" class="lui-human_view-tree_node__trigger" data-action="click->human-view#toggleTree" aria-expanded="false" aria-controls="extra-data-tree-1becb5e12da2"> <i data-tree-icon data-tree-icon-closed="fa-chevron-right" data-tree-icon-open="fa-chevron-down" class="fa-solid fa-chevron-right lui-human_view-tree_node__icon"></i> <span class="lui-human_view-tree_node__key">tags</span> </button> <div id="extra-data-tree-1becb5e12da2" data-tree-content data-state="closed" class="lui-human_view-tree_node__children" hidden> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__leaf"> <i class="fa-solid fa-chevron-right lui-human_view-tree_node__icon lui-human_view-tree_node__icon--placeholder"></i> <span class="lui-human_view-tree_node__key">1:</span> <span class="lui-human_view-tree_node__value lui-human_view-tree_node__value--string">finance</span> </div> </div> <div class="lui-human_view-tree_node"> <div class="lui-human_view-tree_node__leaf"> <i class="fa-solid fa-chevron-right lui-human_view-tree_node__icon lui-human_view-tree_node__icon--placeholder"></i> <span class="lui-human_view-tree_node__key">2:</span> <span class="lui-human_view-tree_node__value lui-human_view-tree_node__value--string">audit</span> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> <div data-extra-data-viewer-target="jsonPanel" class="lui-extra_data_viewer__panel lui-extra_data_viewer__panel--json lui-extra_data_viewer__panel--hidden"> <div data-react-class="Editor" data-react-props="{"mode":"json","name":"code_editor","storedValue":"{\"origin\":\"core\",\"retry_count\":2,\"metadata\":{\"source\":\"manual\",\"tags\":[\"finance\",\"audit\"]}}","readOnly":false,"className":"json-editor"}" data-react-cache-id="Editor-0" style="width:100%"></div> </div> </div></div>ExtraDataViewer
ExtraDataViewer renders structured data in a readable “Human” tree view and optionally a JSON editor view. It’s useful for debugging or inspecting payloads (e.g., extra data) while keeping a consistent UI and (when needed) a read-only editor.
- Inputs:
data(Hash/Array/String JSON), optionaltitle,default_view(human/json), andreadonly(controls JSON editor editability). - Output: A toggle between Human/JSON panels and the corresponding rendered content.
Related components
| Used Components | Components where is Used |
|---|---|
LooposUi::HumanView, LooposUi::CodeEditor, LooposUi::Toggle |
LooposUi::ExtraDataViewer |
Usage rules
✅ Do
- Use it for inspection/debugging of structured payloads (Hash/Array) or JSON strings.
- Prefer
readonly: truein screens where editing extra data is not intended. - Pass a stable
inline_turbo_idif you want the selected view to persist per frame/context.
❌ Don't
- Don’t pass non-JSON strings that look like JSON but aren’t valid; prefer a Hash/Array or a valid JSON string.
- Don’t enable editing (
readonly: false) unless you also provide the inline-edit context (inline_element, paths, hidden fields) to make the save flow work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<% sample_data = { origin: "core", retry_count: 2, metadata: { source: "manual", tags: ["finance", "audit"] } } selected_title = params[:title].presence || "Extra data" selected_view = params[:default_view].presence || "human" readonly_value = ActiveModel::Type::Boolean.new.cast(params[:readonly])%><div class="w-full max-w-4xl"> <%= render LooposUi::ExtraDataViewer.new( title: selected_title, data: sample_data, default_view: selected_view, readonly: readonly_value ) %></div>No notes provided.
| Param | Description | Input |
|---|---|---|
|
Extra data |
|
|
|
— |
|
|
|
Readonly JSON editor |
|
Description
The ExtraDataViewer component displays structured data with two switchable modes:
- Human mode: rendered with
LooposUi::HumanView. - JSON mode: rendered with
LooposUi::CodeEditor.
It is useful for showing extra_data fields in admin/detail pages while allowing inline edit integrations through the code editor mode.
Arguments
| Property | Default | Description |
|---|---|---|
title |
nil |
Optional title shown in human/JSON views. |
data |
required | Data to display. Accepts Hash, Array or String. |
readonly |
false |
Makes the JSON editor read-only. |
default_view |
"human" |
Initial mode. Allowed values: "human" or "json". |
inline_element |
nil |
Inline edit target model instance for CodeEditor. |
inline_attribute |
nil |
Attribute name used by inline edit mode. |
inline_show_path |
nil |
Show path used by inline edit mode. |
inline_edit_path |
nil |
Optional explicit edit path override. |
inline_form_url |
nil |
Optional explicit form submit URL override. |
inline_input_name |
nil |
Optional explicit input name for form submission. |
inline_show_edit_button |
true |
Shows/hides inline edit button in JSON editor mode. |
inline_turbo_id |
nil |
Optional turbo-frame id wrapper key for persistence. |
inline_hidden_fields |
{} |
Extra hidden fields merged into editor form hidden fields. |
Behavior Notes
- If
default_viewis invalid, the component falls back to"human". - If request param
extra_data_viewer_default_viewis present and valid, it overrides the initial view. - JSON payload is normalized using
json_code:Hash/Array->to_jsonString-> unchanged- any other value ->
to_s