From 31962b43a3f010e7292c658adfe6dda581cfbae0 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 7 Jul 2020 13:23:27 -0400 Subject: [PATCH] Improve status messages --- MongoView.xcodeproj/project.pbxproj | 8 ++- MongoView/MongoController.swift | 20 ++++++- MongoView/StatusManager.swift | 54 +++++++++++++++++++ .../DatabaseViewController.swift | 6 ++- .../QueryViewController.swift | 4 ++ MongoView/Views/WindowStatusView.swift | 1 + .../Windows/DatabaseWindowController.swift | 45 +++++++++------- 7 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 MongoView/StatusManager.swift diff --git a/MongoView.xcodeproj/project.pbxproj b/MongoView.xcodeproj/project.pbxproj index a6ac141..48ec848 100644 --- a/MongoView.xcodeproj/project.pbxproj +++ b/MongoView.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ D6A7D096243541A400B46857 /* WindowStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A7D095243541A400B46857 /* WindowStatusView.swift */; }; D6A7D09A243546B500B46857 /* WindowStatusView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A7D099243546B500B46857 /* WindowStatusView.xib */; }; D6A7D0A42435885B00B46857 /* JavaScriptHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A7D0A32435885B00B46857 /* JavaScriptHighlighter.swift */; }; + D6ABB01424B4DE7600F79DA8 /* StatusManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ABB01324B4DE7600F79DA8 /* StatusManager.swift */; }; D6D13B042436C33D00493D97 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D13B032436C33D00493D97 /* main.swift */; }; D6D13B082436C34200493D97 /* JavaScriptHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A7D0A32435885B00B46857 /* JavaScriptHighlighter.swift */; }; D6D4665323CB730C00F13B1B /* MongoEvaluator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4665223CB730C00F13B1B /* MongoEvaluator.swift */; }; @@ -122,6 +123,7 @@ D6A7D095243541A400B46857 /* WindowStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowStatusView.swift; sourceTree = ""; }; D6A7D099243546B500B46857 /* WindowStatusView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WindowStatusView.xib; sourceTree = ""; }; D6A7D0A32435885B00B46857 /* JavaScriptHighlighter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavaScriptHighlighter.swift; sourceTree = ""; }; + D6ABB01324B4DE7600F79DA8 /* StatusManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusManager.swift; sourceTree = ""; }; D6D13B012436C33D00493D97 /* jstest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jstest; sourceTree = BUILT_PRODUCTS_DIR; }; D6D13B032436C33D00493D97 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; D6D4665223CB730C00F13B1B /* MongoEvaluator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MongoEvaluator.swift; sourceTree = ""; }; @@ -216,6 +218,7 @@ children = ( D63CDEBD23C837DC0012D658 /* AppDelegate.swift */, D63CDF3423C838190012D658 /* MongoController.swift */, + D6ABB01324B4DE7600F79DA8 /* StatusManager.swift */, D63CDF3323C838190012D658 /* Node.swift */, D6D4665223CB730C00F13B1B /* MongoEvaluator.swift */, D624090E243903E90020E09F /* ExtendedJSON.swift */, @@ -376,6 +379,7 @@ D6A7D096243541A400B46857 /* WindowStatusView.swift in Sources */, D626BF82243BD2EE0075117B /* EditDocumentWindowController.swift in Sources */, D6A7D0A42435885B00B46857 /* JavaScriptHighlighter.swift in Sources */, + D6ABB01424B4DE7600F79DA8 /* StatusManager.swift in Sources */, D62408C12438CF550020E09F /* JavaScriptEditorView.swift in Sources */, D63CDF4023C839010012D658 /* QueryViewController.swift in Sources */, ); @@ -526,7 +530,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 3; - DEVELOPMENT_TEAM = V4WK9KR9U2; + DEVELOPMENT_TEAM = HGYVAQA9FW; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = MongoView/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -548,7 +552,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 3; - DEVELOPMENT_TEAM = V4WK9KR9U2; + DEVELOPMENT_TEAM = HGYVAQA9FW; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = MongoView/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/MongoView/MongoController.swift b/MongoView/MongoController.swift index 1ab0bf7..11361b1 100644 --- a/MongoView/MongoController.swift +++ b/MongoView/MongoController.swift @@ -18,10 +18,17 @@ class MongoController { var client: MongoClient! - @Published var status: ConnectionStatus = .connecting + @Published var statusManager = StatusManager() + @Published private(set) var status: ConnectionStatus { + didSet { + statusManager.set(messageFor(status: status), for: .connection) + } + } init(connectionString: String) { self.connectionString = connectionString + self.status = .connecting + self.statusManager.set(messageFor(status: .connecting), for: .connection) } deinit { @@ -50,6 +57,17 @@ class MongoController { func collection(_ collection: DatabaseCollection) -> MongoCollection { return db(for: collection).collection(collection.name) } + + private func messageFor(status: ConnectionStatus) -> String { + switch status { + case .connecting: + return "Connecting..." + case .connected: + return "Connected to \(connectionString)" + case .failed: + return "Failed to connect" + } + } } diff --git a/MongoView/StatusManager.swift b/MongoView/StatusManager.swift new file mode 100644 index 0000000..9b62040 --- /dev/null +++ b/MongoView/StatusManager.swift @@ -0,0 +1,54 @@ +// +// StatusManager.swift +// MongoView +// +// Created by Shadowfacts on 7/7/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Foundation + +struct StatusManager { + private(set) var statuses = [Category: Status]() + + var mostRelevant: Status? { + for category in Category.sortedByPriority { + if let status = statuses[category] { + return status + } + } + return nil + } + + mutating func set(_ message: String, for category: Category, override: Bool = false) { + statuses[category] = Status(message: message, category: category) + + if override { + for other in Category.allCases where other < category { + remove(for: other) + } + } + } + + mutating func remove(for category: Category) { + statuses.removeValue(forKey: category) + } + + enum Category: Int, Comparable, CaseIterable { + case document + case query + case connection + + static let sortedByPriority = allCases.sorted() + + static func < (lhs: StatusManager.Category, rhs: StatusManager.Category) -> Bool { + return lhs.rawValue < rhs.rawValue + } + } + + struct Status { + let message: String + let category: Category + let timestamp = Date() + } +} diff --git a/MongoView/View Controllers/DatabaseViewController.swift b/MongoView/View Controllers/DatabaseViewController.swift index adf3fff..5bbfce0 100644 --- a/MongoView/View Controllers/DatabaseViewController.swift +++ b/MongoView/View Controllers/DatabaseViewController.swift @@ -15,9 +15,13 @@ struct DatabaseCollections { let collections: [String] } -struct DatabaseCollection { +struct DatabaseCollection: CustomStringConvertible { let database: String let name: String + + var description: String { + return "\(database).\(name)" + } } class DatabaseViewController: NSViewController { diff --git a/MongoView/View Controllers/QueryViewController.swift b/MongoView/View Controllers/QueryViewController.swift index 86c9d04..aff3821 100644 --- a/MongoView/View Controllers/QueryViewController.swift +++ b/MongoView/View Controllers/QueryViewController.swift @@ -94,6 +94,8 @@ class QueryViewController: NSViewController { if reload { outlineView.reloadData() } + + mongoController.statusManager.set("Queried \(collection)", for: .query, override: true) } func deleteRootNode(_ node: Node) { @@ -133,6 +135,7 @@ class QueryViewController: NSViewController { return } self.refresh() + self.mongoController.statusManager.set("Deleted document", for: .document) case let .failure(error): let alert = NSAlert(error: error) alert.beginSheetModal(for: self.view.window!, completionHandler: nil) @@ -171,6 +174,7 @@ class QueryViewController: NSViewController { let wc = EditDocumentWindowController(mongoController: mongoController, collection: collection, document: document) wc.documentEdited = { self.refresh() + self.mongoController.statusManager.set("Updated document", for: .document) } wc.showWindow(nil) } diff --git a/MongoView/Views/WindowStatusView.swift b/MongoView/Views/WindowStatusView.swift index 38f9f9e..179ebb6 100644 --- a/MongoView/Views/WindowStatusView.swift +++ b/MongoView/Views/WindowStatusView.swift @@ -23,6 +23,7 @@ class WindowStatusView: NSView { super.awakeFromNib() (button.cell as! NSButtonCell).imageDimsWhenDisabled = false + button.font = .monospacedDigitSystemFont(ofSize: 13, weight: .regular) } func setText(_ text: String) { diff --git a/MongoView/Windows/DatabaseWindowController.swift b/MongoView/Windows/DatabaseWindowController.swift index 104219f..d08b082 100644 --- a/MongoView/Windows/DatabaseWindowController.swift +++ b/MongoView/Windows/DatabaseWindowController.swift @@ -22,7 +22,8 @@ class DatabaseWindowController: NSWindowController { private var databaseViewController: DatabaseViewController! - private var statusDidChangeHandler: Cancellable? + private var statusChangeHandler: Cancellable? + private var connectionStatusChangeHandler: Cancellable? convenience init() { self.init(windowNibName: "DatabaseWindowController") @@ -35,15 +36,16 @@ class DatabaseWindowController: NSWindowController { if setupMongo { mongoController = MongoController(connectionString: "mongodb://localhost:27017") } - statusDidChangeHandler = mongoController.$status + + statusChangeHandler = mongoController.$statusManager .receive(on: DispatchQueue.main) - .sink { (status) in - self.updateStatusText(status) - - if status == .connected { - self.initializeUI() - } - } + .sink { self.updateStatusText(manager: $0) } + + connectionStatusChangeHandler = mongoController.$status + .receive(on: DispatchQueue.main) + .filter { $0 == .connected } + .sink { (_) in self.initializeUI() } + if setupMongo { mongoController.setup() } @@ -66,16 +68,23 @@ class DatabaseWindowController: NSWindowController { window?.title = databaseViewController?.title ?? "MongoView" } - private func updateStatusText(_ status: MongoController.ConnectionStatus) { - guard let statusView = self.statusView else { return } - switch status { - case .connecting: - statusView.setText("Connecting...") - case .failed: - statusView.setText("Failed to connect") - case .connected: - statusView.setText("Connected to \(self.mongoController.connectionString)") + private func updateStatusText(manager: StatusManager) { + guard let statusView = self.statusView, + let mostRelevant = manager.mostRelevant else { return } + + let dayComparisonResult = Calendar.current.compare(mostRelevant.timestamp, to: Date(), toGranularity: .day) + + let formatter = DateFormatter() + if dayComparisonResult == .orderedSame { + formatter.dateStyle = .none + } else { + formatter.dateStyle = .short } + formatter.timeStyle = .medium + let timestamp = formatter.string(from: mostRelevant.timestamp) + + let string = "\(mostRelevant.message) | \(timestamp)" + statusView.setText(string) } private func initializeUI() {