@izumisy-tailor/tailor-data-viewer 0.1.6 → 0.1.7

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@izumisy-tailor/tailor-data-viewer",
3
3
  "private": false,
4
- "version": "0.1.6",
4
+ "version": "0.1.7",
5
5
  "type": "module",
6
6
  "description": "Flexible data viewer component for Tailor Platform",
7
7
  "files": [
@@ -1,9 +1,28 @@
1
- import { defineModule, defineResource } from "@tailor-platform/app-shell";
2
- import { Database } from "lucide-react";
1
+ import {
2
+ defineModule,
3
+ defineResource,
4
+ useNavigate,
5
+ useSearchParams,
6
+ Link,
7
+ } from "@tailor-platform/app-shell";
8
+ import {
9
+ Database,
10
+ Trash2,
11
+ Calendar,
12
+ Filter,
13
+ Columns,
14
+ LayoutGrid,
15
+ } from "lucide-react";
3
16
  import type { DataViewModuleConfig } from "./types";
4
17
  import { isStoreFactory } from "./types";
5
18
  import { DataViewer } from "../component/data-viewer";
6
- import { SavedViewProvider } from "../component/saved-view-context";
19
+ import {
20
+ SavedViewProvider,
21
+ useSavedViews,
22
+ } from "../component/saved-view-context";
23
+ import { Card, CardContent, CardHeader, CardTitle } from "../component/ui/card";
24
+ import { Button } from "../component/ui/button";
25
+ import { Badge } from "../component/ui/badge";
7
26
 
8
27
  /**
9
28
  * Create a DataView module for use with AppShell
@@ -42,22 +61,130 @@ export function createDataViewModule(config: DataViewModuleConfig) {
42
61
 
43
62
  // Create the explorer resource page component
44
63
  const ExplorerPage = () => {
64
+ const [searchParams] = useSearchParams();
65
+ const viewId = searchParams.get("viewId") ?? undefined;
66
+
45
67
  return (
46
68
  <SavedViewProvider store={store}>
47
- <DataViewer tableMetadata={tableMetadata} appUri={appUri} />
69
+ <DataViewer
70
+ tableMetadata={tableMetadata}
71
+ appUri={appUri}
72
+ initialViewId={viewId}
73
+ />
48
74
  </SavedViewProvider>
49
75
  );
50
76
  };
51
77
 
78
+ // Saved views list component (used inside ModulePage)
79
+ const SavedViewsList = ({
80
+ explorerFullPath,
81
+ }: {
82
+ explorerFullPath: string;
83
+ }) => {
84
+ const { views, deleteView } = useSavedViews();
85
+ const navigate = useNavigate();
86
+
87
+ const handleOpenView = (viewId: string) => {
88
+ navigate(`${explorerFullPath}?viewId=${viewId}`);
89
+ };
90
+
91
+ return (
92
+ <Card>
93
+ <CardHeader>
94
+ <CardTitle className="flex items-center gap-2">
95
+ <LayoutGrid className="size-5" />
96
+ 保存済みビュー
97
+ </CardTitle>
98
+ </CardHeader>
99
+ <CardContent>
100
+ {views.length === 0 ? (
101
+ <div className="py-8 text-center">
102
+ <div className="text-muted-foreground mb-4">
103
+ 保存されたビューはありません
104
+ </div>
105
+ <Link to={explorerFullPath}>
106
+ <Button variant="outline">
107
+ <Database className="mr-2 size-4" />
108
+ Data View Explorer を開く
109
+ </Button>
110
+ </Link>
111
+ </div>
112
+ ) : (
113
+ <div className="space-y-3">
114
+ {views.map((savedView) => (
115
+ <div
116
+ key={savedView.id}
117
+ className="hover:bg-muted flex cursor-pointer items-center justify-between rounded-lg border p-4 transition-colors"
118
+ onClick={() => handleOpenView(savedView.id)}
119
+ >
120
+ <div className="flex-1">
121
+ <div className="flex items-center gap-2">
122
+ <span className="font-medium">{savedView.name}</span>
123
+ <Badge variant="secondary">{savedView.tableName}</Badge>
124
+ </div>
125
+ <div className="text-muted-foreground mt-1 flex items-center gap-4 text-sm">
126
+ <span className="flex items-center gap-1">
127
+ <Filter className="size-3" />
128
+ {savedView.filters.length} フィルター
129
+ </span>
130
+ <span className="flex items-center gap-1">
131
+ <Columns className="size-3" />
132
+ {savedView.selectedFields.length} カラム
133
+ </span>
134
+ <span className="flex items-center gap-1">
135
+ <Calendar className="size-3" />
136
+ {savedView.createdAt.toLocaleString()}
137
+ </span>
138
+ </div>
139
+ {savedView.filters.length > 0 && (
140
+ <div className="mt-2 flex flex-wrap gap-1">
141
+ {savedView.filters.map((filter) => (
142
+ <Badge
143
+ key={filter.field}
144
+ variant="outline"
145
+ className="text-xs"
146
+ >
147
+ {filter.field}=
148
+ {typeof filter.value === "boolean"
149
+ ? filter.value
150
+ ? "true"
151
+ : "false"
152
+ : filter.value}
153
+ </Badge>
154
+ ))}
155
+ </div>
156
+ )}
157
+ </div>
158
+ <Button
159
+ variant="ghost"
160
+ size="sm"
161
+ className="text-destructive hover:text-destructive"
162
+ onClick={(e) => {
163
+ e.stopPropagation();
164
+ deleteView(savedView.id);
165
+ }}
166
+ >
167
+ <Trash2 className="size-4" />
168
+ </Button>
169
+ </div>
170
+ ))}
171
+ </div>
172
+ )}
173
+ </CardContent>
174
+ </Card>
175
+ );
176
+ };
177
+
52
178
  // Create the module page component
179
+ const explorerFullPath = `/${basePath}/${explorerPath}`;
180
+
53
181
  const ModulePage = () => {
54
182
  return (
55
- <div className="space-y-4">
56
- <h1 className="text-2xl font-bold">{title}</h1>
57
- <p className="text-muted-foreground">
58
- データビューでテーブルを探索できます。
59
- </p>
60
- </div>
183
+ <SavedViewProvider store={store}>
184
+ <div className="space-y-6">
185
+ <SavedViewsList explorerFullPath={explorerFullPath} />
186
+ </div>
187
+ </SavedViewProvider>
61
188
  );
62
189
  };
63
190