Fix AI chat threads query firing for users without AI permissions (#19507)
<img width="1511" height="825" alt="Capture d’écran 2026-04-09 à 14 19 52" src="https://github.com/user-attachments/assets/cd6c533e-abc9-45f9-b5c1-5cb7341d5dfe" /> - Move GetChatThreads query from the generic metadata pipeline (useLoadStaleMetadataEntities) into AgentChatThreadInitializationEffect, gated by useHasPermissionFlag(AI_SETTINGS) — prevents "Entity does not have permissions" errors for users whose role lacks AI access - Fix initialization bug where isDefined(currentAIChatThread) always returned true for the 'unknown-thread' sentinel value, preventing thread initialization from ever running — replaced with isValidUuid check
This commit is contained in:
+52
-7
@@ -1,6 +1,6 @@
|
||||
import { useAtomValue, useStore } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined, isValidUuid } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
AGENT_CHAT_NEW_THREAD_DRAFT_KEY,
|
||||
@@ -14,13 +14,26 @@ import { currentAIChatThreadState } from '@/ai/states/currentAIChatThreadState';
|
||||
import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState';
|
||||
import { hasInitializedAgentChatThreadsState } from '@/ai/states/hasInitializedAgentChatThreadsState';
|
||||
import { hasTriggeredCreateForDraftState } from '@/ai/states/hasTriggeredCreateForDraftState';
|
||||
import { useUpdateMetadataStoreDraft } from '@/metadata-store/hooks/useUpdateMetadataStoreDraft';
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { type FlatAgentChatThread } from '@/metadata-store/types/FlatAgentChatThread';
|
||||
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import {
|
||||
GetChatThreadsDocument,
|
||||
PermissionFlagType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const AgentChatThreadInitializationEffect = () => {
|
||||
const client = useApolloClient();
|
||||
const { replaceDraft, applyChanges } = useUpdateMetadataStoreDraft();
|
||||
const hasAiSettingsPermission = useHasPermissionFlag(
|
||||
PermissionFlagType.AI_SETTINGS,
|
||||
);
|
||||
|
||||
const currentAIChatThread = useAtomStateValue(currentAIChatThreadState);
|
||||
const setCurrentAIChatThread = useSetAtomState(currentAIChatThreadState);
|
||||
const setAgentChatInput = useSetAtomState(agentChatInputState);
|
||||
@@ -40,15 +53,46 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
useAtomState(hasInitializedAgentChatThreadsState);
|
||||
|
||||
useEffect(() => {
|
||||
setAgentChatThreadsLoading(storeEntry.status === 'empty');
|
||||
}, [storeEntry.status, setAgentChatThreadsLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasInitializedAgentChatThreads || isDefined(currentAIChatThread)) {
|
||||
if (storeEntry.status !== 'empty' || !hasAiSettingsPermission) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (storeEntry.status === 'empty') {
|
||||
client
|
||||
.query({
|
||||
query: GetChatThreadsDocument,
|
||||
variables: { paging: { first: 500 } },
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
if (!isDefined(result.data?.chatThreads?.edges)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const threads = result.data.chatThreads.edges.map((edge) => edge.node);
|
||||
|
||||
replaceDraft('agentChatThreads', threads);
|
||||
applyChanges();
|
||||
});
|
||||
}, [
|
||||
storeEntry.status,
|
||||
hasAiSettingsPermission,
|
||||
client,
|
||||
replaceDraft,
|
||||
applyChanges,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setAgentChatThreadsLoading(
|
||||
storeEntry.status === 'empty' && hasAiSettingsPermission,
|
||||
);
|
||||
}, [storeEntry.status, hasAiSettingsPermission, setAgentChatThreadsLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasInitializedAgentChatThreads || isValidUuid(currentAIChatThread)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (storeEntry.status === 'empty' && hasAiSettingsPermission) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -99,6 +143,7 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
}, [
|
||||
agentChatThreads,
|
||||
currentAIChatThread,
|
||||
hasAiSettingsPermission,
|
||||
hasInitializedAgentChatThreads,
|
||||
setHasInitializedAgentChatThreads,
|
||||
storeEntry.status,
|
||||
|
||||
+1
-27
@@ -5,12 +5,10 @@ import { splitPageLayoutWithRelated } from '@/metadata-store/utils/splitPageLayo
|
||||
import { splitViewWithRelated } from '@/metadata-store/utils/splitViewWithRelated';
|
||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||
import { transformPageLayout } from '@/page-layout/utils/transformPageLayout';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
FindAllViewsDocument,
|
||||
FindManyCommandMenuItemsDocument,
|
||||
FindAllRecordPageLayoutsDocument,
|
||||
@@ -18,7 +16,6 @@ import {
|
||||
FindManyFrontComponentsDocument,
|
||||
FindManyLogicFunctionsDocument,
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
GetChatThreadsDocument,
|
||||
type ObjectMetadataItemsQuery,
|
||||
ViewType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
@@ -56,7 +53,6 @@ const hasOverlap = (
|
||||
export const useLoadStaleMetadataEntities = () => {
|
||||
const client = useApolloClient();
|
||||
const { replaceDraft, applyChanges } = useUpdateMetadataStoreDraft();
|
||||
const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
|
||||
|
||||
const loadStaleMetadataEntities = useCallback(
|
||||
async (staleEntityKeys: MetadataEntityKey[]) => {
|
||||
@@ -226,32 +222,10 @@ export const useLoadStaleMetadataEntities = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (staleEntityKeys.includes('agentChatThreads') && isAiEnabled) {
|
||||
fetchPromises.push(
|
||||
client
|
||||
.query({
|
||||
query: GetChatThreadsDocument,
|
||||
variables: { paging: { first: 500 } },
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
if (!isDefined(result.data?.chatThreads?.edges)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const threads = result.data.chatThreads.edges.map(
|
||||
(edge) => edge.node,
|
||||
);
|
||||
|
||||
replaceDraft('agentChatThreads', threads);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(fetchPromises);
|
||||
applyChanges();
|
||||
},
|
||||
[client, replaceDraft, applyChanges, isAiEnabled],
|
||||
[client, replaceDraft, applyChanges],
|
||||
);
|
||||
|
||||
return { loadStaleMetadataEntities };
|
||||
|
||||
Reference in New Issue
Block a user