Ctrl K
ComunidadGuías…

lib/admin-sections.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"use client";

import { useMemo } from "react";
import { Activity, ServerStack01Icon, DollarCircleIcon as CircleDollarSign, FileExportIcon, FlowIcon as Workflow, KeyRoundIcon as KeyRound, Mic01Icon as Mic, PieChart, ReceiptText, Search01Icon, Sparkles, UserGroupIcon as Users, VectorSquareIcon } from "@hugeicons/core-free-icons";
import { useTranslations } from "next-intl";
import type { AppIcon } from "@/components/icon";
import type { MessageKey } from "@/lib/i18n-keys";
import {
  AI_MODEL_CONFIG_FIELDS,
  type AiConfigField,
  type AiConfigGroup,
} from "@/lib/ai-model-config";
import type { AdminTabId } from "@/lib/admin-tabs";

/** Stable section ids shared by search results and their DOM destinations. */
export const ADMIN_SECTIONS = {
  accountsSummary: "accounts-summary",
  accountsSupport: "accounts-support",
  costsSummary: "costs-summary",
  costsChart: "costs-chart",
  costsByFeature: "costs-by-feature",
  costsLogs: "costs-logs",
  modelsFile: "models-file",
  modelsAssistant: "models-assistant",
  modelsEmbeddings: "models-embeddings",
  modelsVoice: "models-voice",
  modelsDecision: "models-decision",
  modelsByok: "models-byok",
  instanceVariables: "instance-variables",
} as const;

export type AdminSectionId =
  (typeof ADMIN_SECTIONS)[keyof typeof ADMIN_SECTIONS];

export const ADMIN_SECTION_PARAM = "section";

export function adminSectionAnchor(id: AdminSectionId): string {
  return `admin-section-${id}`;
}

export type AdminSection = {
  id: AdminSectionId;
  tab: AdminTabId;
  icon: AppIcon;
  title: string;
  tabLabel: string;
  keywords: string[];
};

type AdminKey = MessageKey<"Admin">;

const MODEL_GROUP_SECTIONS: Record<
  AiConfigGroup,
  { id: AdminSectionId; icon: AppIcon }
> = {
  assistant: { id: ADMIN_SECTIONS.modelsAssistant, icon: Sparkles },
  embeddings: { id: ADMIN_SECTIONS.modelsEmbeddings, icon: VectorSquareIcon },
  voice: { id: ADMIN_SECTIONS.modelsVoice, icon: Mic },
  decision: { id: ADMIN_SECTIONS.modelsDecision, icon: Workflow },
  byok: { id: ADMIN_SECTIONS.modelsByok, icon: KeyRound },
};

/**
 * Administration search catalog in the current locale.
 *
 * Model rows remain grouped by their visible card, just like account/project
 * settings search: a query for “Reasoning level” returns the Assistant card.
 * Raw config keys stay in the keyword set so English technical terms remain
 * discoverable from every locale.
 */
export function useAdminSections(): AdminSection[] {
  const t = useTranslations("Admin");

  return useMemo(() => {
    const tabs: Record<AdminTabId, string> = {
      accounts: t("tabs.accounts"),
      costs: t("tabs.costs"),
      models: t("tabs.models"),
      instance: t("tabs.instance"),
    };
    const section = (value: Omit<AdminSection, "tabLabel">): AdminSection => ({
      ...value,
      tabLabel: tabs[value.tab],
    });

    const fieldLabel = (field: AiConfigField): string => {
      const key = `fields.${field.key}.label` as AdminKey;
      return field.adminLabel ?? (t.has(key) ? t(key) : field.key);
    };
    const modelSections = (
      Object.keys(MODEL_GROUP_SECTIONS) as AiConfigGroup[]
    ).map((group) => {
      const meta = MODEL_GROUP_SECTIONS[group];
      const fields = AI_MODEL_CONFIG_FIELDS.filter((field) => field.group === group);
      return section({
        id: meta.id,
        tab: "models",
        icon: meta.icon,
        title: t(`groups.${group}.title`),
        keywords: fields.flatMap((field) => [field.key, fieldLabel(field)]),
      });
    });

    return [
      section({
        id: ADMIN_SECTIONS.accountsSummary,
        tab: "accounts",
        icon: Users,
        title: t("accounts.countLabel"),
        keywords: ["accounts", "users", "count"],
      }),
      section({
        id: ADMIN_SECTIONS.accountsSupport,
        tab: "accounts",
        icon: Search01Icon,
        title: t("accounts.supportTitle"),
        keywords: [
          t("users.usageTitle"),
          t("billing.title"),
          t("quotas.reset"),
          "email",
          "quota",
          "budget",
          "gift plan",
          "usage",
        ],
      }),
      section({
        id: ADMIN_SECTIONS.costsSummary,
        tab: "costs",
        icon: CircleDollarSign,
        title: t("costs.summaryTitle"),
        keywords: [t("costs.kpiSpend"), t("costs.kpiRequests"), t("costs.kpiTokens"), "cost", "spend", "month"],
      }),
      section({
        id: ADMIN_SECTIONS.costsChart,
        tab: "costs",
        icon: Activity,
        title: t("costs.spendByModelTitle"),
        keywords: [t("costs.topModelsTitle"), t("costs.requestsByModelTitle"), "chart", "daily", "model"],
      }),
      section({
        id: ADMIN_SECTIONS.costsByFeature,
        tab: "costs",
        icon: PieChart,
        title: t("costs.topFeaturesTitle"),
        keywords: [t("costs.spendByGroupTitle"), "feature", "cost", "usage"],
      }),
      section({
        id: ADMIN_SECTIONS.costsLogs,
        tab: "costs",
        icon: ReceiptText,
        title: t("costs.logsTitle"),
        keywords: ["log", "runs", "calls", "model", "tokens"],
      }),
      section({
        id: ADMIN_SECTIONS.modelsFile,
        tab: "models",
        icon: FileExportIcon,
        title: t("modelsFile.title"),
        keywords: [t("modelsFile.export"), t("modelsFile.import"), "export", "import", "json", "file"],
      }),
      ...modelSections,
      section({
        id: ADMIN_SECTIONS.instanceVariables,
        tab: "instance",
        icon: ServerStack01Icon,
        title: t("instance.title"),
        keywords: [
          "environment",
          "variables",
          ".env",
          "OPENROUTER_API_KEY",
          "ADMIN_EMAILS",
          "EMAIL_PROVIDER",
          "GITHUB_APP_ID",
          "GITLAB_OAUTH_CLIENT_ID",
          "POSTHOG_API_KEY",
        ],
      }),
    ];
  }, [t]);
}