tr]:last:border-b-0",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
+ return (
+
+ )
+}
+
+function TableHead({ className, ...props }: React.ComponentProps<"th">) {
+ return (
+ [role=checkbox]]:translate-y-[2px]",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TableCell({ className, ...props }: React.ComponentProps<"td">) {
+ return (
+ | [role=checkbox]]:translate-y-[2px]",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TableCaption({
+ className,
+ ...props
+}: React.ComponentProps<"caption">) {
+ return (
+
+ )
+}
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/turing-shadcn/src/components/ui/tabs.tsx b/turing-shadcn/src/components/ui/tabs.tsx
new file mode 100644
index 00000000000..3d6f3acf86c
--- /dev/null
+++ b/turing-shadcn/src/components/ui/tabs.tsx
@@ -0,0 +1,64 @@
+import * as React from "react"
+import * as TabsPrimitive from "@radix-ui/react-tabs"
+
+import { cn } from "@/lib/utils"
+
+function Tabs({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function TabsList({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function TabsTrigger({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function TabsContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent }
diff --git a/turing-shadcn/src/components/ui/textarea.tsx b/turing-shadcn/src/components/ui/textarea.tsx
new file mode 100644
index 00000000000..7f21b5e78a4
--- /dev/null
+++ b/turing-shadcn/src/components/ui/textarea.tsx
@@ -0,0 +1,18 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
+ return (
+
+ )
+}
+
+export { Textarea }
diff --git a/turing-shadcn/src/components/ui/toggle-group.tsx b/turing-shadcn/src/components/ui/toggle-group.tsx
new file mode 100644
index 00000000000..24a4850d73e
--- /dev/null
+++ b/turing-shadcn/src/components/ui/toggle-group.tsx
@@ -0,0 +1,83 @@
+"use client"
+
+import * as React from "react"
+import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
+import { type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+import { toggleVariants } from "@/components/ui/toggle"
+
+const ToggleGroupContext = React.createContext<
+ VariantProps & {
+ spacing?: number
+ }
+>({
+ size: "default",
+ variant: "default",
+ spacing: 0,
+})
+
+function ToggleGroup({
+ className,
+ variant,
+ size,
+ spacing = 0,
+ children,
+ ...props
+}: React.ComponentProps &
+ VariantProps & {
+ spacing?: number
+ }) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+function ToggleGroupItem({
+ className,
+ children,
+ variant,
+ size,
+ ...props
+}: React.ComponentProps &
+ VariantProps) {
+ const context = React.useContext(ToggleGroupContext)
+
+ return (
+
+ {children}
+
+ )
+}
+
+export { ToggleGroup, ToggleGroupItem }
diff --git a/turing-shadcn/src/components/ui/toggle.tsx b/turing-shadcn/src/components/ui/toggle.tsx
new file mode 100644
index 00000000000..2e13faf69bc
--- /dev/null
+++ b/turing-shadcn/src/components/ui/toggle.tsx
@@ -0,0 +1,46 @@
+/* eslint-disable react-refresh/only-export-components */
+import * as React from "react"
+import * as TogglePrimitive from "@radix-ui/react-toggle"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const toggleVariants = cva(
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
+ {
+ variants: {
+ variant: {
+ default: "bg-transparent",
+ outline:
+ "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
+ },
+ size: {
+ default: "h-9 px-2 min-w-9",
+ sm: "h-8 px-1.5 min-w-8",
+ lg: "h-10 px-2.5 min-w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+function Toggle({
+ className,
+ variant,
+ size,
+ ...props
+}: React.ComponentProps &
+ VariantProps) {
+ return (
+
+ )
+}
+
+export { Toggle, toggleVariants }
diff --git a/turing-shadcn/src/components/ui/tooltip.tsx b/turing-shadcn/src/components/ui/tooltip.tsx
new file mode 100644
index 00000000000..715bf76d6ba
--- /dev/null
+++ b/turing-shadcn/src/components/ui/tooltip.tsx
@@ -0,0 +1,59 @@
+import * as React from "react"
+import * as TooltipPrimitive from "@radix-ui/react-tooltip"
+
+import { cn } from "@/lib/utils"
+
+function TooltipProvider({
+ delayDuration = 0,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function Tooltip({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function TooltipTrigger({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function TooltipContent({
+ className,
+ sideOffset = 0,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+ {children}
+
+
+
+ )
+}
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
diff --git a/turing-shadcn/src/hooks/use-mobile.ts b/turing-shadcn/src/hooks/use-mobile.ts
new file mode 100644
index 00000000000..2b0fe1dfef3
--- /dev/null
+++ b/turing-shadcn/src/hooks/use-mobile.ts
@@ -0,0 +1,19 @@
+import * as React from "react"
+
+const MOBILE_BREAKPOINT = 768
+
+export function useIsMobile() {
+ const [isMobile, setIsMobile] = React.useState(undefined)
+
+ React.useEffect(() => {
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
+ const onChange = () => {
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
+ }
+ mql.addEventListener("change", onChange)
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
+ return () => mql.removeEventListener("change", onChange)
+ }, [])
+
+ return !!isMobile
+}
diff --git a/turing-shadcn/src/index.css b/turing-shadcn/src/index.css
new file mode 100644
index 00000000000..f4c1e9b51d3
--- /dev/null
+++ b/turing-shadcn/src/index.css
@@ -0,0 +1,120 @@
+@import "tailwindcss";
+@import "tw-animate-css";
+
+@custom-variant dark (&:is(.dark *));
+
+@theme inline {
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+}
+
+:root {
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
+}
+
+.dark {
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.205 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.922 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.556 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.556 0 0);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/turing-shadcn/src/lib/utils.ts b/turing-shadcn/src/lib/utils.ts
new file mode 100644
index 00000000000..bd0c391ddd1
--- /dev/null
+++ b/turing-shadcn/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/turing-shadcn/src/main.tsx b/turing-shadcn/src/main.tsx
new file mode 100644
index 00000000000..632bf593c2a
--- /dev/null
+++ b/turing-shadcn/src/main.tsx
@@ -0,0 +1,64 @@
+import axios from 'axios'
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { BrowserRouter } from 'react-router-dom'
+import App from './App.tsx'
+import { ROUTES } from './app/routes.const.ts'
+import './index.css'
+import type { TurRestInfo } from './models/auth/rest-info.ts'
+import { TurAuthorizationService } from './services/authorization.service.ts'
+import type { TurDiscoveryAPI } from './models/auth/discovery.ts'
+
+const authorization = new TurAuthorizationService()
+axios.defaults.baseURL = `${import.meta.env.VITE_API_URL}/api`;
+
+// Cache discovery result to avoid repeated API calls
+let discoveryCache: TurDiscoveryAPI | null = null;
+let discoveryPromise: Promise | null = null;
+
+const getDiscovery = async (): Promise => {
+ if (discoveryCache) {
+ return discoveryCache;
+ }
+ if (discoveryPromise) {
+ return discoveryPromise;
+ }
+ discoveryPromise = authorization.discovery().then(result => {
+ discoveryCache = result;
+ discoveryPromise = null;
+ return result;
+ });
+ return discoveryPromise;
+};
+
+axios.interceptors.request.use(async (config) => {
+ config.headers['Content-Type'] = 'application/json';
+ config.headers['X-Requested-With'] = 'XMLHttpRequest';
+ try {
+ const discovery = await getDiscovery();
+ if (!discovery.keycloak) {
+ const token: TurRestInfo = getAuthToken();
+ if (token.authdata) {
+ config.headers.Authorization = `Basic ${token.authdata}`;
+ } else {
+ window.location.href = `${ROUTES.LOGIN}?returnUrl=${ROUTES.CONSOLE}`;
+ }
+ }
+ } catch (error) {
+ console.error('Error during request interception:', error);
+ }
+ return config;
+});
+
+const getAuthToken = (): TurRestInfo => {
+ return JSON.parse(localStorage.getItem('restInfo') || "{}");
+};
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+
+
+)
+
diff --git a/turing-shadcn/src/models/auth/discovery.ts b/turing-shadcn/src/models/auth/discovery.ts
new file mode 100644
index 00000000000..5db0edd3ce6
--- /dev/null
+++ b/turing-shadcn/src/models/auth/discovery.ts
@@ -0,0 +1,5 @@
+export type TurDiscoveryAPI = {
+ product: string;
+ keycloak: boolean;
+ multiTenant: boolean;
+};
diff --git a/turing-shadcn/src/models/auth/rest-info.ts b/turing-shadcn/src/models/auth/rest-info.ts
new file mode 100644
index 00000000000..838cf5b5612
--- /dev/null
+++ b/turing-shadcn/src/models/auth/rest-info.ts
@@ -0,0 +1,10 @@
+export type TurRestInfo = {
+ id: number;
+ username: string;
+ password: string;
+ firstName: string;
+ lastName: string;
+ authdata?: string;
+ admin: boolean;
+ email: string;
+}
\ No newline at end of file
diff --git a/turing-shadcn/src/models/integration/integration-instance.model.ts b/turing-shadcn/src/models/integration/integration-instance.model.ts
new file mode 100644
index 00000000000..4cbf9b7fc1e
--- /dev/null
+++ b/turing-shadcn/src/models/integration/integration-instance.model.ts
@@ -0,0 +1,8 @@
+export type TurIntegrationInstance = {
+ id: string;
+ title: string;
+ description: string;
+ endpoint: string;
+ vendor: string;
+ enabled: number;
+};
diff --git a/turing-shadcn/src/models/llm/llm-instance.model.ts b/turing-shadcn/src/models/llm/llm-instance.model.ts
new file mode 100644
index 00000000000..86145634045
--- /dev/null
+++ b/turing-shadcn/src/models/llm/llm-instance.model.ts
@@ -0,0 +1,23 @@
+import type { TurLLMVendor } from "./llm-vendor.model.ts";
+
+export interface TurLLMInstance {
+ id: string;
+ title: string;
+ description: string;
+ url: string;
+ turLLMVendor: TurLLMVendor;
+ language: string;
+ enabled: number;
+ modelName: string;
+ temperature: number;
+ topK: number;
+ topP: number;
+ repeatPenalty: number;
+ seed: number;
+ numPredict: number;
+ stop: string;
+ responseFormat: string;
+ supportedCapabilities: string;
+ timeout: string;
+ maxRetries: number;
+}
diff --git a/turing-shadcn/src/models/llm/llm-vendor.model.ts b/turing-shadcn/src/models/llm/llm-vendor.model.ts
new file mode 100644
index 00000000000..986543d0e2e
--- /dev/null
+++ b/turing-shadcn/src/models/llm/llm-vendor.model.ts
@@ -0,0 +1,5 @@
+export interface TurLLMVendor {
+ id: string;
+ title: string;
+ description: string;
+}
\ No newline at end of file
diff --git a/turing-shadcn/src/models/locale/locale.model.ts b/turing-shadcn/src/models/locale/locale.model.ts
new file mode 100644
index 00000000000..2cc7ca8275b
--- /dev/null
+++ b/turing-shadcn/src/models/locale/locale.model.ts
@@ -0,0 +1,5 @@
+export type TurLocale = {
+ initials: string;
+ en: string;
+ pt: string;
+};
diff --git a/turing-shadcn/src/models/logging/logging-instance.model.ts b/turing-shadcn/src/models/logging/logging-instance.model.ts
new file mode 100644
index 00000000000..9b7463656d4
--- /dev/null
+++ b/turing-shadcn/src/models/logging/logging-instance.model.ts
@@ -0,0 +1,23 @@
+import type { TurLoggingVendor } from "./logging-vendor.model.ts";
+
+export interface TurLoggingInstance {
+ id: string;
+ title: string;
+ description: string;
+ url: string;
+ turLoggingVendor: TurLoggingVendor;
+ language: string;
+ enabled: number;
+ modelName: string;
+ temperature: number;
+ topK: number;
+ topP: number;
+ repeatPenalty: number;
+ seed: number;
+ numPredict: number;
+ stop: string;
+ responseFormat: string;
+ supportedCapabilities: string;
+ timeout: string;
+ maxRetries: number;
+}
diff --git a/turing-shadcn/src/models/logging/logging-vendor.model.ts b/turing-shadcn/src/models/logging/logging-vendor.model.ts
new file mode 100644
index 00000000000..cc5cae312a0
--- /dev/null
+++ b/turing-shadcn/src/models/logging/logging-vendor.model.ts
@@ -0,0 +1,5 @@
+export interface TurLoggingVendor {
+ id: string;
+ title: string;
+ description: string;
+}
\ No newline at end of file
diff --git a/turing-shadcn/src/models/se/se-instance.model.ts b/turing-shadcn/src/models/se/se-instance.model.ts
new file mode 100644
index 00000000000..47210109c06
--- /dev/null
+++ b/turing-shadcn/src/models/se/se-instance.model.ts
@@ -0,0 +1,12 @@
+import type { TurSEVendor } from "./se-vendor.model.ts";
+
+export interface TurSEInstance {
+ id: string;
+ title: string;
+ description: string;
+ host: string;
+ port: number;
+ turSEVendor: TurSEVendor;
+ language: string;
+ enabled: number;
+}
diff --git a/turing-shadcn/src/models/se/se-vendor.model.ts b/turing-shadcn/src/models/se/se-vendor.model.ts
new file mode 100644
index 00000000000..8c5fe721fc6
--- /dev/null
+++ b/turing-shadcn/src/models/se/se-vendor.model.ts
@@ -0,0 +1,5 @@
+export interface TurSEVendor {
+ id: string;
+ title: string;
+ description: string;
+}
\ No newline at end of file
diff --git a/turing-shadcn/src/models/sn/sn-field-type.model.ts b/turing-shadcn/src/models/sn/sn-field-type.model.ts
new file mode 100644
index 00000000000..b2fc9e1172d
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-field-type.model.ts
@@ -0,0 +1,4 @@
+export type TurSNFieldType = {
+ id: string;
+ name: string;
+};
diff --git a/turing-shadcn/src/models/sn/sn-ranking-condition.model.ts b/turing-shadcn/src/models/sn/sn-ranking-condition.model.ts
new file mode 100644
index 00000000000..7090aa1e417
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-ranking-condition.model.ts
@@ -0,0 +1,6 @@
+export type TurSNRankingCondition = {
+ id: string;
+ attribute: string;
+ condition: number;
+ value: string;
+}
diff --git a/turing-shadcn/src/models/sn/sn-ranking-expression.model.ts b/turing-shadcn/src/models/sn/sn-ranking-expression.model.ts
new file mode 100644
index 00000000000..24b786fa2b0
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-ranking-expression.model.ts
@@ -0,0 +1,10 @@
+import type {TurSNRankingCondition} from "./sn-ranking-condition.model";
+
+export type TurSNRankingExpression = {
+ id: string;
+ name: string;
+ weight: number;
+ turSNRankingConditions: TurSNRankingCondition[];
+ lastModifiedDate: Date;
+ description: string;
+}
diff --git a/turing-shadcn/src/models/sn/sn-site-facet-field-sort.type.ts b/turing-shadcn/src/models/sn/sn-site-facet-field-sort.type.ts
new file mode 100644
index 00000000000..3d2ee45d8b2
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-facet-field-sort.type.ts
@@ -0,0 +1 @@
+ export type TurSNSiteFacetFieldSortTypes = 'DEFAULT' | 'COUNT' | 'ALPHABETICAL';
\ No newline at end of file
diff --git a/turing-shadcn/src/models/sn/sn-site-facet-range.type.ts b/turing-shadcn/src/models/sn/sn-site-facet-range.type.ts
new file mode 100644
index 00000000000..877d8178885
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-facet-range.type.ts
@@ -0,0 +1 @@
+export type TurSNSiteFacetRangeTypes = "DISABLED" |"DAY" |"MONTH" |"YEAR";
diff --git a/turing-shadcn/src/models/sn/sn-site-facet-sort.type.ts b/turing-shadcn/src/models/sn/sn-site-facet-sort.type.ts
new file mode 100644
index 00000000000..6be94da6ded
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-facet-sort.type.ts
@@ -0,0 +1 @@
+export type TurSNSiteFacetSortTypes = "COUNT" | "ALPHABETICAL";
diff --git a/turing-shadcn/src/models/sn/sn-site-facet.field.type.ts b/turing-shadcn/src/models/sn/sn-site-facet.field.type.ts
new file mode 100644
index 00000000000..9652a3aa7bb
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-facet.field.type.ts
@@ -0,0 +1 @@
+export type TurSNSiteFacetFieldTypes = "DEFAULT" | "AND" | "OR";
diff --git a/turing-shadcn/src/models/sn/sn-site-facet.type.ts b/turing-shadcn/src/models/sn/sn-site-facet.type.ts
new file mode 100644
index 00000000000..694954a2d37
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-facet.type.ts
@@ -0,0 +1 @@
+export type TurSNSiteFacetTypes = "AND" | "OR";
diff --git a/turing-shadcn/src/models/sn/sn-site-field-facet.model.ts b/turing-shadcn/src/models/sn/sn-site-field-facet.model.ts
new file mode 100644
index 00000000000..0d8acbc7cbf
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-field-facet.model.ts
@@ -0,0 +1,5 @@
+export type TurSNSiteFieldFacet = {
+ id: string;
+ locale: string;
+ label: string;
+};
diff --git a/turing-shadcn/src/models/sn/sn-site-field.model.ts b/turing-shadcn/src/models/sn/sn-site-field.model.ts
new file mode 100644
index 00000000000..d4d16aece49
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-field.model.ts
@@ -0,0 +1,29 @@
+import type { TurSNSiteFacetFieldSortTypes } from "./sn-site-facet-field-sort.type.ts";
+import type { TurSNSiteFacetRangeTypes } from "./sn-site-facet-range.type.ts";
+import type { TurSNSiteFacetFieldTypes } from "./sn-site-facet.field.type.ts";
+import type { TurSNSiteFieldFacet } from "./sn-site-field-facet.model.ts";
+
+export type TurSNSiteField = {
+ id: string;
+ name: string;
+ description: string;
+ defaultValue: string;
+ enabled: number;
+ externalId: string;
+ facet: number;
+ facetName: string;
+ facetRange: TurSNSiteFacetRangeTypes;
+ facetLocales: TurSNSiteFieldFacet[];
+ facetType: TurSNSiteFacetFieldTypes;
+ facetItemType: TurSNSiteFacetFieldTypes;
+ facetSort: TurSNSiteFacetFieldSortTypes;
+ facetPosition: number;
+ secondaryFacet: boolean;
+ showAllFacetItems: boolean;
+ mlt: number;
+ multiValued: number;
+ required: number;
+ snType: string;
+ type: string;
+ hl: number;
+};
diff --git a/turing-shadcn/src/models/sn/sn-site-genai.model.ts b/turing-shadcn/src/models/sn/sn-site-genai.model.ts
new file mode 100644
index 00000000000..700563cdd38
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-genai.model.ts
@@ -0,0 +1,10 @@
+import type { TurLLMInstance } from "../llm/llm-instance.model.ts";
+import type { TurStoreInstance } from "../store/store-instance.model.ts";
+
+export interface TurSNSiteGenAi {
+ id: string;
+ turLLMInstance: TurLLMInstance;
+ turStoreInstance: TurStoreInstance;
+ enabled: boolean;
+ systemPrompt: string;
+}
diff --git a/turing-shadcn/src/models/sn/sn-site-locale.model.ts b/turing-shadcn/src/models/sn/sn-site-locale.model.ts
new file mode 100644
index 00000000000..89699e62c3d
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-locale.model.ts
@@ -0,0 +1,8 @@
+import type { TurSNSite } from "./sn-site.model.ts";
+
+export type TurSNSiteLocale = {
+ id: string;
+ language: string;
+ core: string;
+ turSNSite: TurSNSite;
+}
\ No newline at end of file
diff --git a/turing-shadcn/src/models/sn/sn-site-merge-field.model.ts b/turing-shadcn/src/models/sn/sn-site-merge-field.model.ts
new file mode 100644
index 00000000000..ea0f643cd8a
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-merge-field.model.ts
@@ -0,0 +1,5 @@
+export type TurSNSiteMergeField = {
+ id?: string;
+ name: string;
+
+}
diff --git a/turing-shadcn/src/models/sn/sn-site-merge.model.ts b/turing-shadcn/src/models/sn/sn-site-merge.model.ts
new file mode 100644
index 00000000000..6a88af63b8d
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-merge.model.ts
@@ -0,0 +1,14 @@
+import type {TurSNSiteMergeField} from "./sn-site-merge-field.model.ts";
+import type {TurSNSite} from "./sn-site.model.ts";
+
+export type TurSNSiteMerge = {
+ id: string;
+ turSNSite: TurSNSite;
+ locale: string;
+ providerFrom: string;
+ providerTo: string;
+ relationFrom: string;
+ relationTo: string;
+ overwrittenFields: TurSNSiteMergeField[];
+ description: string;
+}
diff --git a/turing-shadcn/src/models/sn/sn-site-spotlight-document.model.ts b/turing-shadcn/src/models/sn/sn-site-spotlight-document.model.ts
new file mode 100644
index 00000000000..38a2ae7b872
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-spotlight-document.model.ts
@@ -0,0 +1,9 @@
+export type TurSNSiteSpotlightDocument = {
+ id: string;
+ position: number;
+ title: string;
+ type: string;
+ link: string;
+ referenceId: string;
+ content:string;
+}
diff --git a/turing-shadcn/src/models/sn/sn-site-spotlight-term.model.ts b/turing-shadcn/src/models/sn/sn-site-spotlight-term.model.ts
new file mode 100644
index 00000000000..ad87a215319
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-spotlight-term.model.ts
@@ -0,0 +1,4 @@
+export type TurSNSiteSpotlightTerm = {
+ id: string;
+ name: string;
+}
diff --git a/turing-shadcn/src/models/sn/sn-site-spotlight.model.ts b/turing-shadcn/src/models/sn/sn-site-spotlight.model.ts
new file mode 100644
index 00000000000..279e2db8d5c
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site-spotlight.model.ts
@@ -0,0 +1,14 @@
+import type {TurSNSiteSpotlightDocument} from "./sn-site-spotlight-document.model.ts";
+import type {TurSNSiteSpotlightTerm} from "./sn-site-spotlight-term.model.ts";
+import type {TurSNSite} from "./sn-site.model.ts";
+
+export type TurSNSiteSpotlight = {
+ id: string;
+ name: string;
+ description: string;
+ language: string;
+ modificationDate: Date;
+ turSNSiteSpotlightTerms: TurSNSiteSpotlightTerm[];
+ turSNSiteSpotlightDocuments: TurSNSiteSpotlightDocument[];
+ turSNSite: TurSNSite;
+}
diff --git a/turing-shadcn/src/models/sn/sn-site.model.ts b/turing-shadcn/src/models/sn/sn-site.model.ts
new file mode 100644
index 00000000000..aef85742631
--- /dev/null
+++ b/turing-shadcn/src/models/sn/sn-site.model.ts
@@ -0,0 +1,39 @@
+import type { TurSEInstance } from "../se/se-instance.model.ts";
+import type { TurSNSiteFacetFieldSortTypes } from "./sn-site-facet-field-sort.type.ts";
+import type { TurSNSiteFacetTypes } from "./sn-site-facet.type.ts";
+import type { TurSNSiteGenAi } from "./sn-site-genai.model.ts";
+import type { TurSNSiteLocale } from "./sn-site-locale.model.ts";
+
+export type TurSNSite = {
+ id: string;
+ name: string;
+ description: string;
+ exactMatchField: string;
+ defaultField: string;
+ defaultTitleField: string;
+ defaultDescriptionField: string;
+ defaultTextField: string;
+ defaultDateField: string;
+ defaultImageField: string;
+ defaultURLField: string;
+ facet: number;
+ itemsPerFacet: number;
+ hl: number;
+ hlPre: string;
+ hlPost: string;
+ mlt: number;
+ thesaurus: number;
+ turSEInstance: TurSEInstance;
+ turSNSiteLocales: TurSNSiteLocale[];
+ rowsPerPage: number;
+ spellCheck: number;
+ spellCheckFixes: number;
+ spotlightWithResults: number;
+ facetType: TurSNSiteFacetTypes;
+ facetItemType: TurSNSiteFacetTypes;
+ facetSort: TurSNSiteFacetFieldSortTypes;
+ wildcardNoResults: number;
+ wildcardAlways: number;
+ exactMatch: number;
+ turSNSiteGenAi: TurSNSiteGenAi;
+}
diff --git a/turing-shadcn/src/models/store/store-instance.model.ts b/turing-shadcn/src/models/store/store-instance.model.ts
new file mode 100644
index 00000000000..a8a37b82b44
--- /dev/null
+++ b/turing-shadcn/src/models/store/store-instance.model.ts
@@ -0,0 +1,23 @@
+import type { TurStoreVendor } from "./store-vendor.model.ts";
+
+export interface TurStoreInstance {
+ id: string;
+ title: string;
+ description: string;
+ url: string;
+ turStoreVendor: TurStoreVendor;
+ language: string;
+ enabled: number;
+ modelName: string;
+ temperature: number;
+ topK: number;
+ topP: number;
+ repeatPenalty: number;
+ seed: number;
+ numPredict: number;
+ stop: string;
+ responseFormat: string;
+ supportedCapabilities: string;
+ timeout: string;
+ maxRetries: number;
+}
diff --git a/turing-shadcn/src/models/store/store-vendor.model.ts b/turing-shadcn/src/models/store/store-vendor.model.ts
new file mode 100644
index 00000000000..96eeeffee67
--- /dev/null
+++ b/turing-shadcn/src/models/store/store-vendor.model.ts
@@ -0,0 +1,5 @@
+export interface TurStoreVendor {
+ id: string;
+ title: string;
+ description: string;
+}
\ No newline at end of file
diff --git a/turing-shadcn/src/models/token/token-instance.model.ts b/turing-shadcn/src/models/token/token-instance.model.ts
new file mode 100644
index 00000000000..2be1a90e34c
--- /dev/null
+++ b/turing-shadcn/src/models/token/token-instance.model.ts
@@ -0,0 +1,6 @@
+export type TurTokenInstance = {
+ id: string;
+ token: string;
+ title: string;
+ description: string;
+};
diff --git a/turing-shadcn/src/search/SearchApp.tsx b/turing-shadcn/src/search/SearchApp.tsx
new file mode 100644
index 00000000000..66d590c7b5e
--- /dev/null
+++ b/turing-shadcn/src/search/SearchApp.tsx
@@ -0,0 +1,18 @@
+import { Route, Routes } from "react-router-dom"
+import SearchPage from "./pages/search.page"
+import { ThemeProvider } from "../components/theme-provider"
+import { Toaster } from "../components/ui/sonner"
+
+function SearchApp() {
+ return (
+
+
+
+ } />
+ } />
+
+
+ )
+}
+
+export default SearchApp
diff --git a/turing-shadcn/src/search/main.tsx b/turing-shadcn/src/search/main.tsx
new file mode 100644
index 00000000000..f7ac3570343
--- /dev/null
+++ b/turing-shadcn/src/search/main.tsx
@@ -0,0 +1,19 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { BrowserRouter } from 'react-router-dom'
+import SearchApp from './SearchApp.tsx'
+import '../index.css'
+import axios from 'axios'
+
+axios.defaults.baseURL = `${import.meta.env.VITE_API_URL}`;
+
+// Use basename only in production
+const basename = import.meta.env.MODE === 'production' ? '/sn/templates' : '/';
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+
+
+)
diff --git a/turing-shadcn/src/search/models/sn-chat.model.ts b/turing-shadcn/src/search/models/sn-chat.model.ts
new file mode 100644
index 00000000000..9b637e1b531
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-chat.model.ts
@@ -0,0 +1,4 @@
+export interface TurSNChat {
+ text: string;
+ enabled: boolean;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-default-fields.model.ts b/turing-shadcn/src/search/models/sn-search-default-fields.model.ts
new file mode 100644
index 00000000000..f8e473f25b4
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-default-fields.model.ts
@@ -0,0 +1,9 @@
+
+export interface TurSNSearchDefaultFields {
+ date: string;
+ description: string;
+ image: string;
+ text: string;
+ title: string;
+ url: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-document-field.model.ts b/turing-shadcn/src/search/models/sn-search-document-field.model.ts
new file mode 100644
index 00000000000..931ead7b067
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-document-field.model.ts
@@ -0,0 +1,4 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+export interface TurSNSearchDocumentField {
+ [key: string]: any
+}
diff --git a/turing-shadcn/src/search/models/sn-search-document-metadata.model.ts b/turing-shadcn/src/search/models/sn-search-document-metadata.model.ts
new file mode 100644
index 00000000000..7b394c75adc
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-document-metadata.model.ts
@@ -0,0 +1,4 @@
+export interface TurSNSearchDocumentMetadata {
+ href: string;
+ text: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-document.model.ts b/turing-shadcn/src/search/models/sn-search-document.model.ts
new file mode 100644
index 00000000000..496b56e8bcf
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-document.model.ts
@@ -0,0 +1,8 @@
+import type { TurSNSearchDocumentField } from "./sn-search-document-field.model";
+import type { TurSNSearchDocumentMetadata } from "./sn-search-document-metadata.model";
+
+export interface TurSNSearchDocument {
+ elevate: boolean;
+ fields: TurSNSearchDocumentField;
+ metadata: TurSNSearchDocumentMetadata[];
+}
diff --git a/turing-shadcn/src/search/models/sn-search-facet-item.model.ts b/turing-shadcn/src/search/models/sn-search-facet-item.model.ts
new file mode 100644
index 00000000000..2a8bf802a65
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-facet-item.model.ts
@@ -0,0 +1,6 @@
+export interface TurSNSearchFacetItem {
+ count: number;
+ label: string;
+ link: string;
+ selected: number;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-facet.model.ts b/turing-shadcn/src/search/models/sn-search-facet.model.ts
new file mode 100644
index 00000000000..5a93c9fbc0b
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-facet.model.ts
@@ -0,0 +1,12 @@
+import type { TurSNSearchFacetItem } from "./sn-search-facet-item.model";
+import type { TurSNSearchLabel } from "./sn-search-label.model";
+
+export interface TurSNSearchFacet {
+ facets: TurSNSearchFacetItem[];
+ label: TurSNSearchLabel;
+ name: string;
+ description: string;
+ type: string;
+ multivalued: boolean;
+ cleanUpLink: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-label.model.ts b/turing-shadcn/src/search/models/sn-search-label.model.ts
new file mode 100644
index 00000000000..fa13cadf7cd
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-label.model.ts
@@ -0,0 +1,5 @@
+
+export interface TurSNSearchLabel {
+ lang: string;
+ text: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-locale.model.ts b/turing-shadcn/src/search/models/sn-search-locale.model.ts
new file mode 100644
index 00000000000..3fa5867a6f1
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-locale.model.ts
@@ -0,0 +1,4 @@
+export interface TurSNSearchLocale {
+ locale: string;
+ link: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-pagination-item.model.ts b/turing-shadcn/src/search/models/sn-search-pagination-item.model.ts
new file mode 100644
index 00000000000..529555ccbf6
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-pagination-item.model.ts
@@ -0,0 +1,7 @@
+
+export interface TurSNSearchPaginationItem {
+ href: string;
+ page: number;
+ text: string;
+ type: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-query-context.model.ts b/turing-shadcn/src/search/models/sn-search-query-context.model.ts
new file mode 100644
index 00000000000..3cdb011d049
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-query-context.model.ts
@@ -0,0 +1,18 @@
+import type { TurSNSearchDefaultFields } from "./sn-search-default-fields.model";
+import type { TurSNSearchQuery } from "./sn-search-query.model";
+
+export interface TurSNSearchQueryContext {
+ count: number;
+ defaultFields: TurSNSearchDefaultFields;
+ index: string;
+ limit: number;
+ offset: number;
+ page: number;
+ pageCount: number;
+ pageEnd: number;
+ pageStart: number;
+ query: TurSNSearchQuery;
+ responseTime: number;
+ facetType: string;
+ facetItemType: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-query.model.ts b/turing-shadcn/src/search/models/sn-search-query.model.ts
new file mode 100644
index 00000000000..49b16fb4cf0
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-query.model.ts
@@ -0,0 +1,6 @@
+
+export interface TurSNSearchQuery {
+ queryString: string;
+ sort: string;
+ locale: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-results.model.ts b/turing-shadcn/src/search/models/sn-search-results.model.ts
new file mode 100644
index 00000000000..6628a821881
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-results.model.ts
@@ -0,0 +1,5 @@
+import type { TurSNSearchDocument } from "./sn-search-document.model";
+
+export interface TurSNSearchResults {
+ document: TurSNSearchDocument[];
+}
diff --git a/turing-shadcn/src/search/models/sn-search-spell-check-text.model.ts b/turing-shadcn/src/search/models/sn-search-spell-check-text.model.ts
new file mode 100644
index 00000000000..1ab12baeae3
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-spell-check-text.model.ts
@@ -0,0 +1,4 @@
+export interface TurSNSearchSpellCheckText {
+ link: string;
+ text: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-spell-check.model.ts b/turing-shadcn/src/search/models/sn-search-spell-check.model.ts
new file mode 100644
index 00000000000..0720bcd8e68
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-spell-check.model.ts
@@ -0,0 +1,8 @@
+import type { TurSNSearchSpellCheckText } from "./sn-search-spell-check-text.model";
+
+export interface TurSNSearchSpellCheck {
+ original: TurSNSearchSpellCheckText;
+ corrected: TurSNSearchSpellCheckText;
+ correctedText: boolean;
+ usingCorrectedText: boolean;
+}
diff --git a/turing-shadcn/src/search/models/sn-search-widget.model.ts b/turing-shadcn/src/search/models/sn-search-widget.model.ts
new file mode 100644
index 00000000000..0705c21ab61
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search-widget.model.ts
@@ -0,0 +1,12 @@
+import type { TurSNSearchFacet } from "./sn-search-facet.model";
+import type { TurSNSearchLocale } from "./sn-search-locale.model";
+import type { TurSNSearchSpellCheck } from "./sn-search-spell-check.model";
+
+export interface TurSNSearchWidget {
+ facet: TurSNSearchFacet[];
+ facetToRemove: TurSNSearchFacet;
+ similar: string;
+ spellCheck: TurSNSearchSpellCheck;
+ locales: TurSNSearchLocale[];
+ cleanUpFacets: string;
+}
diff --git a/turing-shadcn/src/search/models/sn-search.model.ts b/turing-shadcn/src/search/models/sn-search.model.ts
new file mode 100644
index 00000000000..24aa4e624d3
--- /dev/null
+++ b/turing-shadcn/src/search/models/sn-search.model.ts
@@ -0,0 +1,11 @@
+import type { TurSNSearchPaginationItem } from "./sn-search-pagination-item.model";
+import type { TurSNSearchQueryContext } from "./sn-search-query-context.model";
+import type { TurSNSearchResults } from "./sn-search-results.model";
+import type { TurSNSearchWidget } from "./sn-search-widget.model";
+
+export interface TurSNSearch {
+ pagination: TurSNSearchPaginationItem[];
+ queryContext: TurSNSearchQueryContext;
+ results: TurSNSearchResults;
+ widget: TurSNSearchWidget;
+}
diff --git a/turing-shadcn/src/search/pages/search.page.tsx b/turing-shadcn/src/search/pages/search.page.tsx
new file mode 100644
index 00000000000..6cafa4668f4
--- /dev/null
+++ b/turing-shadcn/src/search/pages/search.page.tsx
@@ -0,0 +1,509 @@
+import { useEffect, useState } from "react";
+import { useSearchParams, useParams } from "react-router-dom";
+import { TurSNSearchService } from "../services/sn-search.service";
+import type { TurSNSearch } from "../models/sn-search.model";
+import type { TurSNChat } from "../models/sn-chat.model";
+import { Search, ChevronDown } from "lucide-react";
+import moment from "moment";
+
+export default function SearchPage() {
+ const { siteName } = useParams<{ siteName: string }>();
+ const [searchParams, setSearchParams] = useSearchParams();
+ const [snSearch, setSnSearch] = useState(null);
+ const [llmChat, setLlmChat] = useState(null);
+ const [turQuery, setTurQuery] = useState(searchParams.get("q") || "");
+ const [turLocale] = useState(searchParams.get("_setlocale") || "en_US");
+ const [turSort] = useState(searchParams.get("sort") || "relevance");
+ const [autoComplete, setAutoComplete] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const turSiteName = siteName || "Sample"; // Get from URL params or use default
+
+ const sortOptions: Record = {
+ relevance: "Relevance",
+ newest: "Newest",
+ oldest: "Oldest",
+ };
+
+ useEffect(() => {
+ performSearch();
+ }, [searchParams]);
+
+ const performSearch = async () => {
+ setLoading(true);
+ try {
+ const q = searchParams.get("q") || "*";
+ const p = searchParams.get("p") || "1";
+ const _setlocale = searchParams.get("_setlocale") || "en_US";
+ const sort = searchParams.get("sort") || "relevance";
+ const fq = searchParams.getAll("fq") || [];
+ const tr = searchParams.getAll("tr") || [];
+ const nfpr = searchParams.get("nfpr") || "";
+
+ const [searchResult, chatResult] = await Promise.all([
+ TurSNSearchService.query(turSiteName, q, p, _setlocale, sort, fq, tr, nfpr),
+ q !== "*" ? TurSNSearchService.chat(turSiteName, q, _setlocale) : Promise.resolve(null),
+ ]);
+
+ setSnSearch(searchResult);
+ setLlmChat(chatResult);
+ } catch (error) {
+ console.error("Search error:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const searchIt = () => {
+ const params = new URLSearchParams(searchParams);
+ params.set("q", turQuery || "*");
+ params.set("p", "1");
+ setSearchParams(params);
+ };
+
+ const retrieveAutoComplete = async () => {
+ if (turQuery && turQuery.length > 2) {
+ try {
+ const results = await TurSNSearchService.autoComplete(
+ turSiteName,
+ turQuery,
+ "1",
+ turLocale,
+ turSort,
+ [],
+ [],
+ ""
+ );
+ setAutoComplete(results);
+ } catch (error) {
+ console.error("Autocomplete error:", error);
+ }
+ } else {
+ setAutoComplete([]);
+ }
+ };
+
+ const turRedirect = (link: string) => {
+ window.location.href = link;
+ };
+
+ const showAll = () => {
+ setTurQuery("*");
+ searchIt();
+ };
+
+ const changeLocale = (locale: string) => {
+ const params = new URLSearchParams(searchParams);
+ params.set("_setlocale", locale);
+ setSearchParams(params);
+ };
+
+ const changeOrderBy = (sort: string) => {
+ const params = new URLSearchParams(searchParams);
+ params.set("sort", sort);
+ setSearchParams(params);
+ };
+
+ const camelize = (text: string) => {
+ return text
+ .split("_")
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
+ .join(" ");
+ };
+
+ if (loading || !snSearch) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
+
+
+ {
+ setTurQuery(e.target.value);
+ retrieveAutoComplete();
+ }}
+ onKeyPress={(e) => e.key === "Enter" && searchIt()}
+ type="search"
+ className="w-full px-4 py-2 pr-10 rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring"
+ placeholder="Search..."
+ autoComplete="off"
+ />
+
+
+
+ {autoComplete.length > 0 && (
+
+ {autoComplete.map((term, idx) => (
+ {
+ setTurQuery(term);
+ setAutoComplete([]);
+ }}
+ >
+ {term}
+
+ ))}
+
+ )}
+
+
+ {/* Locale Selector */}
+
+
+
+ {snSearch.widget.locales.map((locale) => (
+
+ ))}
+
+
+
+
+
+
+ {/* Main Content */}
+
+ {/* Chat/AI Response */}
+ {llmChat?.text && (
+
+ Assistant
+ {llmChat.text}
+
+ )}
+
+ {/* No Results */}
+ {snSearch.results.document.length === 0 && (
+
+
+
+ We couldn't find any results matching '{turQuery}'.
+
+ {snSearch.widget.spellCheck.correctedText && (
+
+ Did you mean{" "}
+
+ ?
+
+ )}
+ {!snSearch.widget.spellCheck.correctedText && !llmChat?.text && (
+
+
+ You can try to see all the available content, maybe you have a new idea. :-)
+
+
+
+ )}
+
+ )}
+
+ {/* Results */}
+ {snSearch.results.document.length > 0 && (
+
+ {/* Facets Sidebar */}
+
+
+ {/* Results Column */}
+
+
+
+ Showing {snSearch.queryContext.pageStart} - {snSearch.queryContext.pageEnd} of{" "}
+ {snSearch.queryContext.count} results
+
+
+ {/* Sort Selector */}
+
+
+
+ {Object.entries(sortOptions).map(([key, value]) => (
+
+ ))}
+
+
+
+
+ {/* Spell Check Messages */}
+ {snSearch.widget.spellCheck.usingCorrectedText &&
+ snSearch.widget.spellCheck.correctedText && (
+
+
+ Showing results for{" "}
+
+ .
+
+
+ Instead, search for{" "}
+
+
+
+ )}
+
+ {!snSearch.widget.spellCheck.usingCorrectedText &&
+ snSearch.widget.spellCheck.correctedText && (
+
+
+ Did you mean '
+
+ '?
+
+
+ )}
+
+ {/* Documents */}
+
+ {snSearch.results.document.map((document, idx) => {
+ const url = document.fields[snSearch.queryContext.defaultFields.url];
+ const title = document.fields[snSearch.queryContext.defaultFields.title];
+ const description =
+ document.fields[snSearch.queryContext.defaultFields.description];
+ const date = document.fields[snSearch.queryContext.defaultFields.date];
+
+ if (!url) return null;
+
+ return (
+
+
+
+
+
+ {description && (
+
+ )}
+ {document.metadata.map((metadata, midx) => (
+
+
+ );
+ })}
+
+
+ {/* Pagination */}
+
+
+
+ )}
+
+
+ {/* Footer */}
+
+
+ );
+}
diff --git a/turing-shadcn/src/search/services/sn-search.service.ts b/turing-shadcn/src/search/services/sn-search.service.ts
new file mode 100644
index 00000000000..2884a3bf51a
--- /dev/null
+++ b/turing-shadcn/src/search/services/sn-search.service.ts
@@ -0,0 +1,104 @@
+import axios from 'axios';
+import type { TurSNSearch } from '../models/sn-search.model';
+import type { TurSNChat } from '../models/sn-chat.model';
+
+export class TurSNSearchService {
+
+ static query(
+ turSiteName: string,
+ q: string,
+ p: string,
+ _setlocale: string,
+ sort: string,
+ fq: string[],
+ tr: string[],
+ nfpr: string
+ ): Promise {
+ const queryString = this.generateQueryString(q, p, _setlocale, sort, fq, tr, nfpr);
+ return axios
+ .get(`/api/sn/${turSiteName}/search?${queryString}`)
+ .then(response => response.data);
+ }
+
+ static chat(turSiteName: string, q: string, _setlocale: string): Promise {
+ return axios
+ .get(`/api/sn/${turSiteName}/chat?q=${q}&_setlocale=${_setlocale}`)
+ .then(response => response.data);
+ }
+
+ static autoComplete(
+ turSiteName: string,
+ q: string,
+ p: string,
+ _setlocale: string,
+ sort: string,
+ fq: string[],
+ tr: string[],
+ nfpr: string
+ ): Promise {
+ const queryString = this.generateQueryString(q, p, _setlocale, sort, fq, tr, nfpr);
+ return axios
+ .get(`/api/sn/${turSiteName}/ac?${queryString}`)
+ .then(response => response.data);
+ }
+
+ static generateQueryString(
+ q: string,
+ p: string,
+ _setlocale: string,
+ sort: string,
+ fq: string[],
+ tr: string[],
+ nfpr: string
+ ): string {
+ let queryString = "";
+
+ if (q) {
+ queryString += `q=${encodeURIComponent(q)}`;
+ } else {
+ queryString += `q=*`;
+ }
+
+ if (p) {
+ queryString += `&p=${p}`;
+ } else {
+ queryString += `&p=1`;
+ }
+
+ if (_setlocale) {
+ queryString += `&_setlocale=${_setlocale}`;
+ }
+
+ if (sort) {
+ queryString += `&sort=${sort}`;
+ } else {
+ queryString += `&sort=relevance`;
+ }
+
+ if (fq) {
+ if (Array.isArray(fq)) {
+ fq.forEach(function (fqItem) {
+ queryString += `&fq[]=${encodeURIComponent(fqItem)}`;
+ });
+ } else {
+ queryString += `&fq[]=${encodeURIComponent(fq)}`;
+ }
+ }
+
+ if (tr) {
+ if (Array.isArray(tr)) {
+ tr.forEach(function (trItem) {
+ queryString += `&tr[]=${encodeURIComponent(trItem)}`;
+ });
+ } else {
+ queryString += `&tr[]=${encodeURIComponent(tr)}`;
+ }
+ }
+
+ if (nfpr) {
+ queryString += `&nfpr=${encodeURIComponent(nfpr)}`;
+ }
+
+ return queryString;
+ }
+}
diff --git a/turing-shadcn/src/services/authorization.service.ts b/turing-shadcn/src/services/authorization.service.ts
new file mode 100644
index 00000000000..4a14d71f0aa
--- /dev/null
+++ b/turing-shadcn/src/services/authorization.service.ts
@@ -0,0 +1,28 @@
+import type { TurDiscoveryAPI } from "@/models/auth/discovery";
+import type { TurRestInfo } from "@/models/auth/rest-info";
+import axios, { type AxiosRequestConfig } from "axios";
+
+export class TurAuthorizationService {
+ async login(username: string, password: string): Promise {
+ const config: AxiosRequestConfig = {
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Basic " + window.btoa(username + ":" + password),
+ },
+ };
+ const response = await axios.create().get("/v2", config);
+ return response.data;
+ }
+
+ async discovery(): Promise {
+ const config: AxiosRequestConfig = {};
+ const response = await axios
+ .create()
+ .get("/discovery", config);
+ return response.data;
+ }
+
+ logout() {
+ localStorage.removeItem("restInfo");
+ }
+}
diff --git a/turing-shadcn/src/services/integration.service.ts b/turing-shadcn/src/services/integration.service.ts
new file mode 100644
index 00000000000..bc9cbd30a46
--- /dev/null
+++ b/turing-shadcn/src/services/integration.service.ts
@@ -0,0 +1,32 @@
+import axios from "axios";
+import type { TurIntegrationInstance } from "@/models/integration/integration-instance.model";
+
+export class TurIntegrationInstanceService {
+ async query(): Promise {
+ const response = await axios.get("/integration");
+ return response.data;
+ }
+ async get(id: string): Promise {
+ const response = await axios.get(`/integration/${id}`);
+ return response.data;
+ }
+ async create(turIntegrationInstance: TurIntegrationInstance): Promise {
+ const response = await axios.post("/integration",
+ turIntegrationInstance
+ );
+ return response.data;
+ }
+ async update(turIntegrationInstance: TurIntegrationInstance): Promise {
+ const response = await axios.put(
+ `/integration/${turIntegrationInstance.id.toString()}`,
+ turIntegrationInstance
+ );
+ return response.data;
+ }
+ async delete(turIntegrationInstance: TurIntegrationInstance): Promise {
+ const response = await axios.delete(
+ `/integration/${turIntegrationInstance.id.toString()}`
+ );
+ return response.status == 200;
+ }
+}
diff --git a/turing-shadcn/src/services/llm.service.ts b/turing-shadcn/src/services/llm.service.ts
new file mode 100644
index 00000000000..01b26cc217b
--- /dev/null
+++ b/turing-shadcn/src/services/llm.service.ts
@@ -0,0 +1,32 @@
+import axios from "axios";
+import type { TurLLMInstance } from "@/models/llm/llm-instance.model";
+
+export class TurLLMInstanceService {
+ async query(): Promise {
+ const response = await axios.get("/llm");
+ return response.data;
+ }
+ async get(id: string): Promise {
+ const response = await axios.get(`/llm/${id}`);
+ return response.data;
+ }
+ async create(turLLMInstance: TurLLMInstance): Promise {
+ const response = await axios.post("/llm",
+ turLLMInstance
+ );
+ return response.data;
+ }
+ async update(turLLMInstance: TurLLMInstance): Promise {
+ const response = await axios.put(
+ `/llm/${turLLMInstance.id.toString()}`,
+ turLLMInstance
+ );
+ return response.data;
+ }
+ async delete(turLLMInstance: TurLLMInstance): Promise {
+ const response = await axios.delete(
+ `/llm/${turLLMInstance.id.toString()}`
+ );
+ return response.status == 200;
+ }
+}
diff --git a/turing-shadcn/src/services/locale.service.ts b/turing-shadcn/src/services/locale.service.ts
new file mode 100644
index 00000000000..850406e7b92
--- /dev/null
+++ b/turing-shadcn/src/services/locale.service.ts
@@ -0,0 +1,13 @@
+import type { TurLocale } from "@/models/locale/locale.model";
+import axios from "axios";
+
+export class TurLocaleService {
+ async query(): Promise {
+ const response = await axios.get("/locale");
+ return response.data;
+ }
+ async get(initials: string): Promise {
+ const response = await axios.get(`/locale/${initials}`);
+ return response.data;
+ }
+}
diff --git a/turing-shadcn/src/services/logging.service.ts b/turing-shadcn/src/services/logging.service.ts
new file mode 100644
index 00000000000..98f93589443
--- /dev/null
+++ b/turing-shadcn/src/services/logging.service.ts
@@ -0,0 +1,32 @@
+import axios from "axios";
+import type { TurLoggingInstance } from "@/models/logging/logging-instance.model";
+
+export class TurLoggingInstanceService {
+ async query(): Promise {
+ const response = await axios.get("/logging");
+ return response.data;
+ }
+ async get(id: string): Promise {
+ const response = await axios.get(`/logging/${id}`);
+ return response.data;
+ }
+ async create(turLoggingInstance: TurLoggingInstance): Promise {
+ const response = await axios.post("/logging",
+ turLoggingInstance
+ );
+ return response.data;
+ }
+ async update(turLoggingInstance: TurLoggingInstance): Promise {
+ const response = await axios.put(
+ `/logging/${turLoggingInstance.id.toString()}`,
+ turLoggingInstance
+ );
+ return response.data;
+ }
+ async delete(turLoggingInstance: TurLoggingInstance): Promise {
+ const response = await axios.delete(
+ `/logging/${turLoggingInstance.id.toString()}`
+ );
+ return response.status == 200;
+ }
+}
diff --git a/turing-shadcn/src/services/se.service.ts b/turing-shadcn/src/services/se.service.ts
new file mode 100644
index 00000000000..07bfb48ccc8
--- /dev/null
+++ b/turing-shadcn/src/services/se.service.ts
@@ -0,0 +1,32 @@
+import axios from "axios";
+import type { TurSEInstance } from "@/models/se/se-instance.model";
+
+export class TurSEInstanceService {
+ async query(): Promise |