diff --git a/.swiftlint.yml b/.swiftlint.yml index 31d6368..a9b0343 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -55,4 +55,5 @@ identifier_name: - env - telemetry_api_server_version -reporter: "github-actions-logging" # reporter type (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging) +#reporter: "github-actions-logging" # reporter type (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging) +reporter: "xcode" \ No newline at end of file diff --git a/APIClient/APIClient.swift b/APIClient/APIClient.swift index 410b5d8..dc2e785 100644 --- a/APIClient/APIClient.swift +++ b/APIClient/APIClient.swift @@ -414,6 +414,17 @@ extension APIClient { runTask(with: request, completion: completion) } + @available(macOS 12.0, *) + func post(data: Input, url: URL) async throws -> Output { + #if DEBUG + print("๐ŸŒ POST", url) + #endif + + var request = authenticatedURLRequest(for: url, httpMethod: "POST") + request.httpBody = try? JSONEncoder.telemetryEncoder.encode(data) + return try await runAsyncTask(with: request) + } + func post(_ data: Input, to url: URL, defaultValue _: Output? = nil, completion: @escaping (Result) -> Void) { #if DEBUG print("๐ŸŒ POST", url) diff --git a/APIClient/DTOs/InsightInfo.swift b/APIClient/DTOs/InsightInfo.swift index 5066a46..be5d5d0 100644 --- a/APIClient/DTOs/InsightInfo.swift +++ b/APIClient/DTOs/InsightInfo.swift @@ -27,12 +27,6 @@ public struct InsightInfo: Codable, Hashable, Identifiable { /// What kind of insight is this? public var type: InsightType - /// If set, display the chart with this accent color, otherwise fall back to default color - public var accentColor: String? - - /// If set, use the custom query in this property instead of constructing a query out of the options below - public var customQuery: CustomQuery? - /// Which signal types are we interested in? If nil, do not filter by signal type public var signalType: String? @@ -57,15 +51,17 @@ public struct InsightInfo: Codable, Hashable, Identifiable { /// The date this query was last run public var lastRunAt: Date? + /// The query to calculate this insight + public var query: CustomQuery? + public init( id: UUID, groupID: UUID, order: Double?, title: String, type: InsightType, - accentColor: String? = nil, + accentColor _: String? = nil, widgetable _: Bool? = false, - customQuery: CustomQuery? = nil, signalType: String?, uniqueUser: Bool, breakdownKey: String?, @@ -73,15 +69,14 @@ public struct InsightInfo: Codable, Hashable, Identifiable { displayMode: InsightDisplayMode, isExpanded: Bool, lastRunTime: TimeInterval?, - lastRunAt: Date? + lastRunAt: Date?, + query: CustomQuery? ) { self.id = id self.groupID = groupID self.order = order self.title = title self.type = type - self.accentColor = accentColor - self.customQuery = customQuery self.signalType = signalType self.uniqueUser = uniqueUser self.breakdownKey = breakdownKey @@ -90,5 +85,6 @@ public struct InsightInfo: Codable, Hashable, Identifiable { self.isExpanded = isExpanded self.lastRunTime = lastRunTime self.lastRunAt = lastRunAt + self.query = query } } diff --git a/Cluster/Chart/BarChart/BarCharTopN.swift b/Cluster/Chart/BarChart/BarCharTopN.swift new file mode 100644 index 0000000..45d56f6 --- /dev/null +++ b/Cluster/Chart/BarChart/BarCharTopN.swift @@ -0,0 +1,25 @@ +// +// BarCharTopN.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import Charts +import DataTransferObjects + +struct BarChartTopN: View { + let result: TopNQueryResult + + var body: some View { + Chart { + //ForEach(result.rows) { row in + // BarMark( + // x: .value("Date", 4), + // y: .value("Total Count", 5) + // ) + //} + } + } +} diff --git a/Cluster/Chart/BarChart/BarChartGroupBy.swift b/Cluster/Chart/BarChart/BarChartGroupBy.swift new file mode 100644 index 0000000..945d079 --- /dev/null +++ b/Cluster/Chart/BarChart/BarChartGroupBy.swift @@ -0,0 +1,25 @@ +// +// BarChartGroupBy.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import Charts +import DataTransferObjects + +struct BarChartGroupBy: View { + let result: GroupByQueryResult + + var body: some View { + Chart { + /*ForEach(result.rows) { row in + BarMark( + x: .value("Date", 5), + y: .value("Total Count", 5) + ) + }*/ + } + } +} diff --git a/Cluster/Chart/BarChart/BarChartTimeSeries.swift b/Cluster/Chart/BarChart/BarChartTimeSeries.swift new file mode 100644 index 0000000..9e4b625 --- /dev/null +++ b/Cluster/Chart/BarChart/BarChartTimeSeries.swift @@ -0,0 +1,25 @@ +// +// BarChartTimeSeries.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import Charts +import DataTransferObjects + +struct BarChartTimeSeries: View { + let result: TimeSeriesQueryResult + + var body: some View { + Chart { + ForEach(result.rows, id: \.timestamp) { row in + BarMark( + x: .value("Date", row.timestamp), + y: .value("Total Count", row.result["count"]?.value ?? 0) + ) + } + } + } +} diff --git a/Cluster/Chart/BarChart/ClusterBarChart.swift b/Cluster/Chart/BarChart/ClusterBarChart.swift new file mode 100644 index 0000000..9cf3d9f --- /dev/null +++ b/Cluster/Chart/BarChart/ClusterBarChart.swift @@ -0,0 +1,38 @@ +// +// ClusterBarChart.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// +import SwiftUI +import DataTransferObjects + +struct ClusterBarChart: View { + let query: CustomQuery + let result: QueryResult + + var body: some View { + switch query.queryType { + case .timeseries: + if case let .timeSeries(result) = result { + BarChartTimeSeries(result: result) + } else { + Text("Mismatch in query type and result type 1") + } + /*case .groupBy: + if case let .groupBy(result) = result { + BarChartGroupBy(result: result) + } else { + Text("Mismatch in query type and result type 2") + }*/ + case .topN: + if case let .topN(result) = result { + BarChartTopN(result: result) + } else { + Text("Mismatch in query type and result type 2") + } + default: + Text("\(query.queryType.rawValue) bar charts are not supported.") + } + } +} diff --git a/Cluster/Chart/ClusterChart.swift b/Cluster/Chart/ClusterChart.swift new file mode 100644 index 0000000..9d7fafa --- /dev/null +++ b/Cluster/Chart/ClusterChart.swift @@ -0,0 +1,28 @@ +// +// ClusterChart.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import DataTransferObjects + +/// Cluster/Chart โ€“ย given a query and a result, displays the result +struct ClusterChart: View { + + let query: CustomQuery + let result: QueryResult + let type: InsightDisplayMode + + var body: some View { + switch type { + case .barChart: + ClusterBarChart(query: query, result: result) + case .lineChart: + ClusterLineChart(query: query, result: result) + default: + Text("Not supported") + } + } +} diff --git a/Cluster/Chart/LineChart/ClusterLineChart.swift b/Cluster/Chart/LineChart/ClusterLineChart.swift new file mode 100644 index 0000000..7e33ba8 --- /dev/null +++ b/Cluster/Chart/LineChart/ClusterLineChart.swift @@ -0,0 +1,27 @@ +// +// ClusterLineChart.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import DataTransferObjects + +struct ClusterLineChart: View { + let query: CustomQuery + let result: QueryResult + + var body: some View { + switch query.queryType { + case .timeseries: + if case let .timeSeries(result) = result { + LineChartTimeSeries(result: result) + } else { + Text("Mismatch in query type and result type") + } + default: + Text("\(query.queryType.rawValue) bar charts are not supported.") + } + } +} diff --git a/Cluster/Chart/LineChart/LineChartTimeSeries.swift b/Cluster/Chart/LineChart/LineChartTimeSeries.swift new file mode 100644 index 0000000..414dc6c --- /dev/null +++ b/Cluster/Chart/LineChart/LineChartTimeSeries.swift @@ -0,0 +1,33 @@ +// +// LineChartTimeSeries.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import Charts +import DataTransferObjects + +struct LineChartTimeSeries: View { + let result: TimeSeriesQueryResult + + var body: some View { + Chart { + ForEach(result.rows, id: \.timestamp) { row in + LineMark( + x: .value("Date", row.timestamp), + y: .value("Total Count", row.result["count"]?.value ?? 0) + ) + } + .interpolationMethod(.cardinal) + + ForEach(result.rows, id: \.timestamp) { row in + AreaMark(x: .value("Date", row.timestamp), + y: .value("Total Count", row.result["count"]?.value ?? 0)) + } + .interpolationMethod(.cardinal) + .foregroundStyle(LinearGradient(colors: [Color.telemetryOrange.opacity(0.25), Color.telemetryOrange.opacity(0.0)], startPoint: .top, endPoint: .bottom)) + } + } +} diff --git a/Cluster/ClusterInstrument.swift b/Cluster/ClusterInstrument.swift new file mode 100644 index 0000000..53de4ea --- /dev/null +++ b/Cluster/ClusterInstrument.swift @@ -0,0 +1,34 @@ +// +// ClusterInstrument.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import SwiftUI +import DataTransferObjects + +struct ClusterInstrument: View { + @EnvironmentObject var api: APIClient + + let query: CustomQuery + let title: String + let type: InsightDisplayMode + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text(title) + .font(.headline) + .fontWeight(.medium) + .foregroundStyle(Color.Zinc600) + .padding(.top) + .padding(.horizontal) + QueryRunner(query: query, type: type) + } + .compositingGroup() + .background(.background) + .shadow(color: .gray.opacity(0.15), radius: 5, x: 0, y: 2) + .border(Color.Zinc200, width: 1.0) + .padding(.vertical, 5) + } +} diff --git a/Cluster/QueryRunner.swift b/Cluster/QueryRunner.swift new file mode 100644 index 0000000..9fcbbd2 --- /dev/null +++ b/Cluster/QueryRunner.swift @@ -0,0 +1,165 @@ +// +// QueryRunner.swift +// Telemetry Viewer (iOS) +// +// Created by Lukas on 23.05.24. +// + +import DataTransferObjects +import SwiftUI + +struct QueryRunner: View { + @EnvironmentObject var api: APIClient + @EnvironmentObject var queryService: QueryService + + let query: CustomQuery + let type: InsightDisplayMode + + @State var queryResultWrapper: QueryResultWrapper? + @State var isLoading: Bool = false + + var body: some View { + VStack(spacing: 10){ + if let queryResult = queryResultWrapper?.result { + ClusterChart(query: query, result: queryResult, type: type) + .padding(.horizontal) + } + + HStack(spacing: 3){ + Spacer() + if let queryResultWrapper = queryResultWrapper { + Text("Updated") + Text(queryResultWrapper.calculationFinishedAt, style: .relative) + Text("ago") + + } else { + Text("Calculating...") + } + } + .font(.footnote) + .foregroundStyle(Color.Zinc400) + .padding(8) + .background(Color.Zinc50) + } + .onAppear { + Task { + do { + try await getQueryResult() + } catch { + print(error) + } + } + } + } + + private func getQueryResult() async throws { + isLoading = true + defer { + isLoading = false + } + + let taskID = try await beginAsyncCalcV2() + + try await getLastSuccessfulValue(taskID) + + try await waitUntilTaskStatusIsSuccessful(taskID) + + try await getLastSuccessfulValue(taskID) + } +} + +extension QueryRunner { + + private func beginAsyncCalcV2() async throws -> String { + // create a query task + let queryBeginURL = api.urlForPath(apiVersion: .v3, "query", "calculate-async") + + var queryCopy = query + + if queryCopy.intervals == nil && queryCopy.relativeIntervals == nil{ + switch queryService.timeWindowBeginning { + case .absolute: + queryCopy.intervals = [.init(beginningDate: queryService.timeWindowBeginningDate, endDate: queryService.timeWindowEndDate)] + default: + queryCopy.relativeIntervals = [RelativeTimeInterval(beginningDate: queryService.timeWindowBeginning.toRelativeDate(), endDate: queryService.timeWindowEnd.toRelativeDate())] + } + } + + let response: [String: String] = try await api.post(data: queryCopy, url: queryBeginURL) + guard let taskID = response["queryTaskID"] else { + throw TransferError.decodeFailed + } + + return taskID + } + + private func getLastSuccessfulValue(_ taskID: String) async throws { + // pick up the finished result + let lastSuccessfulValueURL = api.urlForPath(apiVersion: .v3, "task", taskID, "lastSuccessfulValue") + queryResultWrapper = try await api.get(url: lastSuccessfulValueURL) + } + + private func waitUntilTaskStatusIsSuccessful(_ taskID: String) async throws { + // wait for the task to finish caluclating + var taskStatus: QueryTaskStatus = .running + while taskStatus != .successful { + let taskStatusURL = api.urlForPath(apiVersion: .v3, "task", taskID, "status") + + let queryTaskStatus: QueryTaskStatusStruct = try await api.get(url: taskStatusURL) + + taskStatus = queryTaskStatus.status + + try await Task.sleep(nanoseconds: 1_000_000_000) + } + + if taskStatus == .error { + throw TransferError.serverError(message: "The server returned an error") + } + } +} + +extension RelativeDateDescription { + func toRelativeDate() -> RelativeDate{ + switch self { + case .end(let of): + switch of { + case .current(let calendarComponent): + RelativeDate(.end, of: RelativeDate.RelativeDateComponent.from(calenderComponent: calendarComponent), adding: 0) + case .previous(let calendarComponent): + RelativeDate(.end, of: RelativeDate.RelativeDateComponent.from(calenderComponent: calendarComponent), adding: -1) + } + case .beginning(let of): + switch of { + case .current(let calendarComponent): + RelativeDate(.beginning, of: RelativeDate.RelativeDateComponent.from(calenderComponent: calendarComponent), adding: 0) + case .previous(let calendarComponent): + RelativeDate(.beginning, of: RelativeDate.RelativeDateComponent.from(calenderComponent: calendarComponent), adding: -1) + } + case .goBack(let days): + RelativeDate(.beginning, of: .day, adding: -days) + case .absolute: + RelativeDate(.beginning, of: .day, adding: -30) + } + } +} + +extension RelativeDate.RelativeDateComponent { + static func from (calenderComponent: Calendar.Component) -> Self { + switch calenderComponent { + case .hour: + .hour + case .day: + .day + case .weekOfYear: + .week + case .month: + .month + case .quarter: + .quarter + case .year: + .year + default: + .day + } + } +} diff --git a/Services/QueryService.swift b/Services/QueryService.swift index b7264cc..e842e39 100644 --- a/Services/QueryService.swift +++ b/Services/QueryService.swift @@ -79,15 +79,13 @@ class QueryService: ObservableObject { struct ProduceQueryBody: Codable { /// Is Test Mode enabled? (nil means false) public var testMode: Bool? - /// Which time intervals are we looking at? public var relativeInterval: RelativeTimeInterval? public var interval: QueryTimeInterval? } - + let produceQueryBody = ProduceQueryBody(testMode: isTestingMode, interval: .init(beginningDate: timeWindowBeginningDate, endDate: timeWindowEndDate)) - - + api.post(produceQueryBody, to: url) { (result: Result) in switch result { case .success(let query): @@ -103,13 +101,13 @@ class QueryService: ObservableObject { func createTask(forQuery query: CustomQuery) async throws -> [String: String] { return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<[String: String], Error>) in - + // If the query has no specified interval, give it the default interval var query = query if query.relativeIntervals == nil && query.intervals == nil { query.intervals = [.init(beginningDate: timeWindowBeginningDate, endDate: timeWindowEndDate)] } - + let url = api.urlForPath(apiVersion: .v3, "query", "calculate-async") api.post(query, to: url) { (result: Result<[String: String], TransferError>) in switch result { diff --git a/Shared/Insight and Groups/InsightCard.swift b/Shared/Insight and Groups/InsightCard.swift deleted file mode 100644 index 7220c99..0000000 --- a/Shared/Insight and Groups/InsightCard.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// InsightCard.swift -// InsightCard -// -// Created by Daniel Jilg on 18.08.21. -// - -import DataTransferObjects -import SwiftUI - -import TelemetryClient - -struct InsightCard: View { - @EnvironmentObject var insightService: InsightService - @EnvironmentObject var queryService: QueryService - - @Binding var selectedInsightID: DTOv2.Insight.ID? - @Binding var sidebarVisible: Bool - - @State var insightWrap: InsightResultWrap? - @State var loadingState: LoadingState = .idle - - @State var customQuery: CustomQuery? - - private var isSelected: Bool { - selectedInsightID == insightID - } - - let insightID: DTOv2.Insight.ID - let isSelectable: Bool - - // make this a timer that retrieves insight occasionally? - private let refreshTimer = Timer.publish( - every: 60, // seconds - on: .main, - in: .common - ).autoconnect() - - var body: some View { - Button { - if isSelectable { - selectedInsightID = insightID - - withAnimation { - sidebarVisible = true - } - } - } label: { - cardContent - } - .frame(idealHeight: 200) - .buttonStyle(CardButtonStyle(isSelected: selectedInsightID == insightID, customAccentColor: Color(hex: insightService.insight(withID: insightID)?.accentColor ?? ""))) - } - - var cardContent: some View { - VStack(alignment: .leading) { - HStack { - TinyLoadingStateIndicator(loadingState: insightService.loadingState[insightID] ?? .idle, title: insightService.insight(withID: insightID)?.title) - .font(.footnote) - .foregroundColor(isSelected ? .cardBackground : .grayColor) - .padding(.leading) - - Spacer() - - UnobtrusiveIconOnlyLoadingStateIndicator(loadingState: loadingState) - .padding(.trailing) - } - - Group { - // This shows an error Sondrine if no internet connection - if let displaymode = insightService.insightDictionary[insightID]?.displayMode, let query = customQuery { - QueryView(viewModel: QueryViewModel(queryService: queryService, customQuery: query, displayMode: displaymode, isSelected: isSelected)) - } else { - SondrineLoadingStateIndicator(loadingState: loadingState) - } - } - - .onAppear(perform: sendTelemetry) - .onChange(of: queryService.isTestingMode) { _ in - customQuery = nil - Task { - await retrieveResults() - } - } - .onChange(of: queryService.timeWindowBeginning) { _ in - customQuery = nil - Task { - await retrieveResults() - } - } - .onChange(of: queryService.timeWindowEnd) { _ in - customQuery = nil - Task { - await retrieveResults() - } - } - .onChange(of: insightService.insightDictionary[insightID]) { _ in - customQuery = nil - Task { - await retrieveResults() - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - } - .padding(.top) - .task { - await insightService.retrieveInsight(with: insightID) - await retrieveResults() - } - } - - func sendTelemetry() { - if let displayMode = insightService.insightDictionary[insightID]?.displayMode { - TelemetryManager.send("InsightShown", with: ["insightDisplayMode": displayMode.rawValue]) - } - } - - @MainActor - func retrieveResults() async { - guard loadingState != .loading else { return } // not sufficient - loadingState = .loading - - do { - let query = try await queryService.getInsightQuery(ofInsightWithID: insightID) - - customQuery = query - - loadingState = .finished(Date()) - - } catch { - print(error.localizedDescription) - - if let transferError = error as? TransferError { - loadingState = .error(transferError.localizedDescription, Date()) - } else { - loadingState = .error(error.localizedDescription, Date()) - } - } - } -} diff --git a/Shared/Insight and Groups/QueryView.swift b/Shared/Insight and Groups/QueryView.swift index 4d0aa4b..d6e7102 100644 --- a/Shared/Insight and Groups/QueryView.swift +++ b/Shared/Insight and Groups/QueryView.swift @@ -7,6 +7,7 @@ import DataTransferObjects import SwiftUI +import Charts // @State var customQuery: CustomQuery @@ -262,6 +263,85 @@ struct QueryView: View { } } +struct QueryViewV2: View { + @StateObject var viewModel: QueryViewModel + + //let displayMode: String + + var body: some View { + VStack { + if let queryResult = viewModel.queryResult?.result, let chartDataSet = viewModel.chartDataSet{ + switch viewModel.displayMode { + case .raw: + RawChartView(chartDataSet: chartDataSet, isSelected: viewModel.isSelected) + case .pieChart: + DonutChartView(chartDataset: chartDataSet, isSelected: viewModel.isSelected) + .padding(.bottom) + .padding(.horizontal) + case .lineChart: + ClusterLineChart(query: viewModel.customQuery, result: queryResult) + case .barChart: + ClusterBarChart(query: viewModel.customQuery, result: queryResult) + default: + Text("\(viewModel.displayMode.rawValue.capitalized) is not supported in this version.") + .font(.footnote) + .foregroundColor(.grayColor) + .padding(.vertical) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + } + } else { + SondrineLoadingStateIndicator(loadingState: viewModel.loadingState) + .onTapGesture { + Task { + await viewModel.retrieveResults() + } + } + } + + /*if let chartDataSet = viewModel.chartDataSet { + switch viewModel.displayMode { + case .raw: + RawChartView(chartDataSet: chartDataSet, isSelected: viewModel.isSelected) + case .pieChart: + DonutChartView(chartDataset: chartDataSet, isSelected: viewModel.isSelected) + .padding(.bottom) + .padding(.horizontal) + case .lineChart: + LineChart(chartDataSet: chartDataSet, isSelected: viewModel.isSelected) + case .barChart: + BarChartView(chartDataSet: chartDataSet, isSelected: viewModel.isSelected) + default: + Text("\(viewModel.displayMode.rawValue.capitalized) is not supported in this version.") + .font(.footnote) + .foregroundColor(.grayColor) + .padding(.vertical) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + } + } else { + SondrineLoadingStateIndicator(loadingState: viewModel.loadingState) + .onTapGesture { + Task { + await viewModel.retrieveResults() + } + } + }*/ + } + .task { + await viewModel.retrieveResults() + } + .onReceive(viewModel.runningTimer) { _ in + Task { + await viewModel.checkIfStillRunning() + } + } + .onReceive(viewModel.successTimer) { _ in + Task { + await viewModel.checkStatus() + } + } + } +} + // struct QueryView_Previews: PreviewProvider { // static var previews: some View { // QueryView() diff --git a/Shared/Supporting Files/Assets.xcassets/TLightGray.colorset/Contents.json b/Shared/Supporting Files/Assets.xcassets/Zinc100.colorset/Contents.json similarity index 84% rename from Shared/Supporting Files/Assets.xcassets/TLightGray.colorset/Contents.json rename to Shared/Supporting Files/Assets.xcassets/Zinc100.colorset/Contents.json index b349cd1..f762bf1 100644 --- a/Shared/Supporting Files/Assets.xcassets/TLightGray.colorset/Contents.json +++ b/Shared/Supporting Files/Assets.xcassets/Zinc100.colorset/Contents.json @@ -7,7 +7,7 @@ "alpha" : "1.000", "blue" : "0xF5", "green" : "0xF3", - "red" : "0xF0" + "red" : "0xF3" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0x30", - "green" : "0x29", - "red" : "0x25" + "blue" : "0x1B", + "green" : "0x18", + "red" : "0x18" } }, "idiom" : "universal" diff --git a/Shared/Supporting Files/Assets.xcassets/TDarkGray.colorset/Contents.json b/Shared/Supporting Files/Assets.xcassets/Zinc200.colorset/Contents.json similarity index 76% rename from Shared/Supporting Files/Assets.xcassets/TDarkGray.colorset/Contents.json rename to Shared/Supporting Files/Assets.xcassets/Zinc200.colorset/Contents.json index cfebf2d..720f03e 100644 --- a/Shared/Supporting Files/Assets.xcassets/TDarkGray.colorset/Contents.json +++ b/Shared/Supporting Files/Assets.xcassets/Zinc200.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0x30", - "green" : "0x29", - "red" : "0x25" + "blue" : "0xE7", + "green" : "0xE3", + "red" : "0xE3" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0x78", - "green" : "0x67", - "red" : "0x5D" + "blue" : "0x2A", + "green" : "0x27", + "red" : "0x27" } }, "idiom" : "universal" diff --git a/Shared/Supporting Files/Assets.xcassets/Zinc400.colorset/Contents.json b/Shared/Supporting Files/Assets.xcassets/Zinc400.colorset/Contents.json new file mode 100644 index 0000000..398be1a --- /dev/null +++ b/Shared/Supporting Files/Assets.xcassets/Zinc400.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xAA", + "green" : "0xA1", + "red" : "0xA1" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5B", + "green" : "0x51", + "red" : "0x51" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Shared/Supporting Files/Assets.xcassets/Zinc50.colorset/Contents.json b/Shared/Supporting Files/Assets.xcassets/Zinc50.colorset/Contents.json new file mode 100644 index 0000000..04b2a75 --- /dev/null +++ b/Shared/Supporting Files/Assets.xcassets/Zinc50.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF5", + "green" : "0xF3", + "red" : "0xF3" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x0B", + "green" : "0x09", + "red" : "0x09" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Shared/Supporting Files/Assets.xcassets/Zinc600.colorset/Contents.json b/Shared/Supporting Files/Assets.xcassets/Zinc600.colorset/Contents.json new file mode 100644 index 0000000..04f767b --- /dev/null +++ b/Shared/Supporting Files/Assets.xcassets/Zinc600.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5B", + "green" : "0x51", + "red" : "0x51" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xAA", + "green" : "0xA1", + "red" : "0xA1" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Telemetry Viewer.xcodeproj/project.pbxproj b/Telemetry Viewer.xcodeproj/project.pbxproj index 844a12a..3eaa9f7 100644 --- a/Telemetry Viewer.xcodeproj/project.pbxproj +++ b/Telemetry Viewer.xcodeproj/project.pbxproj @@ -87,8 +87,6 @@ 2BA0397E26AAE19B004A9E48 /* MacOs12SignalTypesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA0397D26AAE19B004A9E48 /* MacOs12SignalTypesView.swift */; }; 2BA5D50226CD05CC008FBF8F /* InsightGroupsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA5D50026CD05CC008FBF8F /* InsightGroupsView.swift */; }; 2BA5D50526CD0E5B008FBF8F /* GroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA5D50326CD0E5B008FBF8F /* GroupView.swift */; }; - 2BA5D50726CD1403008FBF8F /* InsightCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA5D50626CD1403008FBF8F /* InsightCard.swift */; }; - 2BA5D50826CD1403008FBF8F /* InsightCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA5D50626CD1403008FBF8F /* InsightCard.swift */; }; 2BA5D50A26CDAA58008FBF8F /* InsightResultService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA5D50926CDAA58008FBF8F /* InsightResultService.swift */; }; 2BA5D50B26CDAA58008FBF8F /* InsightResultService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA5D50926CDAA58008FBF8F /* InsightResultService.swift */; }; 2BBFC9FB267D05E40013DC74 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BBFC9DA267D05E30013DC74 /* Helpers.swift */; }; @@ -165,6 +163,15 @@ 80427FF62BFE2AF4007E89CC /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80427FDF2BFE2AF4007E89CC /* UserInfo.swift */; }; 80427FF72BFE2AF4007E89CC /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80427FDF2BFE2AF4007E89CC /* UserInfo.swift */; }; 80427FF82BFE2AF4007E89CC /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80427FDF2BFE2AF4007E89CC /* UserInfo.swift */; }; + 80AD3E942BFF2A7300BBD7EB /* QueryRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3E932BFF2A7300BBD7EB /* QueryRunner.swift */; }; + 80AD3E972BFF2AA200BBD7EB /* ClusterChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3E962BFF2AA200BBD7EB /* ClusterChart.swift */; }; + 80AD3E992BFF2B0A00BBD7EB /* ClusterInstrument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3E982BFF2B0A00BBD7EB /* ClusterInstrument.swift */; }; + 80AD3E9E2BFF305100BBD7EB /* ClusterBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3E9D2BFF305100BBD7EB /* ClusterBarChart.swift */; }; + 80AD3EA02BFF306F00BBD7EB /* BarChartTimeSeries.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3E9F2BFF306F00BBD7EB /* BarChartTimeSeries.swift */; }; + 80AD3EA32BFF33D900BBD7EB /* ClusterLineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3EA22BFF33D900BBD7EB /* ClusterLineChart.swift */; }; + 80AD3EA52BFF33FF00BBD7EB /* LineChartTimeSeries.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3EA42BFF33FF00BBD7EB /* LineChartTimeSeries.swift */; }; + 80AD3EAC2BFF6BE000BBD7EB /* BarChartGroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3EAB2BFF6BE000BBD7EB /* BarChartGroupBy.swift */; }; + 80AD3EAE2BFF6D2200BBD7EB /* BarCharTopN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AD3EAD2BFF6D2200BBD7EB /* BarCharTopN.swift */; }; C5173B41283D52E40018CE9F /* InsightsGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5173B40283D52E40018CE9F /* InsightsGrid.swift */; }; C51CB73627565EB5005A3FB9 /* TelemetryDeckWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = C5A8D869270C5D7B0032560A /* TelemetryDeckWidget.intentdefinition */; }; C51CB73C27565F76005A3FB9 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C5A8D8AD270C821A0032560A /* Intents.framework */; platformFilter = maccatalyst; }; @@ -470,7 +477,6 @@ 2BA0397D26AAE19B004A9E48 /* MacOs12SignalTypesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacOs12SignalTypesView.swift; sourceTree = ""; }; 2BA5D50026CD05CC008FBF8F /* InsightGroupsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightGroupsView.swift; sourceTree = ""; }; 2BA5D50326CD0E5B008FBF8F /* GroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupView.swift; sourceTree = ""; }; - 2BA5D50626CD1403008FBF8F /* InsightCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightCard.swift; sourceTree = ""; }; 2BA5D50926CDAA58008FBF8F /* InsightResultService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightResultService.swift; sourceTree = ""; }; 2BBFC9DA267D05E30013DC74 /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; 2BBFC9DC267D05E30013DC74 /* OrderSetter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderSetter.swift; sourceTree = ""; }; @@ -510,6 +516,15 @@ 80427FDD2BFE2AF4007E89CC /* InsightGroupInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsightGroupInfo.swift; sourceTree = ""; }; 80427FDE2BFE2AF4007E89CC /* InsightInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsightInfo.swift; sourceTree = ""; }; 80427FDF2BFE2AF4007E89CC /* UserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = ""; }; + 80AD3E932BFF2A7300BBD7EB /* QueryRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryRunner.swift; sourceTree = ""; }; + 80AD3E962BFF2AA200BBD7EB /* ClusterChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClusterChart.swift; sourceTree = ""; }; + 80AD3E982BFF2B0A00BBD7EB /* ClusterInstrument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClusterInstrument.swift; sourceTree = ""; }; + 80AD3E9D2BFF305100BBD7EB /* ClusterBarChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClusterBarChart.swift; sourceTree = ""; }; + 80AD3E9F2BFF306F00BBD7EB /* BarChartTimeSeries.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarChartTimeSeries.swift; sourceTree = ""; }; + 80AD3EA22BFF33D900BBD7EB /* ClusterLineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClusterLineChart.swift; sourceTree = ""; }; + 80AD3EA42BFF33FF00BBD7EB /* LineChartTimeSeries.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartTimeSeries.swift; sourceTree = ""; }; + 80AD3EAB2BFF6BE000BBD7EB /* BarChartGroupBy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarChartGroupBy.swift; sourceTree = ""; }; + 80AD3EAD2BFF6D2200BBD7EB /* BarCharTopN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarCharTopN.swift; sourceTree = ""; }; C5173B40283D52E40018CE9F /* InsightsGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightsGrid.swift; sourceTree = ""; }; C51CB73B27565F76005A3FB9 /* TelemetryDeckMacIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TelemetryDeckMacIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; C51CB74C275660E0005A3FB9 /* TelemetryDeckMacWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TelemetryDeckMacWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -843,6 +858,46 @@ path = DTOs; sourceTree = ""; }; + 80AD3E922BFF28AF00BBD7EB /* Cluster */ = { + isa = PBXGroup; + children = ( + 80AD3E982BFF2B0A00BBD7EB /* ClusterInstrument.swift */, + 80AD3E932BFF2A7300BBD7EB /* QueryRunner.swift */, + 80AD3E952BFF2A9600BBD7EB /* Chart */, + ); + path = Cluster; + sourceTree = ""; + }; + 80AD3E952BFF2A9600BBD7EB /* Chart */ = { + isa = PBXGroup; + children = ( + 80AD3E962BFF2AA200BBD7EB /* ClusterChart.swift */, + 80AD3EA12BFF33C100BBD7EB /* LineChart */, + 80AD3E9C2BFF303E00BBD7EB /* BarChart */, + ); + path = Chart; + sourceTree = ""; + }; + 80AD3E9C2BFF303E00BBD7EB /* BarChart */ = { + isa = PBXGroup; + children = ( + 80AD3E9D2BFF305100BBD7EB /* ClusterBarChart.swift */, + 80AD3E9F2BFF306F00BBD7EB /* BarChartTimeSeries.swift */, + 80AD3EAB2BFF6BE000BBD7EB /* BarChartGroupBy.swift */, + 80AD3EAD2BFF6D2200BBD7EB /* BarCharTopN.swift */, + ); + path = BarChart; + sourceTree = ""; + }; + 80AD3EA12BFF33C100BBD7EB /* LineChart */ = { + isa = PBXGroup; + children = ( + 80AD3EA22BFF33D900BBD7EB /* ClusterLineChart.swift */, + 80AD3EA42BFF33FF00BBD7EB /* LineChartTimeSeries.swift */, + ); + path = LineChart; + sourceTree = ""; + }; C5551E5627C3CC78005847B6 /* Sondrine Animation */ = { isa = PBXGroup; children = ( @@ -954,7 +1009,6 @@ DC53393E25222C0900D9C889 /* Insight and Groups */ = { isa = PBXGroup; children = ( - 2BA5D50626CD1403008FBF8F /* InsightCard.swift */, 2B21FCD626FDC38500A8A55B /* NewInsightMenu.swift */, 2B21FCDE26FDCAE200A8A55B /* InsightsList.swift */, 6351A788277C9ED8003AF559 /* InsightDisplayMode+Extensions.swift */, @@ -1019,6 +1073,7 @@ children = ( 4903E9722983EDAA00EEDF5E /* README.md */, 4903E9712983EA1500EEDF5E /* Common.xcconfig */, + 80AD3E922BFF28AF00BBD7EB /* Cluster */, C5F4D31328ACF48000EBB667 /* SwiftUICharts */, 2B74555C27230626002CBB45 /* SwiftUIChartsExtensions */, 2BD189F6267BCEA900DFDE4D /* UIComponents */, @@ -1220,12 +1275,13 @@ DCE239FF24D3687D00053370 /* Sources */, DCE23A0024D3687D00053370 /* Frameworks */, DCE23A0124D3687D00053370 /* Resources */, - DC7DEE9D258A355F00BEA712 /* ShellScript */, + DC7DEE9D258A355F00BEA712 /* Run Script */, C5A8D875270C5D800032560A /* Embed Foundation Extensions */, ); buildRules = ( ); dependencies = ( + 809E189D2C009A1400E83D74 /* PBXTargetDependency */, C5A8D870270C5D800032560A /* PBXTargetDependency */, C5A8D8C5270C821B0032560A /* PBXTargetDependency */, ); @@ -1305,6 +1361,7 @@ DC9C082F252CD622001C0F94 /* XCRemoteSwiftPackageReference "SwiftClient" */, 2B25EAE726D3EEE700BBBB1B /* XCRemoteSwiftPackageReference "SwiftUI-Shimmer" */, C5AD4B6227D3928600CD7E4C /* XCRemoteSwiftPackageReference "models" */, + 809E189B2C00998C00E83D74 /* XCRemoteSwiftPackageReference "SwiftLint" */, ); productRefGroup = DCE23A0424D3687D00053370 /* Products */; projectDirPath = ""; @@ -1446,7 +1503,7 @@ shellPath = /bin/sh; shellScript = "# Use Xcode's copy of the Git binary\nGIT=`xcrun -find git`\n\n# Use the commit count as CFBundleVersion\nGIT_COMMIT_COUNT=`${GIT} rev-list --count HEAD`\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion ${GIT_COMMIT_COUNT}\" \"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n"; }; - DC7DEE9D258A355F00BEA712 /* ShellScript */ = { + DC7DEE9D258A355F00BEA712 /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -1456,6 +1513,7 @@ ); inputPaths = ( ); + name = "Run Script"; outputFileListPaths = ( ); outputPaths = ( @@ -1645,6 +1703,7 @@ files = ( 2B21FCDD26FDCA6A00A8A55B /* GroupView.swift in Sources */, 2BBFCA09267D05E40013DC74 /* Color.swift in Sources */, + 80AD3EAE2BFF6D2200BBD7EB /* BarCharTopN.swift in Sources */, 2B1D469B26CC4F45008814A9 /* AppService.swift in Sources */, DCD52C4A2541FFE3003F12C6 /* ColSpan.swift in Sources */, 2BA5D50B26CDAA58008FBF8F /* InsightResultService.swift in Sources */, @@ -1654,9 +1713,9 @@ 2B21FCD526FDC33F00A8A55B /* InsightGroupsView.swift in Sources */, DCB02B722502781A00304964 /* LoginView.swift in Sources */, 2B379D2126FBC3A300714BE6 /* IconFinderService.swift in Sources */, + 80AD3EAC2BFF6BE000BBD7EB /* BarChartGroupBy.swift in Sources */, C5CD589D2810368400671359 /* ThreeCirclesInATrenchcode.swift in Sources */, 2BBFC9FF267D05E40013DC74 /* OrderSetter.swift in Sources */, - 2BA5D50726CD1403008FBF8F /* InsightCard.swift in Sources */, 2B745562272306DD002CBB45 /* ChartDataPoint+InsightCalculationResult.swift in Sources */, C5F4D34A28ACF48000EBB667 /* DonutChart.swift in Sources */, 2BC522EA2625FCEF00E643AC /* HelpAndFeedbackView.swift in Sources */, @@ -1664,6 +1723,7 @@ 2B1D469826CC4C5D008814A9 /* ErrorService.swift in Sources */, 2BBFCA01267D05E40013DC74 /* DashedCardView.swift in Sources */, C5A8D86E270C5D800032560A /* TelemetryDeckWidget.intentdefinition in Sources */, + 80AD3E992BFF2B0A00BBD7EB /* ClusterInstrument.swift in Sources */, C5F4D36628ACF48000EBB667 /* TextModifiers.swift in Sources */, 2B61B94E264C08D4003F62C4 /* SignalsService.swift in Sources */, 2B1D46A126CC52DD008814A9 /* InsightService.swift in Sources */, @@ -1674,7 +1734,9 @@ 2B781B8326F4A5E30062DBDC /* StatusMessageBanner.swift in Sources */, DCE23A0F24D3687D00053370 /* Telemetry_ViewerApp_iOS.swift in Sources */, DCF7CD40254A08B900BFA23B /* LexiconView.swift in Sources */, + 80AD3E9E2BFF305100BBD7EB /* ClusterBarChart.swift in Sources */, 2B3CC0DC264D4AFE0038B528 /* LexiconService.swift in Sources */, + 80AD3EA52BFF33FF00BBD7EB /* LineChartTimeSeries.swift in Sources */, 2B1D469E26CC51A8008814A9 /* GroupService.swift in Sources */, C56B91F927C536D60085839A /* QueryView.swift in Sources */, 2B1D468926CC4423008814A9 /* OrgService.swift in Sources */, @@ -1687,6 +1749,7 @@ 2B6431992739A5BB009A33C4 /* Data+JSONPrettyPrint.swift in Sources */, C598487727CFBB7A00026772 /* QueryService.swift in Sources */, C5F4D34E28ACF48000EBB667 /* DonutChartLegend.swift in Sources */, + 80AD3E972BFF2AA200BBD7EB /* ClusterChart.swift in Sources */, DCDC6F13253EECA90012D9A7 /* Numbers+Bound.swift in Sources */, 2B0050932703617B009C609C /* Color+Hex.swift in Sources */, 2B1D46A426CCF9CB008814A9 /* LoadingStateIndicator.swift in Sources */, @@ -1706,9 +1769,11 @@ DC9A92B0255C1CD100E92C89 /* AutoCompletingTextField.swift in Sources */, 2BBFC9FB267D05E40013DC74 /* Helpers.swift in Sources */, 63C4E9522778C00000344E20 /* SignalList.swift in Sources */, + 80AD3EA32BFF33D900BBD7EB /* ClusterLineChart.swift in Sources */, C5F4D33228ACF48000EBB667 /* LineChartView.swift in Sources */, DC627EEF25A35B6A00C1DF33 /* EmptyAppView.swift in Sources */, 6351A784277C6431003AF559 /* CustomPickers.swift in Sources */, + 80AD3EA02BFF306F00BBD7EB /* BarChartTimeSeries.swift in Sources */, DCB02B6B2502773D00304964 /* WelcomeView.swift in Sources */, 2B46280B2728699E00515530 /* StatusMessageContainer.swift in Sources */, 2BBFCA33267D05E40013DC74 /* AdaptiveStack.swift in Sources */, @@ -1719,6 +1784,7 @@ C5F4D36228ACF48000EBB667 /* SingleKeyValueView.swift in Sources */, 63C4E9582778C54D00344E20 /* SignalListExplanationView.swift in Sources */, 2BBFCA25267D05E40013DC74 /* ProgressView+Scale.swift in Sources */, + 80AD3E942BFF2A7300BBD7EB /* QueryRunner.swift in Sources */, 2BBFCA29267D05E40013DC74 /* Binding+OnUpdate.swift in Sources */, 2BC2720226207D710045A2FE /* MockData.swift in Sources */, DCDC6F0C253EEB9B0012D9A7 /* Optional+Bound.swift in Sources */, @@ -1817,7 +1883,6 @@ 2BBFCA12267D05E40013DC74 /* DetailSidebar.swift in Sources */, DCF7CD48254A0DB300BFA23B /* LexiconItemView.swift in Sources */, 2B670C0026BD8BF7005DA07E /* SidebarSplitView.swift in Sources */, - 2BA5D50826CD1403008FBF8F /* InsightCard.swift in Sources */, DCEC64B126025AAF00BEF69C /* PasswordResetView.swift in Sources */, DC24DF3425DD54090003ADCB /* NoAppSelectedView.swift in Sources */, C5CD589C2810368300671359 /* AnimatedCircle.swift in Sources */, @@ -1864,6 +1929,10 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 809E189D2C009A1400E83D74 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 809E189C2C009A1400E83D74 /* SwiftLintBuildToolPlugin */; + }; C5A8D870270C5D800032560A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = C5A8D862270C5D7A0032560A /* TelemetryDeckWidgetExtension */; @@ -2260,7 +2329,7 @@ DEVELOPMENT_TEAM = FL4V655A94; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2286,7 +2355,7 @@ DEVELOPMENT_TEAM = FL4V655A94; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2434,6 +2503,14 @@ minimumVersion = 1.0.0; }; }; + 809E189B2C00998C00E83D74 /* XCRemoteSwiftPackageReference "SwiftLint" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/realm/SwiftLint"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.55.1; + }; + }; C5AD4B6227D3928600CD7E4C /* XCRemoteSwiftPackageReference "models" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/TelemetryDeck/models"; @@ -2484,6 +2561,11 @@ package = 2B25EAE726D3EEE700BBBB1B /* XCRemoteSwiftPackageReference "SwiftUI-Shimmer" */; productName = Shimmer; }; + 809E189C2C009A1400E83D74 /* SwiftLintBuildToolPlugin */ = { + isa = XCSwiftPackageProductDependency; + package = 809E189B2C00998C00E83D74 /* XCRemoteSwiftPackageReference "SwiftLint" */; + productName = "plugin:SwiftLintBuildToolPlugin"; + }; C51CB76227566148005A3FB9 /* DataTransferObjects */ = { isa = XCSwiftPackageProductDependency; productName = DataTransferObjects; diff --git a/Telemetry Viewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Telemetry Viewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ff024ae..8ff7842 100644 --- a/Telemetry Viewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Telemetry Viewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,24 @@ { + "originHash" : "c77feac7351e9360f94da77ea6664ee97c0a4c27540c7ad522fe8a1013e98df7", "pins" : [ + { + "identity" : "collectionconcurrencykit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", + "state" : { + "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", + "version" : "0.2.0" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0", + "version" : "1.8.2" + } + }, { "identity" : "models", "kind" : "remoteSourceControl", @@ -9,6 +28,24 @@ "version" : "1.11.0" } }, + { + "identity" : "sourcekitten", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/SourceKitten.git", + "state" : { + "revision" : "fd4df99170f5e9d7cf9aa8312aa8506e0e7a44e7", + "version" : "0.35.0" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b", + "version" : "1.4.0" + } + }, { "identity" : "swift-crypto", "kind" : "remoteSourceControl", @@ -18,6 +55,15 @@ "version" : "2.6.0" } }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "303e5c5c36d6a558407d364878df131c3546fad8", + "version" : "510.0.2" + } + }, { "identity" : "swiftclient", "kind" : "remoteSourceControl", @@ -36,6 +82,15 @@ "version" : "1.0.3" } }, + { + "identity" : "swiftlint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/SwiftLint", + "state" : { + "revision" : "b515723b16eba33f15c4677ee65f3fef2ce8c255", + "version" : "0.55.1" + } + }, { "identity" : "swiftui-shimmer", "kind" : "remoteSourceControl", @@ -44,7 +99,34 @@ "revision" : "5659a623567cefe258d1e3e67cb65585fbb6ecb6", "version" : "1.4.2" } + }, + { + "identity" : "swiftytexttable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", + "state" : { + "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", + "version" : "0.9.0" + } + }, + { + "identity" : "swxmlhash", + "kind" : "remoteSourceControl", + "location" : "https://github.com/drmohundro/SWXMLHash.git", + "state" : { + "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", + "version" : "7.0.2" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "9234124cff5e22e178988c18d8b95a8ae8007f76", + "version" : "5.1.2" + } } ], - "version" : 2 + "version" : 3 } diff --git a/UIComponents/Color.swift b/UIComponents/Color.swift index 5befda6..0488444 100644 --- a/UIComponents/Color.swift +++ b/UIComponents/Color.swift @@ -20,4 +20,11 @@ extension Color { static let telemetryOrange = Color("Torange") static let cardBackground = Color("CardBackgroundColor") static let customTextColor = Color("CustomTextColor") + + static let Zinc50 = Color("Zinc50") + static let Zinc100 = Color("Zinc100") + static let Zinc200 = Color("Zinc200") + static let Zinc400 = Color("Zinc400") + static let Zinc600 = Color("Zinc600") + } diff --git a/iOS/InsightGroupsView.swift b/iOS/InsightGroupsView.swift index f4dd1b7..668d87e 100644 --- a/iOS/InsightGroupsView.swift +++ b/iOS/InsightGroupsView.swift @@ -40,7 +40,7 @@ struct InsightGroupsView: View { var body: some View { NavigationView { VStack(alignment: .leading, spacing: 0) { - StatusMessageDisplay() + //StatusMessageDisplay() TestModeIndicator() @@ -59,7 +59,7 @@ struct InsightGroupsView: View { selectedInsightGroupID.map { GroupView(groupID: $0, selectedInsightID: $selectedInsightID, sidebarVisible: $sidebarVisible) - .background(Color.separatorColor) + .background(Color.Zinc100) } } } diff --git a/iOS/InsightsGrid.swift b/iOS/InsightsGrid.swift index caa52f3..f8ca720 100644 --- a/iOS/InsightsGrid.swift +++ b/iOS/InsightsGrid.swift @@ -17,39 +17,15 @@ struct InsightsGrid: View { let isSelectable: Bool var body: some View { - let allInsights = insightGroup.insightIDs.map { - ($0, insightService.insight(withID: $0)) - } - - let loadedInsights = allInsights.filter { $0.1 != nil } - let loadingInsights = allInsights.filter { $0.1 == nil } - let expandedInsights = loadedInsights.filter { $0.1?.isExpanded == true }.sorted { $0.1?.order ?? 0 < $1.1?.order ?? 0 } - let unexpandedInsights = loadedInsights.filter { $0.1?.isExpanded == false }.sorted { $0.1?.order ?? 0 < $1.1?.order ?? 0 } - return LazyVGrid(columns: [GridItem(.adaptive(minimum: 800), spacing: spacing)], alignment: .leading, spacing: spacing) { - ForEach(expandedInsights.map { $0.0 }, id: \.self) { insightID in - InsightCard(selectedInsightID: $selectedInsightID, sidebarVisible: $sidebarVisible, insightID: insightID, isSelectable: isSelectable) - .id(insightID) - } - - LazyVGrid(columns: [GridItem(.adaptive(minimum: 300), spacing: spacing)], alignment: .leading, spacing: spacing) { - ForEach(unexpandedInsights.map { $0.0 }, id: \.self) { insightID in - InsightCard(selectedInsightID: $selectedInsightID, sidebarVisible: $sidebarVisible, insightID: insightID, isSelectable: isSelectable) - .id(insightID) + VStack{ + ForEach(insightGroup.insights, id: \.id) { insight in + if let query = insight.query { + ClusterInstrument(query: query, title: insight.title, type: insight.displayMode) + } else { + Text("Couldn't get query") } } - - LazyVGrid(columns: [GridItem(.adaptive(minimum: 300), spacing: spacing)], alignment: .leading, spacing: spacing) { - ForEach(loadingInsights.map { $0.0 }, id: \.self) { insightID in - InsightCard(selectedInsightID: $selectedInsightID, sidebarVisible: $sidebarVisible, insightID: insightID, isSelectable: isSelectable) - .id(insightID) - } - } - } - .refreshable { - for insightID in insightGroup.insightIDs { - insightService.taskRetrieveInsight(with: insightID) - } } } }