terrazzo 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/views/terrazzo/application/_show_base.json.props +5 -5
- data/lib/generators/terrazzo/views/templates/fields/has_many/ShowField.jsx +29 -71
- data/lib/generators/terrazzo/views/templates/pages/_collection.jsx +4 -48
- data/lib/terrazzo/field/has_many.rb +12 -6
- data/lib/terrazzo/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6976f4987f794484e19de73da573e1b7d65dfc75a0852133c1eebf005d22167e
|
|
4
|
+
data.tar.gz: 4dc5597241838c5523ed2a5a50d23185a0e21199b18ae9dd07128d7687e836e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 673cd873e8c295de85c4bc2d798a33d4879e37cfded9357d01c08b1617e050931502193c3be3c445f0577f4bc29372bc15867b3e4fafe519161f6209d894ca4f
|
|
7
|
+
data.tar.gz: ae15ddf2abd934407d97f3e17d4344e68f5ff93e7fce588f9d520998d017404f980c7f75d07709ba2e984ae49490d65d9a573d4f169949c8b03cce849402f46b
|
|
@@ -9,11 +9,11 @@ show_field_json = ->(json, field) do
|
|
|
9
9
|
|
|
10
10
|
if field.class.associative? && field.data.present?
|
|
11
11
|
if field.is_a?(Terrazzo::Field::HasMany)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
hash[record.id.to_s] =
|
|
12
|
+
render_actions = field.options.fetch(:render_actions, true)
|
|
13
|
+
json.hasManyRowExtras(field.data.each_with_object({}) do |record, hash|
|
|
14
|
+
extras = { showPath: (polymorphic_path([namespace, record]) rescue nil) }
|
|
15
|
+
extras[:collectionItemActions] = collection_item_actions(record) if render_actions
|
|
16
|
+
hash[record.id.to_s] = extras
|
|
17
17
|
end)
|
|
18
18
|
else
|
|
19
19
|
json.showPath polymorphic_path([namespace, field.data]) rescue nil
|
|
@@ -1,85 +1,36 @@
|
|
|
1
|
-
import React, { useState
|
|
2
|
-
import { NavigationContext } from "@thoughtbot/superglue";
|
|
1
|
+
import React, { useState } from "react";
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
Table,
|
|
6
|
-
TableHeader,
|
|
7
|
-
TableBody,
|
|
8
|
-
TableRow,
|
|
9
|
-
TableHead,
|
|
10
|
-
TableCell,
|
|
11
|
-
} from "terrazzo/ui";
|
|
3
|
+
import { ResourceTable } from "terrazzo/components";
|
|
12
4
|
import { Badge } from "terrazzo/ui";
|
|
13
5
|
import { Button } from "terrazzo/ui";
|
|
14
|
-
import { CollectionItemActions } from "terrazzo/components";
|
|
15
|
-
import { FieldRenderer } from "../FieldRenderer";
|
|
16
6
|
|
|
17
|
-
export function ShowField({ value,
|
|
7
|
+
export function ShowField({ value, hasManyRowExtras, options }) {
|
|
18
8
|
if (!value) return <span className="text-muted-foreground">None</span>;
|
|
19
9
|
|
|
20
|
-
const {
|
|
10
|
+
const { rows, headers, total, initialLimit, items } = value;
|
|
21
11
|
const [expanded, setExpanded] = useState(false);
|
|
22
|
-
const { visit } = useContext(NavigationContext);
|
|
23
12
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
// Table mode: collection_attributes specified
|
|
14
|
+
if (headers && rows) {
|
|
15
|
+
if (rows.length === 0) {
|
|
16
|
+
return <span className="text-muted-foreground">None</span>;
|
|
17
|
+
}
|
|
27
18
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const visibleItems = expanded || !hasMore ? items : items.slice(0, initialLimit);
|
|
19
|
+
const hasMore = initialLimit && initialLimit > 0 && total > initialLimit;
|
|
20
|
+
const visibleRows = expanded || !hasMore ? rows : rows.slice(0, initialLimit);
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
const enrichedRows = visibleRows.map((row) => {
|
|
23
|
+
const extras = hasManyRowExtras?.[String(row.id)] || {};
|
|
24
|
+
return {
|
|
25
|
+
...row,
|
|
26
|
+
showPath: extras.showPath,
|
|
27
|
+
collectionItemActions: extras.collectionItemActions,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
38
30
|
|
|
39
|
-
// Table mode: collection_attributes specified
|
|
40
|
-
if (headers) {
|
|
41
31
|
return (
|
|
42
32
|
<div>
|
|
43
|
-
<
|
|
44
|
-
<Table>
|
|
45
|
-
<TableHeader>
|
|
46
|
-
<TableRow>
|
|
47
|
-
{headers.map((header) =>
|
|
48
|
-
<TableHead key={header.attribute}>{header.label}</TableHead>
|
|
49
|
-
)}
|
|
50
|
-
{collectionItemActions && <TableHead></TableHead>}
|
|
51
|
-
</TableRow>
|
|
52
|
-
</TableHeader>
|
|
53
|
-
<TableBody>
|
|
54
|
-
{visibleItems.map((item) => {
|
|
55
|
-
const showPath = pathFor(item.id);
|
|
56
|
-
return (
|
|
57
|
-
<TableRow
|
|
58
|
-
key={item.id}
|
|
59
|
-
className={showPath ? "cursor-pointer" : ""}
|
|
60
|
-
onClick={(e) => handleRowClick(e, showPath)}>
|
|
61
|
-
{item.columns.map((col, colIndex) =>
|
|
62
|
-
<TableCell key={col.attribute}>
|
|
63
|
-
{showPath && colIndex === 0 ? (
|
|
64
|
-
<a href={showPath} data-sg-visit className="hover:underline">
|
|
65
|
-
<FieldRenderer mode="index" {...col} />
|
|
66
|
-
</a>
|
|
67
|
-
) : (
|
|
68
|
-
<FieldRenderer mode="index" {...col} />
|
|
69
|
-
)}
|
|
70
|
-
</TableCell>
|
|
71
|
-
)}
|
|
72
|
-
{collectionItemActions && (
|
|
73
|
-
<TableCell>
|
|
74
|
-
<CollectionItemActions actions={collectionItemActions?.[String(item.id)]} />
|
|
75
|
-
</TableCell>
|
|
76
|
-
)}
|
|
77
|
-
</TableRow>
|
|
78
|
-
);
|
|
79
|
-
})}
|
|
80
|
-
</TableBody>
|
|
81
|
-
</Table>
|
|
82
|
-
</div>
|
|
33
|
+
<ResourceTable headers={headers} rows={enrichedRows} showActions={options?.renderActions !== false} />
|
|
83
34
|
{hasMore && (
|
|
84
35
|
<Button
|
|
85
36
|
variant="link"
|
|
@@ -93,12 +44,19 @@ export function ShowField({ value, itemShowPaths, collectionItemActions }) {
|
|
|
93
44
|
);
|
|
94
45
|
}
|
|
95
46
|
|
|
96
|
-
// Simple list mode
|
|
47
|
+
// Simple list mode (no collection_attributes)
|
|
48
|
+
if (!items || items.length === 0) {
|
|
49
|
+
return <span className="text-muted-foreground">None</span>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const hasMore = initialLimit && initialLimit > 0 && total > initialLimit;
|
|
53
|
+
const visibleItems = expanded || !hasMore ? items : items.slice(0, initialLimit);
|
|
54
|
+
|
|
97
55
|
return (
|
|
98
56
|
<div>
|
|
99
57
|
<div className="flex flex-wrap items-center gap-1.5">
|
|
100
58
|
{visibleItems.map((item) => {
|
|
101
|
-
const showPath =
|
|
59
|
+
const showPath = hasManyRowExtras?.[String(item.id)]?.showPath;
|
|
102
60
|
return showPath ? (
|
|
103
61
|
<a key={item.id} href={showPath} data-sg-visit>
|
|
104
62
|
<Badge variant="secondary" className="cursor-pointer">{item.display}</Badge>
|
|
@@ -1,55 +1,11 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { NavigationContext } from "@thoughtbot/superglue";
|
|
1
|
+
import React from "react";
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
import { FieldRenderer } from "terrazzo/fields";
|
|
6
|
-
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from "terrazzo/ui";
|
|
3
|
+
import { ResourceTable } from "terrazzo/components";
|
|
7
4
|
|
|
8
5
|
export function AdminCollection({ table }) {
|
|
9
|
-
const { visit } = useContext(NavigationContext);
|
|
10
|
-
|
|
11
|
-
const handleRowClick = (e, showPath) => {
|
|
12
|
-
if (!showPath) return;
|
|
13
|
-
if (e.target.closest("a, button, form")) return;
|
|
14
|
-
if (window.getSelection().toString()) return;
|
|
15
|
-
visit(showPath, {});
|
|
16
|
-
};
|
|
17
|
-
|
|
18
6
|
return (
|
|
19
|
-
<div className="overflow-x-auto
|
|
20
|
-
<
|
|
21
|
-
<TableHeader>
|
|
22
|
-
<TableRow>
|
|
23
|
-
{table.headers.map((header) =>
|
|
24
|
-
<SortableHeader key={header.attribute} {...header} />
|
|
25
|
-
)}
|
|
26
|
-
<TableHead className="w-[120px]">Actions</TableHead>
|
|
27
|
-
</TableRow>
|
|
28
|
-
</TableHeader>
|
|
29
|
-
<TableBody>
|
|
30
|
-
{table.rows.map((row) =>
|
|
31
|
-
<TableRow
|
|
32
|
-
key={row.id}
|
|
33
|
-
className={row.showPath ? "cursor-pointer" : ""}
|
|
34
|
-
onClick={(e) => handleRowClick(e, row.showPath)}>
|
|
35
|
-
{row.cells.map((cell) =>
|
|
36
|
-
<TableCell key={cell.attribute}>
|
|
37
|
-
{cell.showPath ? (
|
|
38
|
-
<a href={cell.showPath} data-sg-visit className="hover:underline">
|
|
39
|
-
<FieldRenderer mode="index" {...cell} />
|
|
40
|
-
</a>
|
|
41
|
-
) : (
|
|
42
|
-
<FieldRenderer mode="index" {...cell} />
|
|
43
|
-
)}
|
|
44
|
-
</TableCell>
|
|
45
|
-
)}
|
|
46
|
-
<TableCell>
|
|
47
|
-
<CollectionItemActions actions={row.collectionItemActions} />
|
|
48
|
-
</TableCell>
|
|
49
|
-
</TableRow>
|
|
50
|
-
)}
|
|
51
|
-
</TableBody>
|
|
52
|
-
</Table>
|
|
7
|
+
<div className="overflow-x-auto">
|
|
8
|
+
<ResourceTable headers={table.headers} rows={table.rows} />
|
|
53
9
|
</div>
|
|
54
10
|
);
|
|
55
11
|
}
|
|
@@ -20,8 +20,14 @@ module Terrazzo
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def serializable_options(page = nil)
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
opts = {}
|
|
24
|
+
if page == :form && resource
|
|
25
|
+
opts[:resourceOptions] = resource_options
|
|
26
|
+
end
|
|
27
|
+
if options.key?(:render_actions)
|
|
28
|
+
opts[:renderActions] = options[:render_actions]
|
|
29
|
+
end
|
|
30
|
+
opts
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
class << self
|
|
@@ -72,8 +78,8 @@ module Terrazzo
|
|
|
72
78
|
{ attribute: attr.to_s, label: attr.to_s.humanize }
|
|
73
79
|
end
|
|
74
80
|
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
rows = records.map do |record|
|
|
82
|
+
cells = col_attrs.map do |attr|
|
|
77
83
|
field = dashboard_class.new.attribute_type_for(attr).new(attr, nil, :index, resource: record)
|
|
78
84
|
{
|
|
79
85
|
attribute: attr.to_s,
|
|
@@ -81,12 +87,12 @@ module Terrazzo
|
|
|
81
87
|
value: field.serialize_value(:index)
|
|
82
88
|
}
|
|
83
89
|
end
|
|
84
|
-
{ id: record.id.to_s,
|
|
90
|
+
{ id: record.id.to_s, cells: cells }
|
|
85
91
|
end
|
|
86
92
|
|
|
87
93
|
{
|
|
88
94
|
headers: headers,
|
|
89
|
-
|
|
95
|
+
rows: rows,
|
|
90
96
|
total: total,
|
|
91
97
|
initialLimit: limit
|
|
92
98
|
}
|
data/lib/terrazzo/version.rb
CHANGED