mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-25 10:42:45 +00:00
* feat(plugins): contribute settings screens and shared controls * fix(plugins): localize settings and verify shared UI consumers * test(composer): unmount draft test roots after each case * test(app): keep launch terminals alive until cleanup The fixed ten-second profile lifetime could expire before a busy CI browser attached or finished revisiting the composer. Keep the real process waiting for input until project teardown terminates it. * test(server): await the initial snapshot before a buffered ref event Watcher setup can read checkout facts before the initial refresh publishes a snapshot. Wait for publication before injecting the event so the test consistently exercises a second refresh.
89 lines
3.4 KiB
TypeScript
89 lines
3.4 KiB
TypeScript
import { useCallback, useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Text, View } from "react-native";
|
|
import { useFocusEffect } from "@react-navigation/native";
|
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
import { ArrowUpRight, Check, Terminal } from "lucide-react-native";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useCliInstall } from "@/desktop/hooks/use-install-status";
|
|
import { SettingsSection } from "@/components/settings/headings/settings-section";
|
|
import { settingsStyles } from "@/styles/settings";
|
|
import { openExternalUrl } from "@/utils/open-external-url";
|
|
import { shouldUseDesktopDaemon } from "@/desktop/daemon/desktop-daemon";
|
|
|
|
const CLI_DOCS_URL = "https://paseo.sh/docs/cli";
|
|
|
|
export function IntegrationsSection() {
|
|
const { t } = useTranslation();
|
|
const { theme } = useUnistyles();
|
|
const showSection = shouldUseDesktopDaemon();
|
|
const { status, isInstalling, install, refresh } = useCliInstall();
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
if (showSection) refresh();
|
|
return undefined;
|
|
}, [refresh, showSection]),
|
|
);
|
|
const docsIcon = useMemo(
|
|
() => <ArrowUpRight size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />,
|
|
[theme.iconSize.sm, theme.colors.foregroundMuted],
|
|
);
|
|
const handleOpenDocs = useCallback(() => {
|
|
void openExternalUrl(CLI_DOCS_URL);
|
|
}, []);
|
|
const trailing = useMemo(
|
|
() => (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
leftIcon={docsIcon}
|
|
textStyle={settingsStyles.sectionHeaderLinkText}
|
|
style={settingsStyles.sectionHeaderLink}
|
|
onPress={handleOpenDocs}
|
|
accessibilityLabel={t("settings.integrations.docs.openCli")}
|
|
>
|
|
{t("settings.integrations.docs.cli")}
|
|
</Button>
|
|
),
|
|
[docsIcon, handleOpenDocs, t],
|
|
);
|
|
if (!showSection) return null;
|
|
return (
|
|
<SettingsSection title={t("settings.integrations.title")} trailing={trailing}>
|
|
<View style={settingsStyles.card}>
|
|
<View style={settingsStyles.row}>
|
|
<View style={settingsStyles.rowContent}>
|
|
<View style={styles.rowTitleRow}>
|
|
<Terminal size={theme.iconSize.md} color={theme.colors.foreground} />
|
|
<Text style={settingsStyles.rowTitle}>
|
|
{t("settings.integrations.commandLine.title")}
|
|
</Text>
|
|
</View>
|
|
<Text style={settingsStyles.rowHint}>
|
|
{t("settings.integrations.commandLine.description")}
|
|
</Text>
|
|
</View>
|
|
{status?.installed ? (
|
|
<View style={styles.installedLabel}>
|
|
<Check size={14} color={theme.colors.foregroundMuted} />
|
|
<Text style={styles.mutedText}>{t("settings.integrations.actions.installed")}</Text>
|
|
</View>
|
|
) : (
|
|
<Button variant="outline" size="sm" onPress={install} disabled={isInstalling}>
|
|
{isInstalling
|
|
? t("settings.integrations.actions.installing")
|
|
: t("settings.integrations.actions.install")}
|
|
</Button>
|
|
)}
|
|
</View>
|
|
</View>
|
|
</SettingsSection>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create((theme) => ({
|
|
rowTitleRow: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2] },
|
|
installedLabel: { flexDirection: "row", alignItems: "center", gap: 4 },
|
|
mutedText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.base },
|
|
}));
|