@izumisy-tailor/tailor-data-viewer 0.1.8 → 0.1.9

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.8",
4
+ "version": "0.1.9",
5
5
  "type": "module",
6
6
  "description": "Flexible data viewer component for Tailor Platform",
7
7
  "files": [
@@ -1,9 +1,11 @@
1
1
  import { useState, useCallback } from "react";
2
- import { Plus, X, Loader2 } from "lucide-react";
2
+ import { Plus, X } from "lucide-react";
3
3
  import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
4
4
  import { Button } from "./ui/button";
5
- import type { TableMetadata, TableMetadataMap } from "../generator/metadata-generator";
6
- import { useTableAccessCheck } from "./hooks/use-table-access-check";
5
+ import type {
6
+ TableMetadata,
7
+ TableMetadataMap,
8
+ } from "../generator/metadata-generator";
7
9
  import { DataViewTabContent } from "./data-view-tab-content";
8
10
  import { SingleRecordTabContent } from "./single-record-tab-content";
9
11
  import { useSavedViews, type SavedView } from "./saved-view-context";
@@ -54,12 +56,7 @@ export function DataViewer({
54
56
  appUri,
55
57
  initialViewId,
56
58
  }: DataViewerProps) {
57
- // Get tables accessible to the current user via runtime permission check
58
59
  const allTables = Object.values(tableMetadata);
59
- const { accessibleTables, isLoading, error } = useTableAccessCheck(
60
- allTables,
61
- appUri,
62
- );
63
60
  const { getViewById } = useSavedViews();
64
61
 
65
62
  // Tab management - initialize with saved view if provided
@@ -188,45 +185,6 @@ export function DataViewer({
188
185
  [tableMetadata],
189
186
  );
190
187
 
191
- // Loading state during permission check
192
- if (isLoading) {
193
- return (
194
- <Card>
195
- <CardContent className="py-8">
196
- <div className="flex flex-col items-center gap-2 text-muted-foreground">
197
- <Loader2 className="size-6 animate-spin" />
198
- <span>テーブルへのアクセス権限を確認中...</span>
199
- </div>
200
- </CardContent>
201
- </Card>
202
- );
203
- }
204
-
205
- // Error state
206
- if (error) {
207
- return (
208
- <Card>
209
- <CardContent className="py-8">
210
- <div className="text-destructive text-center">
211
- アクセス権限の確認中にエラーが発生しました: {error}
212
- </div>
213
- </CardContent>
214
- </Card>
215
- );
216
- }
217
-
218
- if (accessibleTables.length === 0) {
219
- return (
220
- <Card>
221
- <CardContent className="py-8">
222
- <div className="text-muted-foreground text-center">
223
- アクセス可能なテーブルがありません
224
- </div>
225
- </CardContent>
226
- </Card>
227
- );
228
- }
229
-
230
188
  return (
231
189
  <Card>
232
190
  <CardHeader className="pb-2">
@@ -289,7 +247,7 @@ export function DataViewer({
289
247
  />
290
248
  ) : (
291
249
  <DataViewTabContent
292
- tables={accessibleTables}
250
+ tables={allTables}
293
251
  appUri={appUri}
294
252
  initialTable={tab.table ?? undefined}
295
253
  onTableConfirm={(table) => handleTableConfirm(tab.id, table)}
@@ -9,10 +9,6 @@ export { SearchFilterForm } from "./search-filter";
9
9
  export { ViewSave } from "./view-save-load";
10
10
  export { useTableData } from "./hooks/use-table-data";
11
11
  export { useColumnState } from "./hooks/use-column-state";
12
- export {
13
- useTableAccessCheck,
14
- checkTableAccess,
15
- } from "./hooks/use-table-access-check";
16
12
  export { useSavedViews, SavedViewProvider } from "./saved-view-context";
17
13
  export type { SavedView, SaveViewInput } from "./saved-view-context";
18
14
  export type { SearchFilter, SearchFilters } from "./types";
@@ -1,22 +0,0 @@
1
- import { useMemo } from "react";
2
- import type {
3
- TableMetadata,
4
- TableMetadataMap,
5
- } from "../../generator/metadata-generator";
6
-
7
- /**
8
- * Filter tables based on user's roles
9
- * Returns only tables the user has read access to
10
- */
11
- export function useAccessibleTables(
12
- tableMetadata: TableMetadataMap,
13
- userRoles: string[],
14
- ): TableMetadata[] {
15
- return useMemo(() => {
16
- return Object.values(tableMetadata).filter((table) =>
17
- table.readAllowedRoles.some((role) =>
18
- userRoles.map((r) => r.toUpperCase()).includes(role.toUpperCase()),
19
- ),
20
- );
21
- }, [tableMetadata, userRoles]);
22
- }
@@ -1,108 +0,0 @@
1
- import { useState, useEffect, useMemo } from "react";
2
- import { GraphQLClient } from "graphql-request";
3
- import type { TableMetadata } from "../../generator/metadata-generator";
4
-
5
- export interface TableAccessCheckResult {
6
- /** Tables that the user has access to */
7
- accessibleTables: TableMetadata[];
8
- /** Whether the check is in progress */
9
- isLoading: boolean;
10
- /** Error message if the check failed entirely */
11
- error: string | null;
12
- }
13
-
14
- /**
15
- * Check which tables the user has access to by executing aggregate queries
16
- * Uses server-side gqlPermission as the source of truth
17
- */
18
- export function useTableAccessCheck(
19
- tables: TableMetadata[],
20
- appUri: string,
21
- ): TableAccessCheckResult {
22
- const [accessibleTables, setAccessibleTables] = useState<TableMetadata[]>([]);
23
- const [isLoading, setIsLoading] = useState(true);
24
- const [error, setError] = useState<string | null>(null);
25
-
26
- // Memoize tables to prevent infinite loops
27
- // when the parent component passes a new array reference on each render
28
- const tableKey = tables.map((t) => t.name).join(",");
29
- const stableTables = useMemo(() => tables, [tableKey]);
30
-
31
- useEffect(() => {
32
- let cancelled = false;
33
-
34
- async function checkAccess() {
35
- setIsLoading(true);
36
- setError(null);
37
-
38
- const client = new GraphQLClient(`${appUri}/query`, {
39
- credentials: "include",
40
- headers: {
41
- "Content-Type": "application/json",
42
- "X-Tailor-Nonce": crypto.randomUUID(),
43
- },
44
- });
45
-
46
- const results = await Promise.allSettled(
47
- stableTables.map(async (table) => {
48
- // Execute a lightweight aggregate query to check access
49
- const query = `query CheckAccess { ${table.pluralForm}(query: {}) { total } }`;
50
- await client.request(query);
51
- return table;
52
- }),
53
- );
54
-
55
- if (cancelled) return;
56
-
57
- // Filter to only fulfilled results (tables with access)
58
- const accessible = results
59
- .filter(
60
- (r): r is PromiseFulfilledResult<TableMetadata> =>
61
- r.status === "fulfilled",
62
- )
63
- .map((r) => r.value);
64
-
65
- setAccessibleTables(accessible);
66
- setIsLoading(false);
67
- }
68
-
69
- checkAccess().catch((err) => {
70
- if (!cancelled) {
71
- setError(
72
- err instanceof Error ? err.message : "Failed to check table access",
73
- );
74
- setIsLoading(false);
75
- }
76
- });
77
-
78
- return () => {
79
- cancelled = true;
80
- };
81
- }, [stableTables, appUri]);
82
-
83
- return { accessibleTables, isLoading, error };
84
- }
85
-
86
- /**
87
- * Standalone function to check table access (non-hook version)
88
- * Useful for one-time checks or server-side usage
89
- */
90
- export async function checkTableAccess(
91
- client: GraphQLClient,
92
- tables: TableMetadata[],
93
- ): Promise<TableMetadata[]> {
94
- const results = await Promise.allSettled(
95
- tables.map(async (table) => {
96
- const query = `query CheckAccess { ${table.pluralForm}(query: {}) { total } }`;
97
- await client.request(query);
98
- return table;
99
- }),
100
- );
101
-
102
- return results
103
- .filter(
104
- (r): r is PromiseFulfilledResult<TableMetadata> =>
105
- r.status === "fulfilled",
106
- )
107
- .map((r) => r.value);
108
- }