Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 114 additions & 112 deletions apps/app/src/app/pages/automations.tsx

Large diffs are not rendered by default.

143 changes: 72 additions & 71 deletions apps/app/src/app/pages/config.tsx

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions apps/app/src/app/pages/extensions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import McpView from "../connections/mcp-view";
import { useConnections } from "../connections/provider";
import { useExtensions } from "../extensions/provider";
import PluginsView, { type PluginsViewProps } from "./plugins";
import { t } from "../../i18n";

export type ExtensionsSection = "all" | "mcp" | "plugins";

Expand Down Expand Up @@ -64,25 +65,25 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
<div class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
<div class="space-y-1">
<Show when={props.showHeader !== false}>
<h2 class="text-3xl font-bold text-dls-text">Extensions</h2>
<h2 class="text-3xl font-bold text-dls-text">{t("extensions.title")}</h2>
<p class="text-sm text-dls-secondary mt-1.5">
Apps (MCP) and OpenCode plugins live in one place.
{t("extensions.subtitle")}
</p>
</Show>
<div class={`${props.showHeader === false ? "" : "mt-3"} flex flex-wrap items-center gap-2`}>
<Show when={connectedAppsCount() > 0}>
<div class="inline-flex items-center gap-2 rounded-full bg-green-3 px-3 py-1">
<div class="w-2 h-2 rounded-full bg-green-9" />
<span class="text-xs font-medium text-green-11">
{connectedAppsCount()} app{connectedAppsCount() === 1 ? "" : "s"} connected
{connectedAppsCount()} {connectedAppsCount() === 1 ? t("extensions.app_count_one") : t("extensions.app_count_many")}
</span>
</div>
</Show>
<Show when={pluginCount() > 0}>
<div class="inline-flex items-center gap-2 rounded-full bg-gray-3 px-3 py-1">
<Cpu size={14} class="text-gray-11" />
<span class="text-xs font-medium text-gray-11">
{pluginCount()} plugin{pluginCount() === 1 ? "" : "s"}
{pluginCount()} {pluginCount() === 1 ? t("extensions.plugin_count_one") : t("extensions.plugin_count_many")}
</span>
</div>
</Show>
Expand All @@ -97,7 +98,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
aria-pressed={section() === "all"}
onClick={() => selectSection("all")}
>
All
{t("extensions.filter_all")}
</button>
<button
type="button"
Expand All @@ -106,7 +107,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
onClick={() => selectSection("mcp")}
>
<Box size={14} />
Apps
{t("extensions.filter_apps")}
</button>
<button
type="button"
Expand All @@ -115,11 +116,11 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
onClick={() => selectSection("plugins")}
>
<Cpu size={14} />
Plugins
{t("extensions.filter_plugins")}
</button>
</div>
<Button variant="ghost" onClick={refreshAll}>
Refresh
{t("common.refresh")}
</Button>
</div>
</div>
Expand All @@ -128,7 +129,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
<div class="space-y-4">
<div class="flex items-center gap-2 text-sm font-medium text-gray-12">
<Box size={16} class="text-gray-11" />
<span>Apps (MCP)</span>
<span>{t("extensions.apps_mcp_header")}</span>
</div>
<McpView
showHeader={false}
Expand All @@ -143,7 +144,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
<div class="space-y-4">
<div class="flex items-center gap-2 text-sm font-medium text-gray-12">
<Cpu size={16} class="text-gray-11" />
<span>Plugins (OpenCode)</span>
<span>{t("extensions.plugins_opencode_header")}</span>
</div>
<PluginsView
busy={props.busy}
Expand Down
302 changes: 146 additions & 156 deletions apps/app/src/app/pages/identities.tsx

Large diffs are not rendered by default.

33 changes: 17 additions & 16 deletions apps/app/src/app/pages/plugins.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useExtensions } from "../extensions/provider";
import Button from "../components/button";
import TextInput from "../components/text-input";
import { Cpu } from "lucide-solid";
import { t } from "../../i18n";

