Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add login flow & session management#10

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ethanndickson merged 4 commits intomainfromethan/login-flow
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from1 commit
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
2 changes: 2 additions & 0 deletionsCoder Desktop/.swiftlint.yml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,3 +3,5 @@ disabled_rules:
- trailing_comma
type_name:
allowed_symbols: "_"
identifier_name:
allowed_symbols: "_"
19 changes: 19 additions & 0 deletionsCoder Desktop/Coder Desktop.xcodeproj/project.pbxproj
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,7 @@
AA8BC3392D0060A900E1ABAA /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = AA8BC3382D0060A900E1ABAA /* ViewInspector */; };
AA8BC33F2D0061F200E1ABAA /* FluidMenuBarExtra in Frameworks */ = {isa = PBXBuildFile; productRef = AA8BC33E2D0061F200E1ABAA /* FluidMenuBarExtra */; };
AA8BC4CF2D00A4B700E1ABAA /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = AA8BC4CE2D00A4B700E1ABAA /* KeychainAccess */; };
AAD720D02D0816B200F6304D /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = AAD720CF2D0816B200F6304D /* Alamofire */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand DownExpand Up@@ -101,6 +102,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AAD720D02D0816B200F6304D /* Alamofire in Frameworks */,
AA8BC4CF2D00A4B700E1ABAA /* KeychainAccess in Frameworks */,
AA8BC33F2D0061F200E1ABAA /* FluidMenuBarExtra in Frameworks */,
);
Expand DownExpand Up@@ -188,6 +190,7 @@
packageProductDependencies = (
AA8BC33E2D0061F200E1ABAA /* FluidMenuBarExtra */,
AA8BC4CE2D00A4B700E1ABAA /* KeychainAccess */,
AAD720CF2D0816B200F6304D /* Alamofire */,
);
productName = "Coder Desktop";
productReference = 961678FC2CFF100D00B2B6DF /* Coder Desktop.app */;
Expand DownExpand Up@@ -302,6 +305,7 @@
AA8BC33A2D0060C500E1ABAA /* XCRemoteSwiftPackageReference "SwiftLintPlugins" */,
AA8BC33D2D0061F200E1ABAA /* XCRemoteSwiftPackageReference "fluid-menu-bar-extra" */,
AA8BC4CD2D00A4B700E1ABAA /* XCRemoteSwiftPackageReference "KeychainAccess" */,
AAD720CE2D0816B200F6304D /* XCRemoteSwiftPackageReference "Alamofire" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 961678FD2CFF100D00B2B6DF /* Products */;
Expand DownExpand Up@@ -533,6 +537,7 @@
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand DownExpand Up@@ -561,6 +566,7 @@
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand DownExpand Up@@ -778,6 +784,14 @@
kind = branch;
};
};
AAD720CE2D0816B200F6304D /* XCRemoteSwiftPackageReference "Alamofire" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Alamofire/Alamofire";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.10.2;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All@@ -801,6 +815,11 @@
package = AA8BC4CD2D00A4B700E1ABAA /* XCRemoteSwiftPackageReference "KeychainAccess" */;
productName = KeychainAccess;
};
AAD720CF2D0816B200F6304D /* Alamofire */ = {
isa = XCSwiftPackageProductDependency;
package = AAD720CE2D0816B200F6304D /* XCRemoteSwiftPackageReference "Alamofire" */;
productName = Alamofire;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 961678F42CFF100D00B2B6DF /* Project object */;
Expand Down

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

47 changes: 47 additions & 0 deletionsCoder Desktop/Coder Desktop/About.swift
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
import SwiftUI

enum About {
private static var credits: NSAttributedString {
let coder = NSMutableAttributedString(
string: "Coder.com",
attributes: [
.foregroundColor: NSColor.labelColor,
.link: NSURL(string: "https://coder.com")!,
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
]
)
let separator = NSAttributedString(
string: " | ",
attributes: [
.foregroundColor: NSColor.labelColor,
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
]
)
let source = NSAttributedString(
string: "GitHub",
attributes: [
.foregroundColor: NSColor.labelColor,
.link: NSURL(string: "https://github.com/coder/coder-desktop-macos")!,
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
]
)
coder.append(separator)
coder.append(source)
return coder
}

static func open() {
#if compiler(>=5.9) && canImport(AppKit)
if #available(macOS 14, *) {
NSApp.activate()
} else {
NSApp.activate(ignoringOtherApps: true)
}
#else
NSApp.activate(ignoringOtherApps: true)
#endif
NSApp.orderFrontStandardAboutPanel(options: [
.credits: credits,
])
}
}
38 changes: 28 additions & 10 deletionsCoder Desktop/Coder Desktop/Coder_DesktopApp.swift
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import SwiftUI
import FluidMenuBarExtra
import SwiftUI

