Skip to content

Commit

Permalink
Use AppInfo Struct instead of App DTO
Browse files Browse the repository at this point in the history
  • Loading branch information
Black-Fox-2022 committed May 21, 2024
1 parent 9899a9a commit 29b8d0e
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 23 deletions.
24 changes: 24 additions & 0 deletions APIClient/DTOs/AppInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// AppInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation
import DataTransferObjects
import SwiftUI

public struct AppInfo: Codable, Hashable, Identifiable {
public var id: UUID
public var name: String
public var organizationID: UUID
public var insightGroups: [InsightGroupInfo]
public var settings: DTOv2.AppSettings
public var insightGroupIDs: [UUID] {
insightGroups.map { group in
group.id
}
}

}
25 changes: 25 additions & 0 deletions APIClient/DTOs/InsightGroupInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// InsightGroupInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation

public struct InsightGroupInfo: Codable, Hashable, Identifiable {
public init(id: UUID, title: String, order: Double? = nil, appID: UUID, insights: [InsightInfo]) {
self.id = id
self.title = title
self.order = order
self.appID = appID
self.insights = insights
}

public var id: UUID
public var title: String
public var order: Double?
public var appID: UUID
public var insights: [InsightInfo]

}
99 changes: 99 additions & 0 deletions APIClient/DTOs/InsightInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// InsightInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation
import DataTransferObjects

