Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit185a894

Browse files
chore: add mutagen session state conversion (#117)
Relates to#63.This allows a Mutagen `Synchronization/State` message to be displayed as a single row in the table.Just like on the Windows app, extra details are shown on hover. Though all columns can be expanded by dragging the column separators, full paths will also be shown on hover.<img width="905" alt="Screenshot 2025-03-20 at 6 20 10 pm" src="https://github.com/user-attachments/assets/c3a51296-54e3-48c7-b3f6-9c915ba1b1a0" /><img width="903" alt="Screenshot 2025-03-20 at 6 21 48 pm" src="https://github.com/user-attachments/assets/2cf9cd9f-6349-42f2-abcd-b354126aafda" /><img width="906" alt="Screenshot 2025-03-20 at 6 21 40 pm" src="https://github.com/user-attachments/assets/ab6a50f5-9018-4712-be8c-9f6ad3ce44d0" /><img width="906" alt="Screenshot 2025-03-20 at 6 20 18 pm" src="https://github.com/user-attachments/assets/7d5bb734-4a40-4897-a7ac-86513501b1ce" /><img width="904" alt="image" src="https://github.com/user-attachments/assets/fdb1f2f8-7b70-4a78-9fb9-ac84df4ca5af" />
1 parentf0cf155 commit185a894

File tree

4 files changed

+317
-21
lines changed

4 files changed

+317
-21
lines changed

‎Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
2020
}.width(min:200, ideal:240)
2121
TableColumn("Workspace", value: \.agentHost)
2222
.width(min:100, ideal:120)
23-
TableColumn("Remote Path", value: \.betaPath)
23+
TableColumn("Remote Path"){Text($0.betaPath).help($0.betaPath)}
2424
.width(min:100, ideal:120)
25-
TableColumn("Status"){ $0.status.body}
25+
TableColumn("Status"){ $0.status.column.help($0.statusAndErrors)}
2626
.width(min:80, ideal:100)
27-
TableColumn("Size"){ itemin
28-
Text(item.size)
29-
}
30-
.width(min:60, ideal:80)
27+
TableColumn("Size"){Text($0.localSize.humanSizeBytes).help($0.sizeDescription)}
28+
.width(min:60, ideal:80)
3129
}
3230
.contextMenu(forSelectionType:FileSyncSession.ID.self, menu:{ _in},
3331
primaryAction:{ selectedSessionsin

‎Coder-Desktop/VPNLib/FileSync/FileSyncSession.swift

Lines changed: 254 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,126 @@ import SwiftUI
33
publicstructFileSyncSession:Identifiable{
44
publicletid:String
55
publicletalphaPath:String
6+
publicletname:String
7+
68
publicletagentHost:String
79
publicletbetaPath:String
810
publicletstatus:FileSyncStatus
9-
publicletsize:String
11+
12+
publicletlocalSize:FileSyncSessionEndpointSize
13+
publicletremoteSize:FileSyncSessionEndpointSize
14+
15+
publicleterrors:[FileSyncError]
16+
17+
init(state:Synchronization_State){
18+
id= state.session.identifier
19+
name= state.session.name
20+
21+
// If the protocol isn't what we expect for alpha or beta, show unknown
22+
alphaPath=if state.session.alpha.protocol==Url_Protocol.local, !state.session.alpha.path.isEmpty{
23+
state.session.alpha.path
24+
}else{
25+
"Unknown"
26+
}
27+
agentHost=if state.session.beta.protocol==Url_Protocol.ssh, !state.session.beta.host.isEmpty{
28+
// TOOD: We need to either:
29+
// - make this compatible with custom suffixes
30+
// - always strip the tld
31+
// - always keep the tld
32+
state.session.beta.host
33+
}else{
34+
"Unknown"
35+
}
36+
betaPath=if !state.session.beta.path.isEmpty{
37+
state.session.beta.path
38+
}else{
39+
"Unknown"
40+
}
41+
42+
varstatus:FileSyncStatus=if state.session.paused{
43+
.paused
44+
}else{
45+
convertSessionStatus(status: state.status)
46+
}
47+
if case.error= status{}else{
48+
if state.conflicts.count>0{
49+
status=.conflicts
50+
}
51+
}
52+
self.status= status
53+
54+
localSize=.init(
55+
sizeBytes: state.alphaState.totalFileSize,
56+
fileCount: state.alphaState.files,
57+
dirCount: state.alphaState.directories,
58+
symLinkCount: state.alphaState.symbolicLinks
59+
)
60+
remoteSize=.init(
61+
sizeBytes: state.betaState.totalFileSize,
62+
fileCount: state.betaState.files,
63+
dirCount: state.betaState.directories,
64+
symLinkCount: state.betaState.symbolicLinks
65+
)
66+
67+
errors=accumulateErrors(from: state)
68+
}
69+
70+
publicvarstatusAndErrors:String{
71+
varout="\(status.type)\n\n\(status.description)"
72+
errors.forEach{ out+="\n\t\($0)"}
73+
return out
74+
}
75+
76+
publicvarsizeDescription:String{
77+
varout=""
78+
out+="Local:\n\(localSize.description(linePrefix:""))\n\n"
79+
out+="Remote:\n\(remoteSize.description(linePrefix:""))"
80+
return out
81+
}
82+
}
83+
84+
publicstructFileSyncSessionEndpointSize:Equatable{
85+
publicletsizeBytes:UInt64
86+
publicletfileCount:UInt64
87+
publicletdirCount:UInt64
88+
publicletsymLinkCount:UInt64
89+
90+
publicinit(sizeBytes:UInt64, fileCount:UInt64, dirCount:UInt64, symLinkCount:UInt64){
91+
self.sizeBytes= sizeBytes
92+
self.fileCount= fileCount
93+
self.dirCount= dirCount
94+
self.symLinkCount= symLinkCount
95+
}
96+
97+
publicvarhumanSizeBytes:String{
98+
humanReadableBytes(sizeBytes)
99+
}
100+
101+
publicfunc description(linePrefix:String="")->String{
102+
varresult=""
103+
result+= linePrefix+ humanReadableBytes(sizeBytes)+"\n"
104+
letnumberFormatter=NumberFormatter()
105+
numberFormatter.numberStyle=.decimal
106+
iflet formattedFileCount= numberFormatter.string(from:NSNumber(value: fileCount)){
107+
result+="\(linePrefix)\(formattedFileCount) file\(fileCount==1?"":"s")\n"
108+
}
109+
iflet formattedDirCount= numberFormatter.string(from:NSNumber(value: dirCount)){
110+
result+="\(linePrefix)\(formattedDirCount) director\(dirCount==1?"y":"ies")"
111+
}
112+
if symLinkCount>0,let formattedSymLinkCount= numberFormatter.string(from:NSNumber(value: symLinkCount)){
113+
result+="\n\(linePrefix)\(formattedSymLinkCount) symlink\(symLinkCount==1?"":"s")"
114+
}
115+
return result
116+
}
10117
}
11118

12119
publicenumFileSyncStatus{
13120
case unknown
14-
case error(String)
121+
case error(FileSyncErrorStatus)
15122
case ok
16123
case paused
17-
caseneedsAttention(String)
18-
case working(String)
124+
caseconflicts
125+
case working(FileSyncWorkingStatus)
19126

20127
publicvarcolor:Color{
21128
switchself{
@@ -27,32 +134,164 @@ public enum FileSyncStatus {
27134
.red
28135
case.error:
29136
.red
30-
case.needsAttention:
137+
case.conflicts:
31138
.orange
32139
case.working:
33-
.white
140+
.purple
34141
}
35142
}
36143

37-
publicvardescription:String{
144+
publicvartype:String{
38145
switchself{
39146
case.unknown:
40147
"Unknown"
41-
caselet.error(msg):
42-
msg
148+
caselet.error(status):
149+
status.name
43150
case.ok:
44151
"Watching"
45152
case.paused:
46153
"Paused"
47-
caselet.needsAttention(msg):
48-
msg
49-
caselet.working(msg):
50-
msg
154+
case.conflicts:
155+
"Conflicts"
156+
caselet.working(status):
157+
status.name
158+
}
159+
}
160+
161+
publicvardescription:String{
162+
switchself{
163+
case.unknown:
164+
"Unknown status message."
165+
caselet.error(status):
166+
status.description
167+
case.ok:
168+
"The session is watching for filesystem changes."
169+
case.paused:
170+
"The session is paused."
171+
case.conflicts:
172+
"The session has conflicts that need to be resolved."
173+
caselet.working(status):
174+
status.description
175+
}
176+
}
177+
178+
publicvarcolumn:someView{
179+
Text(type).foregroundColor(color)
180+
}
181+
}
182+
183+
publicenumFileSyncWorkingStatus{
184+
case connectingAlpha
185+
case connectingBeta
186+
case scanning
187+
case reconciling
188+
case stagingAlpha
189+
case stagingBeta
190+
case transitioning
191+
case saving
192+
193+
varname:String{
194+
switchself{
195+
case.connectingAlpha:
196+
"Connecting (alpha)"
197+
case.connectingBeta:
198+
"Connecting (beta)"
199+
case.scanning:
200+
"Scanning"
201+
case.reconciling:
202+
"Reconciling"
203+
case.stagingAlpha:
204+
"Staging (alpha)"
205+
case.stagingBeta:
206+
"Staging (beta)"
207+
case.transitioning:
208+
"Transitioning"
209+
case.saving:
210+
"Saving"
211+
}
212+
}
213+
214+
vardescription:String{
215+
switchself{
216+
case.connectingAlpha:
217+
"The session is attempting to connect to the alpha endpoint."
218+
case.connectingBeta:
219+
"The session is attempting to connect to the beta endpoint."
220+
case.scanning:
221+
"The session is scanning the filesystem on each endpoint."
222+
case.reconciling:
223+
"The session is performing reconciliation."
224+
case.stagingAlpha:
225+
"The session is staging files on the alpha endpoint"
226+
case.stagingBeta:
227+
"The session is staging files on the beta endpoint"
228+
case.transitioning:
229+
"The session is performing transition operations on each endpoint."
230+
case.saving:
231+
"The session is recording synchronization history to disk."
51232
}
52233
}
234+
}
235+
236+
publicenumFileSyncErrorStatus{
237+
case disconnected
238+
case haltedOnRootEmptied
239+
case haltedOnRootDeletion
240+
case haltedOnRootTypeChange
241+
case waitingForRescan
242+
243+
varname:String{
244+
switchself{
245+
case.disconnected:
246+
"Disconnected"
247+
case.haltedOnRootEmptied:
248+
"Halted on root emptied"
249+
case.haltedOnRootDeletion:
250+
"Halted on root deletion"
251+
case.haltedOnRootTypeChange:
252+
"Halted on root type change"
253+
case.waitingForRescan:
254+
"Waiting for rescan"
255+
}
256+
}
257+
258+
vardescription:String{
259+
switchself{
260+
case.disconnected:
261+
"The session is unpaused but not currently connected or connecting to either endpoint."
262+
case.haltedOnRootEmptied:
263+
"The session is halted due to the root emptying safety check."
264+
case.haltedOnRootDeletion:
265+
"The session is halted due to the root deletion safety check."
266+
case.haltedOnRootTypeChange:
267+
"The session is halted due to the root type change safety check."
268+
case.waitingForRescan:
269+
"The session is waiting to retry scanning after an error during the previous scan."
270+
}
271+
}
272+
}
53273

54-
publicvarbody:someView{
55-
Text(description).foregroundColor(color)
274+
publicenumFileSyncEndpoint{
275+
case local
276+
case remote
277+
}
278+
279+
publicenumFileSyncProblemType{
280+
case scan
281+
case transition
282+
}
283+
284+
publicenumFileSyncError{
285+
case generic(String)
286+
case problem(FileSyncEndpoint,FileSyncProblemType, path:String, error:String)
287+
288+
vardescription:String{
289+
switchself{
290+
caselet.generic(error):
291+
error
292+
caselet.problem(endpoint, type, path, error):
293+
"\(endpoint)\(type) error at\(path):\(error)"
294+
}
56295
}
57296
}
58297

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// swiftlint:disable:next cyclomatic_complexity
2+
func convertSessionStatus(status:Synchronization_Status)->FileSyncStatus{
3+
switch status{
4+
case.disconnected:
5+
.error(.disconnected)
6+
case.haltedOnRootEmptied:
7+
.error(.haltedOnRootEmptied)
8+
case.haltedOnRootDeletion:
9+
.error(.haltedOnRootDeletion)
10+
case.haltedOnRootTypeChange:
11+
.error(.haltedOnRootTypeChange)
12+
case.waitingForRescan:
13+
.error(.waitingForRescan)
14+
case.connectingAlpha:
15+
.working(.connectingAlpha)
16+
case.connectingBeta:
17+
.working(.connectingBeta)
18+
case.scanning:
19+
.working(.scanning)
20+
case.reconciling:
21+
.working(.reconciling)
22+
case.stagingAlpha:
23+
.working(.stagingAlpha)
24+
case.stagingBeta:
25+
.working(.stagingBeta)
26+
case.transitioning:
27+
.working(.transitioning)
28+
case.saving:
29+
.working(.saving)
30+
case.watching:
31+
.ok
32+
case.UNRECOGNIZED:
33+
.unknown
34+
}
35+
}
36+
37+
func accumulateErrors(from state:Synchronization_State)->[FileSyncError]{
38+
varerrors:[FileSyncError]=[]
39+
if !state.lastError.isEmpty{
40+
errors.append(.generic(state.lastError))
41+
}
42+
forproblemin state.alphaState.scanProblems{
43+
errors.append(.problem(.local,.scan, path: problem.path, error: problem.error))
44+
}
45+
forproblemin state.alphaState.transitionProblems{
46+
errors.append(.problem(.local,.transition, path: problem.path, error: problem.error))
47+
}
48+
forproblemin state.betaState.scanProblems{
49+
errors.append(.problem(.remote,.scan, path: problem.path, error: problem.error))
50+
}
51+
forproblemin state.betaState.transitionProblems{
52+
errors.append(.problem(.remote,.transition, path: problem.path, error: problem.error))
53+
}
54+
return errors
55+
}
56+
57+
func humanReadableBytes(_ bytes:UInt64)->String{
58+
ByteCountFormatter().string(fromByteCount:Int64(bytes))
59+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp