@rebasepro/plugin-insights 0.3.0 → 0.5.0

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.
Files changed (36) hide show
  1. package/README.md +115 -0
  2. package/dist/common/src/collections/default-collections.d.ts +5 -8
  3. package/dist/common/src/data/query_builder.d.ts +6 -2
  4. package/dist/common/src/util/permissions.d.ts +14 -6
  5. package/dist/core/src/components/LoginView/LoginView.d.ts +9 -1
  6. package/dist/core/src/components/common/types.d.ts +3 -3
  7. package/dist/core/src/hooks/data/useCollectionFetch.d.ts +12 -1
  8. package/dist/index.es.js +215 -164
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/index.umd.js +215 -164
  11. package/dist/index.umd.js.map +1 -1
  12. package/dist/plugin-insights/src/components/InsightWidget.d.ts +2 -2
  13. package/dist/plugin-insights/src/components/InsightWidgetSkeleton.d.ts +3 -1
  14. package/dist/plugin-insights/src/components/InsightsScorecardView.d.ts +3 -1
  15. package/dist/types/src/controllers/auth.d.ts +2 -2
  16. package/dist/types/src/controllers/client.d.ts +25 -40
  17. package/dist/types/src/controllers/data.d.ts +21 -3
  18. package/dist/types/src/controllers/data_driver.d.ts +5 -0
  19. package/dist/types/src/controllers/email.d.ts +2 -0
  20. package/dist/types/src/types/auth_adapter.d.ts +3 -56
  21. package/dist/types/src/types/backend.d.ts +38 -3
  22. package/dist/types/src/types/backend_hooks.d.ts +2 -17
  23. package/dist/types/src/types/collections.d.ts +30 -6
  24. package/dist/types/src/types/entity_views.d.ts +19 -28
  25. package/dist/types/src/types/properties.d.ts +9 -15
  26. package/dist/types/src/types/user_management_delegate.d.ts +16 -53
  27. package/dist/types/src/users/index.d.ts +0 -1
  28. package/dist/types/src/users/user.d.ts +0 -1
  29. package/dist/ui/src/components/Card.d.ts +2 -3
  30. package/dist/ui/src/components/FilterChip.d.ts +2 -10
  31. package/dist/ui/src/components/VirtualTable/VirtualTableProps.d.ts +8 -2
  32. package/package.json +4 -4
  33. package/src/components/InsightWidget.tsx +33 -4
  34. package/src/components/InsightWidgetSkeleton.tsx +7 -1
  35. package/src/components/InsightsScorecardView.tsx +4 -1
  36. package/dist/types/src/users/roles.d.ts +0 -14
@@ -1,14 +1,36 @@
1
1
  import React from "react";
2
- import type { InsightDefinition, DataRow } from "../types";
2
+ import type { InsightDefinition, DataRow, ScorecardConfig } from "../types";
3
3
  import { useInsightsData } from "../engine/useInsightsData";
4
4
  import { InsightsScorecardView } from "./InsightsScorecardView";
5
5
  import { InsightWidgetSkeleton } from "./InsightWidgetSkeleton";
6
6
 
7
+ /**
8
+ * Compute a deterministic fixed height for a standard scorecard based
9
+ * on which optional elements the config declares. This eliminates
10
+ * layout shift between skeleton and loaded states.
11
+ *
12
+ * Breakdown (non-compact, non-small):
13
+ * py-4 padding: 16 + 16 = 32
14
+ * title row: 16.5 (text-xs leading-snug)
15
+ * mb-2 margin: 8
16
+ * value: 30 (text-2xl leading-tight)
17
+ * ---
18
+ * base: 86.5
19
+ * + dateRange: +16 (14px text + 2px mt-0.5)
20
+ * + comparison: +20 (16px text + 4px mt-1)
21
+ */
22
+ function computeFixedHeight(config: ScorecardConfig): number {
23
+ let h = 86.5; // base: padding + title + mb-2 + value
24
+ if (config.dateRange) h += 16;
25
+ if (config.comparison) h += 20;
26
+ return Math.ceil(h);
27
+ }
28
+
7
29
  /**
8
30
  * Single insight widget orchestrator.
9
31
  *
10
- * Fetches data via the engine, renders the scorecard visualization,
11
- * and manages loading/error states.
32
+ * Wraps skeleton and loaded states in a fixed-height container
33
+ * (computed from the scorecard config) to prevent layout shift.
12
34
  *
13
35
  * All theme-awareness is handled via Tailwind `dark:` classes.
14
36
  */
