Skip to content

Conversation

@jullianm
Copy link
Contributor

@jullianm jullianm commented Dec 3, 2025

TaskWPB-21660 [iOS] Implement versioning

Issue

This PR introduces File versioning, specifically the ability for a user to :

  • see all versions for a file
  • restore a previous version

note: video taken before merging latest changes from develop also opening and viewing a version has been recently removed from the implementation
https://github.com/user-attachments/assets/6c2defce-cb7b-414b-94b8-00c069cd2d1a

Testing

  • select version history on the files list (item ellipsis)
  • see all versions from that file
  • restore the version it should show up as the most recent version
  • edit and save a file on the Web, it should show up on the list (polling mechanism) as the current version
  • going back to the Files list, when previewing the file, the latest file should show up correctly
  • if on the Files list, and the document is edited on Web, we need to pull to refresh to see the correct file (no polling).

Checklist

  • Title contains a reference JIRA issue number like [WPB-XXX].
  • Description is filled and free of optional paragraphs.
  • Adds/updates automated tests.

UI accessibility checklist

If your PR includes UI changes, please utilize this checklist:

  • Make sure you use the API for UI elements that support large fonts.
  • All colors are taken from WireDesign.ColorTheme or constructed using WireDesign.BaseColorPalette.
  • New UI elements have Accessibility strings for VoiceOver.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 3, 2025

Test Results

0 tests   0 ✅  0s ⏱️
0 suites  0 💤
0 files    0 ❌

Results for commit 57c5809.

♻️ This comment has been updated with latest results.

)
}

func `It returns a collection of WireCellsNodeVersion`() async throws {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: I think you are missing @test prefix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, thanks

#expect(result == WireCellsNodeVersion.mock)
}

func `It fails retrieving node versions`() async throws {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise: Using the new style tests.

do {
try await localAssetRepository.downloadAsset(source: source)
cacheKey = try localAssetRepository.asset(nodeID: source.id)?.downloadState.cacheKey
} catch WireCellsLocalAssetRepositoryError.downloadAlreadyInProgress {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: This branch is not necessary as downloadAlreadyInProgress can no longer be thrown. I thought I had already deleted it, but perhaps not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, no longer here in latest commits, it's up to date.

Comment on lines 70 to 83
private func awaitDownload(id: UUID) async throws {
for await item in localAssetRepository.observeAsset(nodeID: id).values {
try Task.checkCancellation()

switch item?.downloadState {
case .downloaded:
return
case let .failed(error):
throw error
default:
break
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: This code can be deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed, updated with latest commits

@jullianm jullianm requested review from a team, David-Henner and netbe and removed request for a team and WilhelmOks December 11, 2025 14:51
@jullianm jullianm requested a review from samwyndham December 11, 2025 15:01
Comment on lines +50 to +51
WireLogger.wireCells.error("Unable to restore node version: \(error)")
throw Failure.unableToRestoreNodeVersion
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Do we have to throw and log here? What type of error is catched, consider if this can be logged publicly

Copy link
Contributor

@samwyndham samwyndham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. A few comments to address but pre-approving as I will soon be on vacation

state = .restoringVersion

// Keep the view visible for a couple of seconds to avoid a quick glitch.
try? await Task.sleep(nanoseconds: 2_000_000_000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Use try? await Task.sleep(for: .seconds(2))
question: Do you have any idea what is the cause of this glitch? 2 seconds is a long time. What does the user see during this period?


private func makeVersionItem(version: WireCellsNodeVersion) -> FileVersionItem {
let title = version.modified.map(formattedItemDate) ?? ""
let subtitle = (version.ownerName ?? "") + " · " + (version.size.map(formattedFileSize) ?? "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: The subtitle will be funny here if one of the components is missing. How about something like...

// rough code
[version.ownerName, version.size.map(formattedFileSize)].compactMap {. $0 }.joined(" · ")

) -> [Date: [WireCellsNodeVersion]] {
Dictionary(grouping: versions) { version in
let date = version.modified ?? Date.distantPast
let components = Calendar.current.dateComponents([.year, .month, .day], from: date)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: can you use Date.startOfDay(for:) here?

}
}

if canOpenVersionHistory {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: I think you might also need to check !viewModel.isInRecycleBin so that it doesnt show when in the recycle bin

@samwyndham
Copy link
Contributor

issue: Could you also put this feature behind the wireCellsCollabora feature flag

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants