@cat-factory/app 0.74.2 → 0.74.3

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.
@@ -66,6 +66,26 @@ const results = ref<TaskSearchResult[]>([])
66
66
  const searching = ref(false)
67
67
  const searchError = ref<string | null>(null)
68
68
 
69
+ // Already-imported issues, scoped to the target container's repo on the backend
70
+ // (GitHub narrows to the service's linked repo, exactly as search does; repo-less
71
+ // sources are unaffected). Held locally rather than read from the shared workspace
72
+ // list, so a task created for one service never offers issues from sibling repos.
73
+ const imported = ref<SourceTask[]>([])
74
+ async function reloadImported() {
75
+ try {
76
+ imported.value = await tasks.listTasksForBlock(props.scopeBlockId)
77
+ } catch {
78
+ imported.value = []
79
+ }
80
+ }
81
+ // Re-scope when the target container changes (its repo, hence the in-repo issues, differ).
82
+ watch(
83
+ () => props.scopeBlockId,
84
+ () => {
85
+ reloadImported()
86
+ },
87
+ )
88
+
69
89
  // Debounced search: free text hits the tracker; a query that's clearly a URL/key
70
90
  // is left to the explicit "by reference" row below (search won't surface it).
71
91
  // Re-scope when `scopeBlockId` changes too (a GitHub search is scoped to the block's
@@ -108,7 +128,7 @@ function keyFor(externalId: string): string {
108
128
  const importedRows = computed(() => {
109
129
  if (!source.value) return []
110
130
  const q = query.value.trim().toLowerCase()
111
- return tasks.tasks
131
+ return imported.value
112
132
  .filter((t) => t.source === source.value)
113
133
  .filter((t) => !chosen.value.has(keyFor(t.externalId)))
114
134
  .filter(
@@ -120,7 +140,7 @@ const importedRows = computed(() => {
120
140
  const searchRows = computed(() => {
121
141
  if (!source.value) return []
122
142
  const importedIds = new Set(
123
- tasks.tasks.filter((t) => t.source === source.value).map((t) => t.externalId),
143
+ imported.value.filter((t) => t.source === source.value).map((t) => t.externalId),
124
144
  )
125
145
  return results.value
126
146
  .filter((r) => !importedIds.has(r.externalId))
@@ -195,8 +215,8 @@ function pickRef(q: string) {
195
215
  }
196
216
 
197
217
  onMounted(() => {
198
- // Keep the quick-pick list current (cheap; the store dedupes).
199
- tasks.loadTasks().catch(() => {})
218
+ // Load the quick-pick list, scoped to the target container's repo.
219
+ reloadImported()
200
220
  })
201
221
  </script>
202
222
 
@@ -62,7 +62,11 @@ export function tasksApi({ send, ws }: ApiContext) {
62
62
  checkTaskSource: (workspaceId: string, source: TaskSourceKind) =>
63
63
  send(diagnoseTaskSourceContract, { pathPrefix: ws(workspaceId), pathParams: { source } }),
64
64
 
65
- listTasks: (workspaceId: string) => send(listTasksContract, { pathPrefix: ws(workspaceId) }),
65
+ // `blockId` scopes the listed issues to that block's service repo for a
66
+ // repo-backed source (GitHub Issues), exactly as search does; omitted → the
67
+ // whole workspace.
68
+ listTasks: (workspaceId: string, blockId?: string) =>
69
+ send(listTasksContract, { pathPrefix: ws(workspaceId), queryParams: { blockId } }),
66
70
 
67
71
  importTask: (workspaceId: string, source: TaskSourceKind, body: { ref: string }) =>
68
72
  send(importTaskContract, { pathPrefix: ws(workspaceId), pathParams: { source }, body }),
@@ -119,6 +119,18 @@ export const useTasksStore = defineStore('tasks', () => {
119
119
  tasks.value = await api.listTasks(workspace.requireId())
120
120
  }
121
121
 
122
+ /**
123
+ * Fetch imported issues scoped to a block's service repo (GitHub only — a
124
+ * repo-backed source narrows to that service's linked repo, exactly as `search`
125
+ * does; repo-less sources are unaffected). Returns the list WITHOUT touching the
126
+ * shared `tasks` state, so a repo-scoped view (the issue picker) can hold its own
127
+ * list without narrowing the workspace-wide one other views rely on. Omit
128
+ * `blockId` for the whole workspace.
129
+ */
130
+ async function listTasksForBlock(blockId?: string): Promise<SourceTask[]> {
131
+ return api.listTasks(workspace.requireId(), blockId)
132
+ }
133
+
122
134
  /** Import (fetch + persist) an issue by key or URL from a source. */
123
135
  async function importTask(source: TaskSourceKind, ref: string): Promise<SourceTask> {
124
136
  loading.value = true
@@ -218,6 +230,7 @@ export const useTasksStore = defineStore('tasks', () => {
218
230
  disconnect,
219
231
  setEnabled,
220
232
  loadTasks,
233
+ listTasksForBlock,
221
234
  importTask,
222
235
  search,
223
236
  linkToBlock,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.74.2",
3
+ "version": "0.74.3",
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",
@@ -34,7 +34,7 @@
34
34
  "valibot": "^1.4.2",
35
35
  "vue": "^3.5.39",
36
36
  "wretch": "^3.0.9",
37
- "@cat-factory/contracts": "0.81.1"
37
+ "@cat-factory/contracts": "0.81.2"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",