Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OrgSwitcher #195

Merged
merged 2 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
}
}

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

@Published var registrationStatus: RegistrationStatus?

@Published var userToken: UserTokenDTO? {
Expand Down Expand Up @@ -95,7 +97,7 @@
extension APIClient {

func login(loginRequestBody: LoginRequestBody, callback: @escaping (Bool) -> Void) {
let url = urlForPath(apiVersion: .v3,"users", "login")

Check warning on line 100 in APIClient/APIClient.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Comma Spacing Violation: There should be no space before and one after any comma (comma)

var request = URLRequest(url: url)
request.httpMethod = "POST"
Expand Down Expand Up @@ -387,6 +389,9 @@
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 @@
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 @@
switch result {
case let .success(org):

self.saveToDisk(org: org)

continuation.resume(returning: org)

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

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