export type PluginsViewProps = {
busy: boolean;
Expand Down Expand Up @@ -37,8 +38,8 @@ export default function PluginsView(props: PluginsViewProps) {
<div class="bg-gray-2/30 border border-gray-6/50 rounded-2xl p-5 space-y-4">
<div class="flex items-start justify-between gap-4">
<div class="space-y-1">
<div class="text-sm font-medium text-gray-12">OpenCode plugins</div>
<div class="text-xs text-gray-10">Manage `opencode.json` for your project or global OpenCode plugins.</div>
<div class="text-sm font-medium text-gray-12">{t("plugins.title")}</div>
<div class="text-xs text-gray-10">{t("plugins.desc")}</div>
</div>
<div class="flex items-center gap-2">
<button
Expand All @@ -52,7 +53,7 @@ export default function PluginsView(props: PluginsViewProps) {
void extensions.refreshPlugins("project");
}}
>
Project
{t("plugins.scope_project")}
</button>
<button
disabled={!props.canUseGlobalScope}
Expand All @@ -67,24 +68,24 @@ export default function PluginsView(props: PluginsViewProps) {
void extensions.refreshPlugins("global");
}}
>
Global
{t("plugins.scope_global")}
</button>
<Button variant="ghost" onClick={() => void extensions.refreshPlugins()}>
Refresh
{t("common.refresh")}
</Button>
</div>
</div>

<div class="flex flex-col gap-1 text-xs text-gray-10">
<div>Config</div>
<div class="text-gray-7 font-mono truncate">{extensions.pluginConfigPath() ?? extensions.pluginConfig()?.path ?? "Not loaded yet"}</div>
<div>{t("plugins.config_label")}</div>
<div class="text-gray-7 font-mono truncate">{extensions.pluginConfigPath() ?? extensions.pluginConfig()?.path ?? t("plugins.not_loaded_yet")}</div>
<Show when={props.accessHint}>
<div class="text-gray-9">{props.accessHint}</div>
</Show>
</div>

<div class="space-y-3">
<div class="text-xs font-medium text-gray-11 uppercase tracking-wider">Suggested plugins</div>
<div class="text-xs font-medium text-gray-11 uppercase tracking-wider">{t("plugins.suggested_heading")}</div>
<div class="grid gap-3">
<For each={props.suggestedPlugins}>
{(plugin) => {
Expand All @@ -108,7 +109,7 @@ export default function PluginsView(props: PluginsViewProps) {
variant="ghost"
onClick={() => extensions.setActivePluginGuide(isGuideOpen() ? null : plugin.packageName)}
>
{isGuideOpen() ? "Hide setup" : "Setup"}
{isGuideOpen() ? t("plugins.hide_setup") : t("plugins.setup")}
</Button>
</Show>
<Button
Expand All @@ -121,7 +122,7 @@ export default function PluginsView(props: PluginsViewProps) {
(extensions.pluginScope() === "project" && !props.selectedWorkspaceRoot.trim())
}
>
{isInstalled() ? "Added" : "Add"}
{isInstalled() ? t("plugins.added") : t("plugins.add")}
</Button>
</div>
</div>
Expand Down Expand Up @@ -177,7 +178,7 @@ export default function PluginsView(props: PluginsViewProps) {
when={extensions.pluginList().length}
fallback={
<div class="rounded-xl border border-gray-6/60 bg-gray-1/40 p-4 text-sm text-gray-10">
No plugins configured yet.
{t("plugins.empty")}
</div>
}
>
Expand All @@ -187,14 +188,14 @@ export default function PluginsView(props: PluginsViewProps) {
<div class="flex items-center justify-between rounded-xl border border-gray-6/60 bg-gray-1/40 px-4 py-2.5">
<div class="text-sm text-gray-12 font-mono">{pluginName}</div>
<div class="flex items-center gap-2">
<div class="text-[10px] uppercase tracking-wide text-gray-10">Enabled</div>
<div class="text-[10px] uppercase tracking-wide text-gray-10">{t("plugins.enabled")}</div>
<Button
variant="ghost"
class="h-7 px-2 text-[11px] text-red-11 hover:text-red-12"
onClick={() => extensions.removePlugin(pluginName)}
disabled={props.busy || !props.canEditPlugins}
>
Remove
{t("plugins.remove")}
</Button>
</div>
</div>
Expand All @@ -207,11 +208,11 @@ export default function PluginsView(props: PluginsViewProps) {
<div class="flex flex-col md:flex-row gap-3">
<div class="flex-1">
<TextInput
label="Add plugin"
label={t("plugins.add_label")}
placeholder="opencode-wakatime"
value={extensions.pluginInput()}
onInput={(e) => extensions.setPluginInput(e.currentTarget.value)}
hint="Add npm package names, e.g. opencode-wakatime"
hint={t("plugins.add_hint")}
/>
</div>
<Button
Expand All @@ -220,7 +221,7 @@ export default function PluginsView(props: PluginsViewProps) {
disabled={props.busy || !extensions.pluginInput().trim() || !props.canEditPlugins}
class="md:mt-6"
>
Add
{t("plugins.add")}
</Button>
</div>
<Show when={extensions.pluginStatus()}>
Expand Down
Loading
Loading