fix: add flow conversation token scope (#8903)

* fix: add flow conversation token scope

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: make flow conversations scope plural

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: update flow chat service import

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
centdix
2026-04-22 15:42:22 +02:00
committed by GitHub
parent 1e83278fe2
commit aea74445a3
4 changed files with 63 additions and 9 deletions
+49 -1
View File
@@ -241,6 +241,7 @@ pub enum ScopeDomain {
Jobs,
Scripts,
Flows,
FlowConversations,
Apps,
Variables,
Resources,
@@ -300,6 +301,7 @@ impl ScopeDomain {
Self::Jobs => "jobs",
Self::Scripts => "scripts",
Self::Flows => "flows",
Self::FlowConversations => "flow_conversations",
Self::Apps => "apps",
Self::Variables => "variables",
Self::Resources => "resources",
@@ -348,6 +350,7 @@ impl ScopeDomain {
"jobs" | "jobs_u" => Some(Self::Jobs),
"scripts" => Some(Self::Scripts),
"flows" => Some(Self::Flows),
"flow_conversations" => Some(Self::FlowConversations),
"apps" | "apps_u" => Some(Self::Apps),
"variables" => Some(Self::Variables),
"resources" => Some(Self::Resources),
@@ -764,6 +767,12 @@ mod tests {
assert_eq!(domain, ScopeDomain::Scripts);
assert_eq!(kind, None);
assert_eq!(route_suffix, Some("scripts/test_script".to_string()));
let (domain, kind, route_suffix) =
extract_domain_from_route("/api/w/test_workspace/flow_conversations/list").unwrap();
assert_eq!(domain, ScopeDomain::FlowConversations);
assert_eq!(kind, None);
assert_eq!(route_suffix, Some("flow_conversations/list".to_string()));
}
#[test]
@@ -788,11 +797,50 @@ mod tests {
ScopeDomain::from_str("agent_workers"),
Some(ScopeDomain::AgentWorkers)
);
assert_eq!(
ScopeDomain::from_str("flow_conversations"),
Some(ScopeDomain::FlowConversations)
);
// Test that string conversion works both ways
// Test canonical string conversion
assert_eq!(ScopeDomain::Acls.as_str(), "acls");
assert_eq!(ScopeDomain::RawApps.as_str(), "raw_apps");
assert_eq!(ScopeDomain::AgentWorkers.as_str(), "agent_workers");
assert_eq!(
ScopeDomain::FlowConversations.as_str(),
"flow_conversations"
);
}
#[test]
fn test_flow_conversations_scope_access() {
let read_scopes = vec!["flow_conversations:read".to_string()];
assert!(check_route_access(
&read_scopes,
"/api/w/test_workspace/flow_conversations/list",
"GET"
)
.is_ok());
assert!(check_route_access(
&read_scopes,
"/api/w/test_workspace/flow_conversations/123/messages",
"GET"
)
.is_ok());
assert!(check_route_access(
&read_scopes,
"/api/w/test_workspace/flow_conversations/delete/123",
"DELETE"
)
.is_err());
let write_scopes = vec!["flow_conversations:write".to_string()];
assert!(check_route_access(
&write_scopes,
"/api/w/test_workspace/flow_conversations/delete/123",
"DELETE"
)
.is_ok());
}
#[test]
+3 -3
View File
@@ -9391,7 +9391,7 @@ paths:
summary: list flow conversations
operationId: listFlowConversations
tags:
- flow_conversation
- flow_conversations
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Page"
@@ -9416,7 +9416,7 @@ paths:
summary: delete flow conversation
operationId: deleteFlowConversation
tags:
- flow_conversation
- flow_conversations
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- name: conversation_id
@@ -9439,7 +9439,7 @@ paths:
summary: list conversation messages
operationId: listConversationMessages
tags:
- flow_conversation
- flow_conversations
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Page"
+6
View File
@@ -65,6 +65,12 @@ fn build_standard_scope_domains() -> Vec<ScopeDomain> {
"Access to automation scripts and workflows",
true,
),
(
"flow_conversations",
"Flow Conversations",
"Flow conversation management",
false,
),
("apps", "Apps", "App management", true),
("raw_apps", "RawApps", "Raw app management", true),
("resources", "Resources", "Resource management", true),
@@ -1,5 +1,5 @@
import type { FlowConversation, FlowConversationMessage } from '$lib/gen/types.gen'
import { FlowConversationService, JobService } from '$lib/gen'
import { FlowConversationsService, JobService } from '$lib/gen'
import { sendUserToast } from '$lib/toast'
import { waitJob } from '$lib/components/waitJob'
import { tick } from 'svelte'
@@ -167,7 +167,7 @@ export class FlowChatManager {
private async deleteConversation(conversationId: string) {
try {
this.deletingConversationId = conversationId
await FlowConversationService.deleteFlowConversation({
await FlowConversationsService.deleteFlowConversation({
workspace: get(workspaceStore)!,
conversationId
})
@@ -217,7 +217,7 @@ export class FlowChatManager {
if (!get(workspaceStore) || !this.#path) return []
try {
const response = await FlowConversationService.listFlowConversations({
const response = await FlowConversationsService.listFlowConversations({
workspace: get(workspaceStore)!,
flowPath: this.#path,
page: page,
@@ -252,7 +252,7 @@ export class FlowChatManager {
try {
const previousScrollHeight = this.messagesContainer?.scrollHeight || 0
const response = await FlowConversationService.listConversationMessages({
const response = await FlowConversationsService.listConversationMessages({
workspace: get(workspaceStore)!,
conversationId: conversationIdToUse,
page: pageToFetch,
@@ -339,7 +339,7 @@ export class FlowChatManager {
try {
const lastId = this.messages[this.messages.length - 1].id
const response = await FlowConversationService.listConversationMessages({
const response = await FlowConversationsService.listConversationMessages({
workspace: get(workspaceStore)!,
conversationId: conversationId,
page: 1,