Merge remote-tracking branch 'origin/main' into SaaS

# Conflicts:
#	frontend/editor/src/core/components/shared/AppConfigModal.tsx
This commit is contained in:
Anthony Stirling
2026-06-10 10:51:06 +01:00
143 changed files with 28540 additions and 984 deletions
@@ -3,6 +3,7 @@
*/
import { describe, test, expect } from "vitest";
import { expectConsole } from "@app/tests/failOnConsole";
import {
convertToAutomationConfig,
convertToFolderScanningConfig,
@@ -111,6 +112,7 @@ describe("automationConverter", () => {
});
test("falls back to operation key when no endpoint is registered", () => {
expectConsole.warn(/No endpoint found for operation "unknownTool"/);
const automation: AutomationConfig = {
...sampleAutomation,
operations: [{ operation: "unknownTool", parameters: {} }],
@@ -6,8 +6,9 @@
* injected via setScarfConfig() which should be called from a React hook
* during app initialization.
*
* IMPORTANT: setScarfConfig() must be called before firePixel() will work.
* The initialization hook (useScarfTracking) is mounted in App.tsx.
* firePixel() can be called BEFORE setScarfConfig() runs: pre-config calls
* are queued and replayed once setScarfConfig fires, so the initial-page-load
* pixel from useUrlSync doesn't race the useScarfTracking init effect.
*
* For testing: Use resetScarfConfig() to clear module state between tests.
*/
@@ -19,6 +20,11 @@ let isServiceAccepted: ((service: string, category: string) => boolean) | null =
null;
let lastFiredPathname: string | null = null;
let lastFiredTime = 0;
// Pathnames passed to firePixel() before setScarfConfig() has run. Drained
// once configured. Bounded to the most recent few entries since intermediate
// path changes during a slow init are uninteresting.
const pendingPaths: string[] = [];
const PENDING_PATHS_CAP = 8;
/**
* Configure scarf tracking with app config and consent checker
@@ -34,6 +40,10 @@ export function setScarfConfig(
configured = true;
enableScarf = scarfEnabled;
isServiceAccepted = consentChecker;
// Drain anything queued before we were configured. Splice first so a
// re-entrant firePixel from inside the drain can't re-queue.
const queued = pendingPaths.splice(0);
for (const path of queued) firePixel(path);
}
/**
@@ -47,12 +57,10 @@ export function setScarfConfig(
* @param pathname - The pathname to track (usually window.location.pathname)
*/
export function firePixel(pathname: string): void {
// Dev-mode warning if called before initialization
// Pre-init: queue and bail. setScarfConfig() drains.
if (!configured) {
console.warn(
"[scarfTracking] firePixel() called before setScarfConfig(). " +
"Ensure useScarfTracking() hook is mounted in App.tsx.",
);
if (pendingPaths.length >= PENDING_PATHS_CAP) pendingPaths.shift();
pendingPaths.push(pathname);
return;
}
@@ -91,8 +99,10 @@ export function firePixel(pathname: string): void {
* Useful for testing to ensure clean state between test runs
*/
export function resetScarfConfig(): void {
configured = false;
enableScarf = null;
isServiceAccepted = null;
lastFiredPathname = null;
lastFiredTime = 0;
pendingPaths.length = 0;
}
+4 -22
View File
@@ -4,34 +4,16 @@ import { TFunction } from "i18next";
export const getSynonyms = (t: TFunction, toolId: string): string[] => {
try {
const candidateKeys = [`home.${toolId}.tags`, `${toolId}.tags`];
const match = candidateKeys
const tags = candidateKeys
.map((key) => ({ key, value: t(key) as unknown as string }))
.find(({ key, value }) => value && value !== key);
const tags = match?.value;
const usedKey = match?.key;
.find(({ key, value }) => value && value !== key)?.value;
if (!tags) {
console.warn(`[Tags] Missing tags for tool: ${toolId}`);
return [];
}
if (!tags) return [];
// Split by comma and clean up the tags
const cleanedTags = tags
return tags
.split(",")
.map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0);
// Log the tags found for this tool
if (cleanedTags.length > 0) {
console.info(
`[Tags] Tool "${toolId}" (${usedKey}) has ${cleanedTags.length} tags:`,
cleanedTags,
);
} else {
console.warn(`[Tags] Tool "${toolId}" has empty tags value`);
}
return cleanedTags;
} catch (error) {
console.error(
`[Tags] Failed to get translated synonyms for tool ${toolId}:`,