@growth-operations/ui-shared 1.0.9 → 1.0.10

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@growth-operations/ui-shared",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "Shared HubSpot UI-extension modules (Home, Billing) for Growth Operations apps.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -6,6 +6,7 @@ import { OnboardingChecklist } from "./OnboardingChecklist";
6
6
  import { SyncPulse } from "./SyncPulse";
7
7
  import { CreditMeter } from "./CreditMeter";
8
8
  import { FeatureNudges } from "./FeatureNudges";
9
+ import { HelpfulLinks } from "./HelpfulLinks";
9
10
 
10
11
  // Minimal inline ATS tile (the `pipeline` block). Kept tiny here rather than a
11
12
  // separate file — it's the simplest of the three archetype tiles. Renders
@@ -76,7 +77,13 @@ function ArchetypeTile({ state }) {
76
77
  // PageLink navigation (the host owns the router).
77
78
  // appName — display name override; defaults to state.app.name.
78
79
  // onRetry — optional, passed to InstallProgress for the failed state.
79
- export function AppHome({ state, onNavigate, appName, onRetry }) {
80
+ // helpfulLinks — optional props for the standard HelpfulLinks section
81
+ // (e.g. { portalId, appId, appName, docsUrl, supportUrl,
82
+ // links }). Omit to hide the section. The host passes this
83
+ // (it owns context.portal.id + the app's docs/support); it can
84
+ // also come from a state.helpful_links block if the backend
85
+ // builds one.
86
+ export function AppHome({ state, onNavigate, appName, onRetry, helpfulLinks }) {
80
87
  if (!state) {
81
88
  return <LoadingSpinner showLabel label="Loading…" />;
82
89
  }
@@ -85,10 +92,21 @@ export function AppHome({ state, onNavigate, appName, onRetry }) {
85
92
  const activationComplete =
86
93
  !activation || activation.complete === true || activation.status === "completed";
87
94
 
95
+ // HelpfulLinks props: explicit prop wins, else a state.helpful_links block if
96
+ // the backend builds one. Shown in both the install and cockpit views so help
97
+ // is reachable even mid-setup.
98
+ const links = helpfulLinks ?? state.helpful_links ?? null;
99
+ const helpfulLinksEl = links ? <HelpfulLinks {...links} /> : null;
100
+
88
101
  // Install isn't finished (running / failed / completed-with-warnings) — show
89
102
  // the install experience instead of the cockpit.
90
103
  if (!activationComplete) {
91
- return <InstallProgress state={state} onRetry={onRetry} />;
104
+ return (
105
+ <Flex direction="column" gap="medium">
106
+ <InstallProgress state={state} onRetry={onRetry} />
107
+ {helpfulLinksEl}
108
+ </Flex>
109
+ );
92
110
  }
93
111
 
94
112
  const onboardingComplete = state.onboarding?.complete === true;
@@ -108,6 +126,8 @@ export function AppHome({ state, onNavigate, appName, onRetry }) {
108
126
  <ArchetypeTile state={state} />
109
127
 
110
128
  <FeatureNudges nudges={state.nudges} onNavigate={onNavigate} />
129
+
130
+ {helpfulLinksEl}
111
131
  </Flex>
112
132
  );
113
133
  }
@@ -35,18 +35,26 @@ export function HelpfulLinks({
35
35
  links = [],
36
36
  title = "Helpful Links",
37
37
  }) {
38
+ // external=false keeps navigation in the SAME tab. The app-pages deep link is
39
+ // an in-app HubSpot URL, so it must stay same-tab (external:true would force a
40
+ // new tab). Docs/support and app-specific extras are off-platform → external.
38
41
  const items = [];
39
42
 
40
43
  if (appPages && appId && portalId != null) {
41
44
  items.push({
42
45
  label: `Open ${appName} →`,
43
46
  url: appPagesUrl(portalId, appId, appPagesPath),
47
+ external: false,
44
48
  });
45
49
  }
46
- if (docsUrl) items.push({ label: "Documentation", url: docsUrl });
47
- if (supportUrl) items.push({ label: "Support", url: supportUrl });
50
+ if (docsUrl) items.push({ label: "Documentation", url: docsUrl, external: true });
51
+ if (supportUrl) items.push({ label: "Support", url: supportUrl, external: true });
48
52
  for (const l of links) {
49
- if (l && l.url && l.label) items.push({ label: l.label, url: l.url });
53
+ if (l && l.url && l.label) {
54
+ // Default app-specific extras to external (they're usually HubSpot record
55
+ // URLs or off-platform), but let a link opt into same-tab via external:false.
56
+ items.push({ label: l.label, url: l.url, external: l.external !== false });
57
+ }
50
58
  }
51
59
 
52
60
  if (items.length === 0) return null;
@@ -56,7 +64,7 @@ export function HelpfulLinks({
56
64
  <Text format={{ fontWeight: "bold" }}>{title}</Text>
57
65
  <Divider />
58
66
  {items.map((item) => (
59
- <Link key={item.url} href={{ url: item.url, external: true }}>
67
+ <Link key={item.url} href={{ url: item.url, external: item.external }}>
60
68
  {item.label}
61
69
  </Link>
62
70
  ))}