public struct InsightInfo: Codable, Hashable, Identifiable {
public enum InsightType: String, Codable, Hashable {
case timeseries
case topN
case customQuery
case funnel
case experiment
}

public var id: UUID
public var groupID: UUID

/// order in which insights appear in the apps (if not expanded)
public var order: Double?
public var title: String

/// 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?

/// If true, only include at the newest signal from each user
public var uniqueUser: Bool

/// Only include signals that match all of these key-values in the payload
public var filters: [String: String]

/// If set, break down the values in this key
public var breakdownKey: String?

/// If set, group and count found signals by this time interval. Incompatible with breakdownKey
public var groupBy: QueryGranularity?

/// How should this insight's data be displayed?
public var displayMode: InsightDisplayMode

/// If true, the insight will be displayed bigger
public var isExpanded: Bool

/// The amount of time (in seconds) this query took to calculate last time
public var lastRunTime: TimeInterval?

/// The date this query was last run
public var lastRunAt: Date?

public init(
id: UUID,
groupID: UUID,
order: Double?,
title: String,
type: InsightType,
accentColor: String? = nil,
widgetable _: Bool? = false,
customQuery: CustomQuery? = nil,
signalType: String?,
uniqueUser: Bool,
filters: [String: String],
breakdownKey: String?,
groupBy: QueryGranularity?,
displayMode: InsightDisplayMode,
isExpanded: Bool,
lastRunTime: TimeInterval?,
lastRunAt: Date?
) {
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.filters = filters
self.breakdownKey = breakdownKey
self.groupBy = groupBy
self.displayMode = displayMode
self.isExpanded = isExpanded
self.lastRunTime = lastRunTime
self.lastRunAt = lastRunAt
}
}
1 change: 0 additions & 1 deletion APIClient/DTOs/UserInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ struct UserInfoDTO: Identifiable, Codable {
public var receiveMarketingEmails: Bool?
public var receiveReports: ReportSendingRate


}
28 changes: 14 additions & 14 deletions Services/AppService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class AppService: ObservableObject {

var loadingCancellable: AnyCancellable?

@Published var appDictionary: [DTOv2.App.ID: DTOv2.App] = [:]
@Published var loadingStateDictionary: [DTOv2.App.ID: LoadingState] = [:]
@Published var appDictionary: [AppInfo.ID: AppInfo] = [:]
@Published var loadingStateDictionary: [AppInfo.ID: LoadingState] = [:]

init(api: APIClient, errors: ErrorService, orgService: OrgService) {
self.api = api
Expand All @@ -46,23 +46,23 @@ class AppService: ObservableObject {
return loadingState
}

func app(withID appID: DTOv2.App.ID) -> DTOv2.App? {
func app(withID appID: AppInfo.ID) -> AppInfo? {
return appDictionary[appID]
}

func retrieveApp(with appID: DTOv2.App.ID, callback: ((Result<DTOv2.App, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)
let url = api.urlForPath(apiVersion: .v3, "apps", appID.uuidString)
api.get(url) { (result: Result<DTOv2.App, TransferError>) in
callback?(result)
}
}

func retrieveApp(withID appID: DTOv2.App.ID) async throws -> DTOv2.App {
func retrieveApp(withID appID: DTOv2.App.ID) async throws -> AppInfo {
// guard loadingStateDictionary[appID] != .loading else { let error: TransferError = .transferFailed; throw error }
// loadingStateDictionary[appID] = .loading
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<DTOv2.App, Error>) in
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)
api.get(url) { (result: Result<DTOv2.App, TransferError>) in
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<AppInfo, Error>) in
let url = api.urlForPath(apiVersion: .v3, "apps", appID.uuidString)
api.get(url) { (result: Result<AppInfo, TransferError>) in
switch result {
case let .success(app):

Expand All @@ -76,10 +76,10 @@ class AppService: ObservableObject {
}
}

func create(appNamed name: String, callback: ((Result<DTOv2.App, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps")
func create(appNamed name: String, callback: ((Result<AppInfo, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v3, "apps")

api.post(["name": name], to: url) { [unowned self] (result: Result<DTOv2.App, TransferError>) in
api.post(["name": name], to: url) { [unowned self] (result: Result<AppInfo, TransferError>) in

if let app = try? result.get() {
appDictionary[app.id] = app
Expand All @@ -90,10 +90,10 @@ class AppService: ObservableObject {
}
}

func update(appID: UUID, newName: String, callback: ((Result<DTOv2.App, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)
func update(appID: UUID, newName: String, callback: ((Result<AppInfo, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v3, "apps", appID.uuidString)

api.patch(["name": newName], to: url) { [unowned self] (result: Result<DTOv2.App, TransferError>) in
api.patch(["name": newName], to: url) { [unowned self] (result: Result<AppInfo, TransferError>) in

if let app = try? result.get() {
appDictionary[app.id] = app
Expand Down
10 changes: 5 additions & 5 deletions Shared/App/CreateNewAppViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ class CreateNewAppViewModel: ObservableObject {
let appService: AppService

@Published var appName: String = "New App"
@Published var existingApps: [DTOv2.App] = []
@Published var existingApps: [AppInfo] = []
@Published var createDefaultInsights: Bool = true
@Published var createdApp: DTOv2.App?
@Published var createdApp: AppInfo?

@Binding var newAppViewShown: Bool

Expand Down Expand Up @@ -47,8 +47,8 @@ class CreateNewAppViewModel: ObservableObject {
return .valid
}

func appsFromAppIDs() -> [DTOv2.App] {
var apps: [DTOv2.App] = []
func appsFromAppIDs() -> [AppInfo] {
var apps: [AppInfo] = []
guard orgService.organization != nil else { return [] }
for appID in orgService.organization!.appIDs {
guard appService.app(withID: appID) != nil else { continue }
Expand All @@ -58,7 +58,7 @@ class CreateNewAppViewModel: ObservableObject {
}

func createNewApp() {
appService.create(appNamed: appName) { (result: Result<DTOv2.App, TransferError>) in
appService.create(appNamed: appName) { (result: Result<AppInfo, TransferError>) in
switch result {
case let .failure(error):
print(error)
Expand Down
2 changes: 1 addition & 1 deletion Shared/Empty Status Views/EmptyAppView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct EmptyAppView: View {
@EnvironmentObject var appService: AppService

let appID: UUID
private var app: DTOv2.App? { appService.app(withID: appID) }
private var app: AppInfo? { appService.app(withID: appID) }

var body: some View {
VStack(spacing: 20) {
Expand Down
4 changes: 2 additions & 2 deletions iOS/CreateNewAppView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct CreateNewAppView: View {
}
}

func copyAppIDSection(newApp: DTOv2.App) -> some View {
func copyAppIDSection(newApp: AppInfo) -> some View {
Section {
Button(newApp.id.uuidString) {
saveToClipBoard(newApp.id.uuidString)
Expand All @@ -61,7 +61,7 @@ struct CreateNewAppView: View {
}
}

func documentationSection(newApp: DTOv2.App) -> some View {
func documentationSection(newApp: AppInfo) -> some View {
Section {
Button("Open Documentation") {
URL(string: "https://telemetrydeck.com/pages/quickstart.html")?.open()
Expand Down

0 comments on commit 29b8d0e

Please sign in to comment.