@@ -30,14 +52,19 @@ export function InsightWidget({
30
52
  }) {
31
53
  const { data, loading, error } = useInsightsData(definition, { path, collectionSlug, parentCollectionSlugs });
32
54
 
55
+ // For non-compact, non-embedded standard scorecards, use a fixed height
56
+ // derived from the config to prevent layout shift between skeleton → loaded.
57
+ const fixedHeight = (!compact && !embedded) ? computeFixedHeight(definition.scorecard) : undefined;
58
+
33
59
  if (loading) {
34
- return <InsightWidgetSkeleton config={definition.scorecard} compact={compact} embedded={embedded} />;
60
+ return <InsightWidgetSkeleton config={definition.scorecard} compact={compact} embedded={embedded} fixedHeight={fixedHeight} />;
35
61
  }
36
62
 
37
63
  if (error) {
38
64
  return (
39
65
  <div
40
66
  className={`text-red-500/70 dark:text-red-400/70 text-[0.8125rem] ${embedded ? "px-5 py-4 h-full" : `rounded-lg bg-red-500/5 dark:bg-red-400/5 border border-red-500/10 dark:border-red-400/10 ${compact ? "px-3.5 py-3" : "px-5 py-4"}`}`}
67
+ style={fixedHeight ? { height: fixedHeight } : undefined}
41
68
  >
42
69
  <div className="font-semibold mb-1">{definition.title}</div>
43
70
  <div>{error.message}</div>
@@ -49,6 +76,7 @@ export function InsightWidget({
49
76
  return (
50
77
  <div
51
78
  className={`text-surface-400 dark:text-surface-500 text-[0.8125rem] ${embedded ? "px-5 py-4 h-full" : `rounded-lg bg-surface-100 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 ${compact ? "px-3.5 py-3" : "px-5 py-4"}`}`}
79
+ style={fixedHeight ? { height: fixedHeight } : undefined}
52
80
  >
53
81
  {definition.title} — No data
54
82
  </div>
@@ -62,6 +90,7 @@ export function InsightWidget({
62
90
  title={definition.title}
63
91
  compact={compact}
64
92
  embedded={embedded}
93
+ fixedHeight={fixedHeight}
65
94
  />
66
95
  );
67
96
  }
@@ -21,12 +21,15 @@ export function InsightWidgetSkeleton({
21
21
  config,
22
22
  compact = false,
23
23
  embedded = false,
24
+ fixedHeight,
24
25
  }: {
25
26
  /** Scorecard config — used to match optional elements (comparison, dateRange, icon). */
26
27
  config: ScorecardConfig;
27
28
  compact?: boolean;
28
29
  /** When true, skip own border since the parent card provides it. */
29
30
  embedded?: boolean;
31
+ /** Explicit height to prevent layout shift between skeleton → loaded. */
32
+ fixedHeight?: number;
30
33
  }) {
31
34
  const hasComparison = Boolean(config.comparison);
32
35
  const hasIcon = Boolean(config.icon);
@@ -74,6 +77,7 @@ export function InsightWidgetSkeleton({
74
77
  hasIcon={hasIcon}
75
78
  hasDateRange={hasDateRange}
76
79
  embedded={embedded}
80
+ fixedHeight={fixedHeight}
77
81
  />;
78
82
  }
79
83
 
@@ -112,11 +116,13 @@ function StandardSkeleton({
112
116
  hasIcon,
113
117
  hasDateRange,
114
118
  embedded,
119
+ fixedHeight,
115
120
  }: {
116
121
  hasComparison: boolean;
117
122
  hasIcon: boolean;
118
123
  hasDateRange: boolean;
119
124
  embedded: boolean;
125
+ fixedHeight?: number;
120
126
  }) {
121
127
  const containerRef = useRef<HTMLDivElement>(null);
122
128
  const [containerWidth, setContainerWidth] = useState<number | null>(null);
@@ -158,7 +164,7 @@ function StandardSkeleton({
158
164
  <div
159
165
  ref={containerRef}
160
166
  className={cls("animate-pulse", baseClass)}
161
- style={embedded ? undefined : { minHeight: isSmall ? 68 : 92 }}
167
+ style={embedded ? undefined : fixedHeight ? { height: fixedHeight } : { minHeight: isSmall ? 68 : 92 }}
162
168
  >
163
169
  {/* Title row — identical flex structure to InsightsScorecardView */}
164
170
  <div className={`flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`}>
@@ -39,6 +39,7 @@ export function InsightsScorecardView({
39
39
  title,
40
40
  compact = false,
41
41
  embedded = false,
42
+ fixedHeight,
42
43
  }: {
43
44
  config: ScorecardConfig;
44
45
  data: DataRow;
@@ -46,6 +47,8 @@ export function InsightsScorecardView({
46
47
  compact?: boolean;
47
48
  /** When true, skip own border/bg since the parent card provides them. */
48
49
  embedded?: boolean;
50
+ /** Explicit height to prevent layout shift between skeleton → loaded. */
51
+ fixedHeight?: number;
49
52
  }) {
50
53
  const containerRef = useRef<HTMLDivElement>(null);
51
54
  const [containerWidth, setContainerWidth] = useState<number | null>(null);
@@ -124,7 +127,7 @@ export function InsightsScorecardView({
124
127
  : cls("rounded-lg flex flex-col min-w-0 bg-transparent border", defaultBorderMixin, isSmall ? "px-3.5 py-3" : "px-5 py-4");
125
128
 
126
129
  return (
127
- <div ref={containerRef} className={baseClass} style={embedded ? undefined : { minHeight: isSmall ? 68 : 92 }}>
130
+ <div ref={containerRef} className={baseClass} style={embedded ? undefined : fixedHeight ? { height: fixedHeight } : { minHeight: isSmall ? 68 : 92 }}>
128
131
  {/* Title row */}
129
132
  <div className={`flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`}>
130
133
  <div className="flex flex-col min-w-0">
@@ -1,14 +0,0 @@
1
- export type Role = {
2
- /**
3
- * ID of the role
4
- */
5
- id: string;
6
- /**
7
- * Name of the role
8
- */
9
- name: string;
10
- /**
11
- * If this flag is true, the user can perform any action
12
- */
13
- isAdmin?: boolean;
14
- };