Skip to content

Commit

Permalink
Merge pull request #195 from TelemetryDeck/OrganisationSwitcher
Browse files Browse the repository at this point in the history
OrgSwitcher
  • Loading branch information
Black-Fox-2022 authored May 31, 2024
2 parents 9d8984f + 7305a1e commit f08383c
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 90 deletions.
5 changes: 5 additions & 0 deletions APIClient/APIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ final class APIClient: ObservableObject {
}
}

@AppStorage("currentOrganisationID") var _currentOrganisationID: String?

@Published var registrationStatus: RegistrationStatus?

@Published var userToken: UserTokenDTO? {
Expand Down Expand Up @@ -387,6 +389,9 @@ extension APIClient {
request.httpMethod = httpMethod
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.setValue(userToken?.bearerTokenAuthString, forHTTPHeaderField: "Authorization")
if let currentOrgID = _currentOrganisationID {
request.setValue(currentOrgID, forHTTPHeaderField: "td-organization-id")
}

if let httpBody = httpBody {
request.httpBody = httpBody
Expand Down
80 changes: 80 additions & 0 deletions APIClient/DTOs/OrganizationInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// OrganizationInfo.swift
// Telemetry Viewer
//
// Created by Lukas on 29.05.24.
//

import Foundation
import SwiftUI

struct OrganizationInfo: Codable, Equatable {
var id: UUID
var name: String
var stripeCustomerID: String?
var stripeMaxSignals: Double?
var maxSignalsMultiplier: Double?
var resolvedMaxSignals: Int64
var isInRestrictedMode: Bool
var countryCode: String?
var referralCode: String
var usagePercentage: Double?
var isSuperOrg: Bool
var apps: [AppInfo]
var basePermissions: AppAccessLevel
var roleOrganizationPermissions: AppAccessLevel?

var appIDs: [UUID] {
apps.map { app in
app.id
}
}

}

public enum AppAccessLevel: String, Codable, Comparable {
case none
case read
case write
case administrate

public static func < (lhs: AppAccessLevel, rhs: AppAccessLevel) -> Bool {

Check warning on line 41 in APIClient/DTOs/OrganizationInfo.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Cyclomatic Complexity Violation: Function should have complexity 10 or less; currently complexity is 16 (cyclomatic_complexity)
switch lhs {
case .none:
switch rhs {
case .none:
false
case .read:
true
case .write:
true
case .administrate:
true
}
case .read:
switch rhs {
case .none:
false
case .read:
false
case .write:
true
case .administrate:
true
}
case .write:
switch rhs {
case .none:
false
case .read:
false
case .write:
false
case .administrate:
true
}
case .administrate:
false
}
}
}
38 changes: 0 additions & 38 deletions Services/AppService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,42 +75,4 @@ class AppService: ObservableObject {
}
}
}

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<AppInfo, TransferError>) in

if let app = try? result.get() {
appDictionary[app.id] = app
orgService.organization?.appIDs.append(app.id)
}

callback?(result)
}
}

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<AppInfo, TransferError>) in

if let app = try? result.get() {
appDictionary[app.id] = app
}

callback?(result)
}
}

func delete(appID: UUID, callback: ((Result<[String: String], TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)

api.delete(url) { [unowned self] (result: Result<[String: String], TransferError>) in

appDictionary[appID] = nil
orgService.organization?.appIDs = (orgService.organization?.appIDs.filter { $0 != appID })!
callback?(result)
}
}
}
38 changes: 4 additions & 34 deletions Services/OrgService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@ class OrgService: ObservableObject {
self.errorService = errors
}