@main
struct DesktopApp: App {
Expand All@@ -10,21 +10,39 @@ struct DesktopApp: App {
MenuBarExtra("", isInserted: $hidden) {
EmptyView()
}
Window("Sign In", id: Windows.login.rawValue) {
LoginForm<PreviewClient, PreviewSession>()
}.environmentObject(appDelegate.session)
.environmentObject(appDelegate.client)
.windowResizability(.contentSize)
}
}

class AppDelegate: NSObject, NSApplicationDelegate {
private var menuBarExtra: FluidMenuBarExtra?
// TODO: Replace with real implementations
private var vpn = PreviewVPN()
private var session = PreviewSession()
let vpn: PreviewVPN
let session: PreviewSession
let client: PreviewClient

override init() {
// TODO: Replace with real implementations
client = PreviewClient()
vpn = PreviewVPN()
session = PreviewSession()
}

func applicationDidFinishLaunching(_ notification: Notification) {
self.menuBarExtra = FluidMenuBarExtra(title: "Coder Desktop", image: "MenuBarIcon") {
VPNMenu(
vpn: self.vpn,
session: self.session
).frame(width: 256)
func applicationDidFinishLaunching(_: Notification) {
if session.hasSession {
client.initialise(url: session.baseAccessURL!, token: session.sessionToken)
}
menuBarExtra = FluidMenuBarExtra(title: "Coder Desktop", image: "MenuBarIcon") {
VPNMenu<PreviewVPN, PreviewSession>().frame(width: 256)
.environmentObject(self.vpn)
.environmentObject(self.session)
}
}

func applicationShouldTerminateAfterLastWindowClosed(_: NSApplication) -> Bool {
false
}
}
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
import SwiftUI

class PreviewClient: Client {
required init() {}
func initialise(url _: URL, token _: String?) {}

func user(_: String) async throws -> User {
try await Task.sleep(for: .seconds(1))
return User(
id: UUID(),
username: "admin",
avatar_url: "",
name: "admin",
email: "admin@coder.com",
created_at: Date.now,
updated_at: Date.now,
last_seen_at: Date.now,
status: "active",
login_type: "none",
theme_preference: "dark",
organization_ids: [],
roles: []
)
}
}
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,15 +11,14 @@ class PreviewSession: Session {
baseAccessURL = nil
}

funclogin(baseAccessURL: URL, sessionToken: String) {
funcstore(baseAccessURL: URL, sessionToken: String) {
hasSession = true
self.baseAccessURL = baseAccessURL
self.sessionToken = sessionToken
}

funclogout() {
funcclear() {
hasSession = false
self.baseAccessURL = nil
self.sessionToken = nil
sessionToken = nil
}
}
10 changes: 4 additions & 6 deletionsCoder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,15 +5,13 @@ class PreviewVPN: Coder_Desktop.VPNService {
@Published var agents: [Coder_Desktop.Agent] = [
Agent(id: UUID(), name: "dogfood2", status: .error, copyableDNS: "asdf.coder", workspaceName: "dogfood2"),
Agent(id: UUID(), name: "testing-a-very-long-name", status: .okay, copyableDNS: "asdf.coder",
workspaceName: "testing-a-very-long-name"
),
workspaceName: "testing-a-very-long-name"),
Agent(id: UUID(), name: "opensrc", status: .warn, copyableDNS: "asdf.coder", workspaceName: "opensrc"),
Agent(id: UUID(), name: "gvisor", status: .off, copyableDNS: "asdf.coder", workspaceName: "gvisor"),
Agent(id: UUID(), name: "example", status: .off, copyableDNS: "asdf.coder", workspaceName: "example"),
Agent(id: UUID(), name: "dogfood2", status: .error, copyableDNS: "asdf.coder", workspaceName: "dogfood2"),
Agent(id: UUID(), name: "testing-a-very-long-name", status: .okay, copyableDNS: "asdf.coder",
workspaceName: "testing-a-very-long-name"
),
workspaceName: "testing-a-very-long-name"),
Agent(id: UUID(), name: "opensrc", status: .warn, copyableDNS: "asdf.coder", workspaceName: "opensrc"),
Agent(id: UUID(), name: "gvisor", status: .off, copyableDNS: "asdf.coder", workspaceName: "gvisor"),
Agent(id: UUID(), name: "example", status: .off, copyableDNS: "asdf.coder", workspaceName: "example"),
Expand All@@ -33,7 +31,7 @@ class PreviewVPN: Coder_Desktop.VPNService {
func start() async {
await setState(.connecting)
do {
try await Task.sleep(nanoseconds: 1000000000)
try await Task.sleep(for: .seconds(1))
} catch {
await setState(.failed(.exampleError))
return
Expand All@@ -49,7 +47,7 @@ class PreviewVPN: Coder_Desktop.VPNService {
guard state == .connected else { return }
await setState(.disconnecting)
do {
try await Task.sleep(nanoseconds: 1000000000) // Simulate network delay
try await Task.sleep(for: .seconds(1))
} catch {
await setState(.failed(.exampleError))
return
Expand Down
65 changes: 65 additions & 0 deletionsCoder Desktop/Coder Desktop/SDK/Client.swift
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
import Alamofire
import Foundation

protocol Client: ObservableObject {
func initialise(url: URL, token: String?)
func user(_ ident: String) async throws -> User
}

class CoderClient: Client {
public var url: URL!
public var token: String?

let decoder: JSONDecoder
let encoder: JSONEncoder

required init() {
encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withOptionalFractionalSeconds
}

func initialise(url: URL, token: String? = nil) {
self.token = token
self.url = url
}

func request<T: Encodable>(
_ path: String,
method: HTTPMethod,
body: T
) async -> DataResponse<Data, AFError> {
let url = self.url.appendingPathComponent(path)
let headers: HTTPHeaders = [Headers.sessionToken: token ?? ""]
return await AF.request(
url,
method: method,
parameters: body,
encoder: JSONParameterEncoder.default,
headers: headers
).serializingData().response
}

func request(
_ path: String,
method: HTTPMethod
) async -> DataResponse<Data, AFError> {
let url = self.url.appendingPathComponent(path)
let headers: HTTPHeaders = [Headers.sessionToken: token ?? ""]
return await AF.request(
url,
method: method,
headers: headers
).serializingData().response
}
}

enum ClientError: Error {
case unexpectedStatusCode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
case unexpectedStatusCode
case unexpectedStatusCode(Int)

This lets you store the status code

case badResponse
}

enum Headers {
static let sessionToken = "Coder-Session-Token"
}
30 changes: 30 additions & 0 deletionsCoder Desktop/Coder Desktop/SDK/Date.swift
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
import Foundation

// Handling for ISO8601 Timestamps with fractional seconds
// Directly from https://stackoverflow.com/questions/46458487/

extension ParseStrategy where Self == Date.ISO8601FormatStyle {
static var iso8601withFractionalSeconds: Self { .init(includingFractionalSeconds: true) }
}

extension JSONDecoder.DateDecodingStrategy {
static let iso8601withOptionalFractionalSeconds = custom {
let string = try $0.singleValueContainer().decode(String.self)
do {
return try .init(string, strategy: .iso8601withFractionalSeconds)
} catch {
return try .init(string, strategy: .iso8601)
}
}
}

extension FormatStyle where Self == Date.ISO8601FormatStyle {
static var iso8601withFractionalSeconds: Self { .init(includingFractionalSeconds: true) }
}

extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode($0.formatted(.iso8601withFractionalSeconds))
}
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp