diff options
| author | Christian Cleberg <[email protected]> | 2026-04-23 23:12:34 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-23 23:12:34 -0500 |
| commit | b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6 (patch) | |
| tree | 099cea2cc4324331a719ed2cad8c0815033b5471 /DomainDig/WorkflowsView.swift | |
| parent | f045a5d339a796f40a9e958436ebc6f5314bdab8 (diff) | |
| download | domain-dig-b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6.tar.gz domain-dig-b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6.tar.bz2 domain-dig-b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6.zip | |
feat(v3.6.0): add iCloud sharing for workflows and tracked domains
- implement CloudKit sharing (CKShare) for TrackedDomain and DomainWorkflow
- support read-only and editable permissions
- add Share actions and shared state indicators in UI
- handle shared record ownership and participant roles
- implement deterministic conflict resolution to prevent duplication
- ensure compatibility with existing iCloud sync layer
- maintain local-first behavior with graceful offline handling
- remove debug logging for domain availability/rdap messages
notes:
- no custom backend or accounts introduced
- sharing is Apple ecosystem only (iCloud-based)
- large history data remains local-only
Diffstat (limited to 'DomainDig/WorkflowsView.swift')
| -rw-r--r-- | DomainDig/WorkflowsView.swift | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/DomainDig/WorkflowsView.swift b/DomainDig/WorkflowsView.swift index 5025a0b..06ae96b 100644 --- a/DomainDig/WorkflowsView.swift +++ b/DomainDig/WorkflowsView.swift @@ -129,6 +129,11 @@ private struct WorkflowRowView: View { var body: some View { VStack(alignment: .leading, spacing: appDensity.metrics.rowSpacing + 1) { HStack(alignment: .firstTextBaseline, spacing: 8) { + if workflow.collaboration?.isShared == true { + Image(systemName: "person.2.fill") + .font(.caption2) + .foregroundStyle(.cyan) + } Text(workflow.name) .font(appDensity.font(.callout, design: .default, weight: .semibold)) .foregroundStyle(.primary) @@ -143,6 +148,12 @@ private struct WorkflowRowView: View { .font(appDensity.font(.caption2)) .foregroundStyle(.secondary) + if let collaboration = workflow.collaboration, collaboration.isShared { + Text("\(collaboration.ownership.title) • \(collaboration.permission.title)") + .font(appDensity.font(.caption2)) + .foregroundStyle(.secondary) + } + if let notes = workflow.notes, !notes.isEmpty { Text(notes) .font(appDensity.font(.caption)) @@ -163,6 +174,7 @@ struct WorkflowDetailView: View { @State private var showingEditor = false @State private var draftDomain = "" @State private var includeAllExports = false + @State private var shareEntity: ShareableEntity? private var workflow: DomainWorkflow? { viewModel.workflow(withID: workflowID) @@ -186,6 +198,11 @@ struct WorkflowDetailView: View { .font(appDensity.font(.caption)) .foregroundStyle(.secondary) } + if let collaboration = workflow.collaboration, collaboration.isShared { + Text("\(collaboration.ownership.title) • \(collaboration.permission.title)") + .font(appDensity.font(.caption)) + .foregroundStyle(.secondary) + } } Section("Actions") { @@ -207,6 +224,13 @@ struct WorkflowDetailView: View { } label: { Label("Edit Workflow", systemImage: "pencil") } + .disabled(!viewModel.canEdit(workflow)) + + Button { + shareEntity = .workflow(workflow.id) + } label: { + Label(workflow.collaboration?.isShared == true ? "Manage Share" : "Share Workflow", systemImage: "person.2") + } if latestSummary != nil { Toggle("Export all domains", isOn: $includeAllExports) @@ -263,6 +287,7 @@ struct WorkflowDetailView: View { viewModel.addDomains([draftDomain], to: workflow) draftDomain = "" } + .disabled(!viewModel.canEdit(workflow)) } } @@ -288,9 +313,11 @@ struct WorkflowDetailView: View { .buttonStyle(.plain) } .onDelete { offsets in + guard viewModel.canEdit(workflow) else { return } viewModel.removeWorkflowDomains(at: offsets, from: workflow) } .onMove { offsets, destination in + guard viewModel.canEdit(workflow) else { return } viewModel.moveWorkflowDomains(from: offsets, to: destination, in: workflow) } } @@ -302,6 +329,7 @@ struct WorkflowDetailView: View { .toolbar { if !workflow.domains.isEmpty { EditButton() + .disabled(!viewModel.canEdit(workflow)) } } .sheet(isPresented: $showingEditor) { @@ -310,6 +338,9 @@ struct WorkflowDetailView: View { .sheet(item: workflowSummaryBinding) { summary in WorkflowRunSummaryView(viewModel: viewModel, summary: summary) } + .sheet(item: $shareEntity) { entity in + CloudSharingSheet(entity: entity, title: workflow.name) + } } else { Text("Workflow not found") .font(appDensity.font(.callout)) |