// Wasn't getting called before -> Never leaving loading state.
// For now called when retrieveOrganisations also called
// Maybe move getCode into the retrieve Func?
func getOrganisation() {
let locallyCachedOrganization = retrieveFromDisk()
self.organization = locallyCachedOrganization

self.loadingState = .loading

Task {
Expand Down Expand Up @@ -57,8 +51,6 @@ class OrgService: ObservableObject {
switch result {
case let .success(org):

self.saveToDisk(org: org)

continuation.resume(returning: org)

case let .failure(error):
Expand All @@ -68,32 +60,10 @@ class OrgService: ObservableObject {
}
}
}
}

/// this is interesting, do we want this for more than the org?
private extension OrgService {
var organizationCacheFilePath: URL {
let fileManager = FileManager.default
let urls = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)
let cachesDirectoryUrl = urls[0]
let fileUrl = cachesDirectoryUrl.appendingPathComponent("telemetrydeck.organization.json")
let filePath = fileUrl.path

if !fileManager.fileExists(atPath: filePath) {
let contents = Data()
fileManager.createFile(atPath: filePath, contents: contents)
}

return fileUrl
}

func saveToDisk(org: DTOv2.Organization) {
guard let data = try? JSONEncoder.telemetryEncoder.encode(org) else { return }
try? data.write(to: self.organizationCacheFilePath, options: .atomic)
}

func retrieveFromDisk() -> DTOv2.Organization? {
guard let data = try? Data(contentsOf: organizationCacheFilePath) else { return nil }
return try? JSONDecoder.telemetryDecoder.decode(DTOv2.Organization.self, from: data)
func allOrganizations() async throws -> [OrganizationInfo]{
let url = api.urlForPath(apiVersion: .v3, "organizations")
return try await api.get(url: url)
}
}

Check warning on line 69 in Services/OrgService.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Trailing Newline Violation: Files should have a single trailing newline (trailing_newline)
5 changes: 0 additions & 5 deletions Shared/Empty Status Views/NoAppSelectedView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ struct NoAppSelectedView: View {
Text("To start, create your first App. You can use that App's unique identifier to send signals from your code.")
.foregroundColor(.grayColor)
VStack {
Button("Create First App") {
appService.create(appNamed: "New App")
}
.buttonStyle(SmallPrimaryButtonStyle())

Button("Documentation: Sending Signals") {
#if os(macOS)
NSWorkspace.shared.open(URL(string: "https://telemetrydeck.com/pages/quickstart.html")!)
Expand Down
35 changes: 22 additions & 13 deletions Shared/Navigational Structure/LeftSidebarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,35 @@ struct LeftSidebarView: View {
case editApp(app: UUID)
}

func getApps(organization: DTOv2.Organization?) {
Task {
for appID in organization?.appIDs ?? [] {
if let app = try? await appService.retrieveApp(withID: appID) {
DispatchQueue.main.async {
app.insightGroupIDs.forEach { groupID in
if !(groupService.groupsDictionary.keys.contains(groupID)) {
groupService.retrieveGroup(with: groupID)
}
}
appService.appDictionary[app.id] = app
}
}
}
}
}

var body: some View {
List {
Section {
if let organization = orgService.organization {
ForEach(organization.appIDs, id: \.self) { appID in
section(for: appID)
}
.onChange(of: orgService.organization) {
getApps(organization: orgService.organization)
}
.task {
for appID in organization.appIDs {
if let app = try? await appService.retrieveApp(withID: appID) {
DispatchQueue.main.async {
app.insightGroupIDs.forEach { groupID in
if !(groupService.groupsDictionary.keys.contains(groupID)) {
groupService.retrieveGroup(with: groupID)
}
}
appService.appDictionary[app.id] = app
}
}
}
getApps(organization: orgService.organization)
}
}

Expand All @@ -64,7 +73,7 @@ struct LeftSidebarView: View {
}

Section {
LoadingStateIndicator(loadingState: orgService.loadingState, title: orgService.organization?.name)
OrganisationSwitcher()

#if os(iOS)
Button {
Expand Down
18 changes: 18 additions & 0 deletions Telemetry Viewer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@
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 */; };
804385CF2C073763004E3285 /* OrganizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385CE2C073763004E3285 /* OrganizationInfo.swift */; };
804385D02C073763004E3285 /* OrganizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385CE2C073763004E3285 /* OrganizationInfo.swift */; };
804385D12C073763004E3285 /* OrganizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385CE2C073763004E3285 /* OrganizationInfo.swift */; };
804385D22C073763004E3285 /* OrganizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385CE2C073763004E3285 /* OrganizationInfo.swift */; };
804385D32C073763004E3285 /* OrganizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385CE2C073763004E3285 /* OrganizationInfo.swift */; };
804385D42C073763004E3285 /* OrganizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385CE2C073763004E3285 /* OrganizationInfo.swift */; };
804385D62C0739D0004E3285 /* OrganisationSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804385D52C0739D0004E3285 /* OrganisationSwitcher.swift */; };
8083DD692C05C9C300596926 /* ClusterPieChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8083DD682C05C9C300596926 /* ClusterPieChart.swift */; };
8083DD6B2C05C9FE00596926 /* PieChartTopN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8083DD6A2C05C9FE00596926 /* PieChartTopN.swift */; };
8083DD6D2C05EA0100596926 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8083DD6C2C05EA0100596926 /* Extensions.swift */; };
Expand Down Expand Up @@ -516,6 +523,8 @@
80427FDD2BFE2AF4007E89CC /* InsightGroupInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsightGroupInfo.swift; sourceTree = "<group>"; };
80427FDE2BFE2AF4007E89CC /* InsightInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsightInfo.swift; sourceTree = "<group>"; };
80427FDF2BFE2AF4007E89CC /* UserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = "<group>"; };
804385CE2C073763004E3285 /* OrganizationInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizationInfo.swift; sourceTree = "<group>"; };
804385D52C0739D0004E3285 /* OrganisationSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationSwitcher.swift; sourceTree = "<group>"; };
8083DD682C05C9C300596926 /* ClusterPieChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClusterPieChart.swift; sourceTree = "<group>"; };
8083DD6A2C05C9FE00596926 /* PieChartTopN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PieChartTopN.swift; sourceTree = "<group>"; };
8083DD6C2C05EA0100596926 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -855,6 +864,7 @@
80427FDD2BFE2AF4007E89CC /* InsightGroupInfo.swift */,
80427FDE2BFE2AF4007E89CC /* InsightInfo.swift */,
80427FDF2BFE2AF4007E89CC /* UserInfo.swift */,
804385CE2C073763004E3285 /* OrganizationInfo.swift */,
);
path = DTOs;
sourceTree = "<group>";
Expand Down Expand Up @@ -1142,6 +1152,7 @@
DC9A92AF255C1CD100E92C89 /* AutoCompletingTextField.swift */,
2B21FCD926FDC9F900A8A55B /* InsightsGrid.swift */,
DCDC6EFE253EDA4C0012D9A7 /* FilterEditView.swift */,
804385D52C0739D0004E3285 /* OrganisationSwitcher.swift */,
2B21FCDC26FDCA6A00A8A55B /* GroupView.swift */,
2B21FCD426FDC33F00A8A55B /* InsightGroupsView.swift */,
DCE239FC24D3687C00053370 /* Telemetry_ViewerApp_iOS.swift */,
Expand Down Expand Up @@ -1551,6 +1562,7 @@
C51CB78B27566279005A3FB9 /* InsightService.swift in Sources */,
C5F4D37028ACF64700EBB667 /* ChartDataSet.swift in Sources */,
80427FEC2BFE2AF4007E89CC /* InsightGroupInfo.swift in Sources */,
804385D42C073763004E3285 /* OrganizationInfo.swift in Sources */,
C51CB78927566275005A3FB9 /* ErrorService.swift in Sources */,
C51CB7922756646E005A3FB9 /* TelemetrySignalTypes.swift in Sources */,
C5F4D37128ACF64700EBB667 /* ChartDataPoint.swift in Sources */,
Expand Down Expand Up @@ -1613,6 +1625,7 @@
C5F4D33528ACF48000EBB667 /* LineChartView.swift in Sources */,
C51CB78527566258005A3FB9 /* ConditionalViewModifier.swift in Sources */,
C5F4D33D28ACF48000EBB667 /* RawChartView.swift in Sources */,
804385D22C073763004E3285 /* OrganizationInfo.swift in Sources */,
C51CB77F27566243005A3FB9 /* Color.swift in Sources */,
C5F4D33128ACF48000EBB667 /* ChartBottomView.swift in Sources */,
C51CB7912756646D005A3FB9 /* TelemetrySignalTypes.swift in Sources */,
Expand Down Expand Up @@ -1675,6 +1688,7 @@
C5F4D33428ACF48000EBB667 /* LineChartView.swift in Sources */,
C5CE3D57271AFCE2005232EC /* Buttonstyles.swift in Sources */,
C5F4D33C28ACF48000EBB667 /* RawChartView.swift in Sources */,
804385D12C073763004E3285 /* OrganizationInfo.swift in Sources */,
2B6431A72739A5BB009A33C4 /* AsyncOperation.swift in Sources */,
C5F4D33028ACF48000EBB667 /* ChartBottomView.swift in Sources */,
C581F4E0271B22FD0031E99C /* Color+Hex.swift in Sources */,
Expand All @@ -1699,6 +1713,7 @@
2B64319C2739A5BB009A33C4 /* Data+JSONPrettyPrint.swift in Sources */,
C5F4D36E28ACF64600EBB667 /* ChartDataSet.swift in Sources */,
80427FEB2BFE2AF4007E89CC /* InsightGroupInfo.swift in Sources */,
804385D32C073763004E3285 /* OrganizationInfo.swift in Sources */,
2B6431AC2739A5BB009A33C4 /* Caching.swift in Sources */,
C51CB78F27566296005A3FB9 /* ConditionalViewModifier.swift in Sources */,
C5F4D36F28ACF64600EBB667 /* ChartDataPoint.swift in Sources */,
Expand All @@ -1721,6 +1736,7 @@
C5F4D35628ACF48000EBB667 /* ChartDataSet.swift in Sources */,
C5F4D33E28ACF48000EBB667 /* RoundedCorners.swift in Sources */,
2B21FCD526FDC33F00A8A55B /* InsightGroupsView.swift in Sources */,
804385D62C0739D0004E3285 /* OrganisationSwitcher.swift in Sources */,
DCB02B722502781A00304964 /* LoginView.swift in Sources */,
2B379D2126FBC3A300714BE6 /* IconFinderService.swift in Sources */,
C5CD589D2810368400671359 /* ThreeCirclesInATrenchcode.swift in Sources */,
Expand All @@ -1743,6 +1759,7 @@
2B781B8326F4A5E30062DBDC /* StatusMessageBanner.swift in Sources */,
DCE23A0F24D3687D00053370 /* Telemetry_ViewerApp_iOS.swift in Sources */,
DCF7CD40254A08B900BFA23B /* LexiconView.swift in Sources */,
804385CF2C073763004E3285 /* OrganizationInfo.swift in Sources */,
80AD3E9E2BFF305100BBD7EB /* ClusterBarChart.swift in Sources */,
2B3CC0DC264D4AFE0038B528 /* LexiconService.swift in Sources */,
80AD3EA52BFF33FF00BBD7EB /* LineChartTimeSeries.swift in Sources */,
Expand Down Expand Up @@ -1928,6 +1945,7 @@
2B46280F27286D2500515530 /* TestingModeToggle.swift in Sources */,
2B1D469926CC4C5D008814A9 /* ErrorService.swift in Sources */,
2B61B94F264C08D4003F62C4 /* SignalsService.swift in Sources */,
804385D02C073763004E3285 /* OrganizationInfo.swift in Sources */,
C5F4D33F28ACF48000EBB667 /* RoundedCorners.swift in Sources */,
DC627EF025A35B6A00C1DF33 /* EmptyAppView.swift in Sources */,
6351A78A277C9EDA003AF559 /* InsightDisplayMode+Extensions.swift in Sources */,
Expand Down
Loading

0 comments on commit f08383c

Please sign in to comment.