Fix which server the iPhone Action button uses
This commit is contained in:
@@ -140,10 +140,6 @@ struct PhoneView: View {
|
|||||||
.environment(overlays)
|
.environment(overlays)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: Binding(get: { QuickRunRequest.shared.shown }, set: { QuickRunRequest.shared.shown = $0 })) {
|
|
||||||
QuickRunPage()
|
|
||||||
.environment(store)
|
|
||||||
}
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
store.paneFocus.attach()
|
store.paneFocus.attach()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,16 +116,46 @@ struct ByreShortcuts: AppShortcutsProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private struct QuickRunChoice {
|
||||||
|
let origin: String
|
||||||
|
let store: Store
|
||||||
|
let overlays: Overlays
|
||||||
|
let run: Components.Schemas.QuickRun
|
||||||
|
|
||||||
|
var project: String {
|
||||||
|
store.projects.first { $0.id == run.projectId }?.name ?? run.projectId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct QuickRunPage: View {
|
struct QuickRunPage: View {
|
||||||
@Environment(Store.self) private var store
|
@ViewState private var picked: String?
|
||||||
@ViewState private var text = ""
|
@ViewState private var text = ""
|
||||||
@ViewState private var starting = false
|
@ViewState private var starting = false
|
||||||
@ViewState private var failure: String?
|
@ViewState private var failure: String?
|
||||||
@FocusState private var focused: Bool
|
@FocusState private var focused: Bool
|
||||||
|
|
||||||
|
private var choices: [QuickRunChoice] {
|
||||||
|
Servers.shared.origins.compactMap { origin in
|
||||||
|
guard let connection = Servers.shared.connections[origin], let store = connection.store, let run = store.me?.quickRun, !run.workflow.isEmpty else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return QuickRunChoice(origin: origin, store: store, overlays: connection.overlays, run: run)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var connecting: Bool {
|
||||||
|
Servers.shared.connections.values.contains {
|
||||||
|
if case .starting = $0.phase {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let q = store.me?.quickRun ?? .init(projectId: "", workflow: "")
|
let choices = choices
|
||||||
let project = store.projects.first { $0.id == q.projectId }
|
let choice = choices.first { $0.origin == picked } ?? (choices.count == 1 ? choices.first : nil)
|
||||||
let prompt = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
let prompt = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
HStack {
|
HStack {
|
||||||
@@ -134,29 +164,55 @@ struct QuickRunPage: View {
|
|||||||
}
|
}
|
||||||
.disabled(starting)
|
.disabled(starting)
|
||||||
Spacer()
|
Spacer()
|
||||||
if !q.workflow.isEmpty {
|
if let choice {
|
||||||
Button("Start") {
|
Button("Start") {
|
||||||
start(q, prompt)
|
start(choice, prompt)
|
||||||
}
|
}
|
||||||
.buttonStyle(WebButtonStyle(primary: true))
|
.buttonStyle(WebButtonStyle(primary: true))
|
||||||
.disabled(prompt.isEmpty || starting)
|
.disabled(prompt.isEmpty || starting)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.font(Fonts.font(15, weight: 700))
|
.font(Fonts.font(15, weight: 700))
|
||||||
if q.workflow.isEmpty {
|
if let choice {
|
||||||
Text("Choose the workflow the Action button starts in More → Settings.")
|
|
||||||
.foregroundStyle(Palette.muted)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
} else {
|
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
Text(q.workflow)
|
Text(choice.run.workflow)
|
||||||
.font(Fonts.font(17, weight: 700))
|
.font(Fonts.font(17, weight: 700))
|
||||||
Text(project?.name ?? q.projectId)
|
Text("\(choice.project) · \(serverName(choice.origin))")
|
||||||
.foregroundStyle(Palette.muted)
|
.foregroundStyle(Palette.muted)
|
||||||
}
|
}
|
||||||
AgentEditor(text: $text, placeholder: "What should it do?", key: "quick-run", height: 220, focus: $focused, border: focused ? Palette.accent : Palette.border) {
|
AgentEditor(text: $text, placeholder: "What should it do?", key: "quick-run", height: 220, focus: $focused, border: focused ? Palette.accent : Palette.border) {
|
||||||
start(q, prompt)
|
start(choice, prompt)
|
||||||
}
|
}
|
||||||
|
.environment(choice.store)
|
||||||
|
.environment(choice.overlays)
|
||||||
|
.onAppear {
|
||||||
|
focused = true
|
||||||
|
}
|
||||||
|
} else if !choices.isEmpty {
|
||||||
|
ForEach(choices, id: \.origin) { c in
|
||||||
|
Button {
|
||||||
|
picked = c.origin
|
||||||
|
} label: {
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text(c.run.workflow)
|
||||||
|
.font(Fonts.font(17, weight: 700))
|
||||||
|
Text("\(c.project) · \(serverName(c.origin))")
|
||||||
|
.foregroundStyle(Palette.muted)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(12)
|
||||||
|
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Servers.shared.color(c.origin)))
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
} else if connecting {
|
||||||
|
Text("Connecting to your servers…")
|
||||||
|
.foregroundStyle(Palette.muted)
|
||||||
|
} else {
|
||||||
|
Text("Choose the workflow the Action button starts in More → Settings.")
|
||||||
|
.foregroundStyle(Palette.muted)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
if let failure {
|
if let failure {
|
||||||
Text(failure)
|
Text(failure)
|
||||||
@@ -172,12 +228,9 @@ struct QuickRunPage: View {
|
|||||||
.tint(Palette.accent)
|
.tint(Palette.accent)
|
||||||
.background(Palette.bg)
|
.background(Palette.bg)
|
||||||
.font(Fonts.font(13))
|
.font(Fonts.font(13))
|
||||||
.onAppear {
|
|
||||||
focused = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func start(_ q: Components.Schemas.QuickRun, _ prompt: String) {
|
private func start(_ choice: QuickRunChoice, _ prompt: String) {
|
||||||
if prompt.isEmpty || starting {
|
if prompt.isEmpty || starting {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -185,9 +238,10 @@ struct QuickRunPage: View {
|
|||||||
failure = nil
|
failure = nil
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
let task = try await store.api.client.createTask(path: .init(projectId: q.projectId), body: .json(.init(prompt: prompt, workflow: q.workflow))).created.body.json
|
let task = try await choice.store.api.client.createTask(path: .init(projectId: choice.run.projectId), body: .json(.init(prompt: prompt, workflow: choice.run.workflow))).created.body.json
|
||||||
close()
|
close()
|
||||||
store.focusTask(task.id)
|
Servers.shared.current = choice.origin
|
||||||
|
choice.store.focusTask(task.id)
|
||||||
} catch {
|
} catch {
|
||||||
starting = false
|
starting = false
|
||||||
failure = errorText(error)
|
failure = errorText(error)
|
||||||
@@ -196,6 +250,7 @@ struct QuickRunPage: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func close() {
|
private func close() {
|
||||||
|
picked = nil
|
||||||
text = ""
|
text = ""
|
||||||
starting = false
|
starting = false
|
||||||
failure = nil
|
failure = nil
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ struct SettingsView: View {
|
|||||||
try await store.api.client.updateDefaultModel(body: .json(.init(model: m))).ok.body.json
|
try await store.api.client.updateDefaultModel(body: .json(.init(model: m))).ok.body.json
|
||||||
}
|
}
|
||||||
heading("Action button workflow")
|
heading("Action button workflow")
|
||||||
Text("The iPhone's Action button, set to byre's Run workflow shortcut, opens a page to type a prompt and start this workflow with it.")
|
Text("The iPhone's Action button, set to byre's Run workflow shortcut, opens a page to type a prompt and start this workflow with it. When more than one server has one set, the page asks which to start.")
|
||||||
.foregroundStyle(Palette.muted)
|
.foregroundStyle(Palette.muted)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
QuickRunSetting()
|
QuickRunSetting()
|
||||||
|
|||||||
@@ -584,6 +584,9 @@ struct ServerWindow: View {
|
|||||||
.tint(Palette.accent)
|
.tint(Palette.accent)
|
||||||
.background(Palette.bg)
|
.background(Palette.bg)
|
||||||
.font(Fonts.font(13))
|
.font(Fonts.font(13))
|
||||||
|
.fullScreenCover(isPresented: Binding(get: { QuickRunRequest.shared.shown }, set: { QuickRunRequest.shared.shown = $0 })) {
|
||||||
|
QuickRunPage()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user