@cat-factory/app 0.231.1 → 0.232.1

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.
@@ -8,10 +8,12 @@
8
8
  // once the block exists (`useContextLinking().linkPending`). The inspector's own panels are the
9
9
  // live counterpart, for a block that already exists.
10
10
  //
11
- // Both sections are ungated: when the relevant integration isn't connected the Attach button
12
- // becomes a "Connect a source" action instead of vanishing, so the capability is discoverable.
13
- // Connecting opens the source's connect modal OVER the host modal (both are root-mounted with
14
- // independent open flags), so in-progress form data survives.
11
+ // Attaching is ungated in both sections: when the relevant integration isn't connected the Attach
12
+ // button becomes a "Connect a source" action instead of vanishing, so the capability is
13
+ // discoverable. Connecting opens the source's connect modal OVER the host modal (both are
14
+ // root-mounted with independent open flags), so in-progress form data survives. That upgrade is
15
+ // itself gated on `integrations.manage` for documents, whose ATTACH writes are member-tier while
16
+ // storing the credential is not.
15
17
  import type { PendingContext } from '~/composables/useContextLinking'
16
18
  import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.vue'
17
19
  import ContextIssuePicker from '~/components/tasks/ContextIssuePicker.vue'
@@ -45,8 +47,16 @@ const issuesConnected = computed(() => tasks.available && tasks.anyOffered)
45
47
  // documents, every configured source without a live connection (GitHub docs are already implicitly
46
48
  // connected via the App, so they never appear here); for issues, every configured tracker not yet
47
49
  // available. The connect modals are the same ones the Integrations hub opens.
50
+ //
51
+ // The document half is additionally empty for anyone without `integrations.manage`: connecting
52
+ // stores a workspace credential and stays admin-tier, while attaching a document moved to the
53
+ // member tier, so a member falls through to the disabled Attach button instead of a connect
54
+ // action that opens a modal, takes a token and 403s.
55
+ const { canManageIntegrations } = useWorkspaceAccess()
48
56
  const connectableDocSources = computed(() =>
49
- documents.available ? documents.sources.filter((s) => !documents.isConnected(s.source)) : [],
57
+ documents.available && canManageIntegrations.value
58
+ ? documents.sources.filter((s) => !documents.isConnected(s.source))
59
+ : [],
50
60
  )
51
61
  const connectableIssueSources = computed(() =>
52
62
  tasks.available ? tasks.sources.filter((s) => !s.available) : [],
@@ -54,8 +54,16 @@ const chosenKeys = computed(() =>
54
54
  const connected = computed(() => documents.available && documents.anyConnected)
55
55
  // Sources the user could connect right now to unlock the picker, when none is
56
56
  // connected yet (GitHub docs are implicitly connected via the App, so never here).
57
+ //
58
+ // Empty for anyone without `integrations.manage`, because connecting stores a workspace
59
+ // credential and stays admin-tier while ATTACHING moved to the member tier. Offering the
60
+ // action to a member was a dead end: the connect modal opened, took a token, and 403'd.
61
+ // Attaching is unaffected, which is the point of the split.
62
+ const { canManageIntegrations } = useWorkspaceAccess()
57
63
  const connectableSources = computed(() =>
58
- documents.available ? documents.sources.filter((s) => !documents.isConnected(s.source)) : [],
64
+ documents.available && canManageIntegrations.value
65
+ ? documents.sources.filter((s) => !documents.isConnected(s.source))
66
+ : [],
59
67
  )
60
68
  const connectMenu = computed<DropdownMenuItem[][]>(() => [
61
69
  connectableSources.value.map((s) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.231.1",
3
+ "version": "0.232.1",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  "valibot": "^1.4.2",
41
41
  "vue": "3.5.40",
42
42
  "wretch": "^3.0.9",
43
- "@cat-factory/contracts": "0.249.0"
43
+ "@cat-factory/contracts": "0.250.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",