@cat-factory/app 0.75.2 → 0.77.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.
@@ -21,6 +21,9 @@ const memberSegments = ref<MemberSeg[]>([])
21
21
  // Frontend frame → bound service frame links (from a frontend's backend bindings).
22
22
  type FrontendSeg = { id: string; x1: number; y1: number; x2: number; y2: number }
23
23
  const frontendSegments = ref<FrontendSeg[]>([])
24
+ // Service frame → connected provider service frame links (from serviceConnections).
25
+ type ConnectionSeg = { id: string; x1: number; y1: number; x2: number; y2: number }
26
+ const connectionSegments = ref<ConnectionSeg[]>([])
24
27
 
25
28
  // task → its dependencies, both ends being tasks
26
29
  const taskDeps = computed(() => {
@@ -66,6 +69,24 @@ const frontendLinks = computed(() => {
66
69
  return out
67
70
  })
68
71
 
72
+ // consumer service frame → each provider service it connects to (a serviceConnections
73
+ // entry, stored on the consumer end). Deduped; a target deleted out of band draws nothing.
74
+ const connectionLinks = computed(() => {
75
+ const out: { id: string; source: string; target: string }[] = []
76
+ for (const f of board.frames) {
77
+ if (f.type !== 'service') continue
78
+ const seen = new Set<string>()
79
+ for (const connection of f.serviceConnections ?? []) {
80
+ const providerId = connection.serviceBlockId
81
+ if (seen.has(providerId)) continue
82
+ seen.add(providerId)
83
+ if (board.getBlock(providerId))
84
+ out.push({ id: `${f.id}__conn__${providerId}`, source: f.id, target: providerId })
85
+ }
86
+ }
87
+ return out
88
+ })
89
+
69
90
  /** Resolve a task's anchor: walk up task → module → service to the first card
70
91
  * that's actually rendered (a container may be collapsed). */
71
92
  function anchorEl(taskId: string): HTMLElement | null {
@@ -152,6 +173,23 @@ function recompute() {
152
173
  fes.push({ id: link.id, x1: start.x, y1: start.y, x2: end.x, y2: end.y })
153
174
  }
154
175
  frontendSegments.value = fes
176
+
177
+ const conns: ConnectionSeg[] = []
178
+ for (const link of connectionLinks.value) {
179
+ const a = anchorEl(link.source)
180
+ const b = anchorEl(link.target)
181
+ if (!a || !b || a === b) continue
182
+ const ra = a.getBoundingClientRect()
183
+ const rb = b.getBoundingClientRect()
184
+ const ax = ra.left + ra.width / 2 - origin.left
185
+ const ay = ra.top + ra.height / 2 - origin.top
186
+ const bx = rb.left + rb.width / 2 - origin.left
187
+ const by = rb.top + rb.height / 2 - origin.top
188
+ const start = border(ax, ay, ra.width / 2, ra.height / 2, bx, by)
189
+ const end = border(bx, by, rb.width / 2, rb.height / 2, ax, ay)
190
+ conns.push({ id: link.id, x1: start.x, y1: start.y, x2: end.x, y2: end.y })
191
+ }
192
+ connectionSegments.value = conns
155
193
  }
156
194
 
157
195
  const { pause, resume } = useRafFn(recompute, { immediate: false })
@@ -195,8 +233,34 @@ onBeforeUnmount(pause)
195
233
  >
196
234
  <path d="M0,0 L10,5 L0,10 z" fill="#22d3ee" />
197
235
  </marker>
236
+ <marker
237
+ id="service-connection-arrow"
238
+ viewBox="0 0 10 10"
239
+ refX="8"
240
+ refY="5"
241
+ markerWidth="6"
242
+ markerHeight="6"
243
+ orient="auto-start-reverse"
244
+ >
245
+ <path d="M0,0 L10,5 L0,10 z" fill="#34d399" />
246
+ </marker>
198
247
  </defs>
199
248
 
249
+ <!-- consumer service → provider service connection links (emerald, arrow toward the provider) -->
250
+ <line
251
+ v-for="s in connectionSegments"
252
+ :key="s.id"
253
+ :x1="s.x1"
254
+ :y1="s.y1"
255
+ :x2="s.x2"
256
+ :y2="s.y2"
257
+ stroke="#34d399"
258
+ :stroke-width="1.5"
259
+ stroke-dasharray="3 4"
260
+ :stroke-opacity="0.55"
261
+ marker-end="url(#service-connection-arrow)"
262
+ />
263
+
200
264
  <!-- frontend frame → bound service frame links (cyan, arrow toward the service under test) -->
201
265
  <line
202
266
  v-for="s in frontendSegments"
@@ -9,6 +9,7 @@ import ServiceTestConfig from '~/components/panels/inspector/ServiceTestConfig.v
9
9
  import ServiceFragments from '~/components/panels/inspector/ServiceFragments.vue'
10
10
  import ServiceReleaseHealthConfig from '~/components/panels/inspector/ServiceReleaseHealthConfig.vue'
11
11
  import FrontendConfig from '~/components/panels/inspector/FrontendConfig.vue'
12
+ import ServiceConnections from '~/components/panels/inspector/ServiceConnections.vue'
12
13
  import ContainerSummary from '~/components/panels/inspector/ContainerSummary.vue'
13
14
  import TaskDependencies from '~/components/panels/inspector/TaskDependencies.vue'
14
15
  import TaskStructure from '~/components/panels/inspector/TaskStructure.vue'
@@ -465,6 +466,9 @@ const showOriginalDescription = ref(false)
465
466
  <!-- frontend (frame): build/serve/mock config + backend bindings (board links) -->
466
467
  <FrontendConfig v-if="isFrame && block.type === 'frontend'" :block="block" />
467
468
 
469
+ <!-- service (frame): directed connections to the other services it uses (board links) -->
470
+ <ServiceConnections v-if="isFrame && block.type === 'service'" :block="block" />
471
+
468
472
  <!-- service (frame): test infra + provisioning configuration -->
469
473
  <ServiceTestConfig v-if="isFrame" :block="block" />
470
474