@xpufx/paseo-top 0.4.4 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OVERVIEW.md +18 -0
- package/client/host-ui.tsx +184 -0
- package/client/multi-host-view.tsx +57 -43
- package/client/multi-host.ts +36 -13
- package/client/pill-labels.ts +94 -1
- package/client/pill.tsx +692 -616
- package/client/resources-query.ts +1 -1
- package/client/settings-events.ts +1 -1
- package/client/settings-ui.tsx +86 -9
- package/client/surface.tsx +308 -276
- package/client/telemetry-copy.ts +8 -2
- package/client/telemetry.tsx +372 -321
- package/client/turn-panel.tsx +126 -104
- package/client/vendor/paseo-plugin-helper/{host.ts → core/host.ts} +9 -3
- package/client/vendor/paseo-plugin-helper/core/index.ts +76 -0
- package/client/vendor/paseo-plugin-helper/core/plugin-load-count.ts +89 -0
- package/client/vendor/paseo-plugin-helper/{query-refresh.ts → core/query-refresh.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{query.ts → core/query.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{settings.ts → core/settings.ts} +1 -1
- package/client/vendor/paseo-plugin-helper/{shared-settings.ts → core/shared-settings.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/clipboard.ts +2 -2
- package/client/vendor/paseo-plugin-helper/lifecycle/flair.ts +26 -0
- package/client/vendor/paseo-plugin-helper/{theme/color-utils.ts → lifecycle/host-color.ts} +95 -38
- package/client/vendor/paseo-plugin-helper/lifecycle/host-theme.tsx +109 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/index.ts +23 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/multi-host.ts +66 -0
- package/client/vendor/paseo-plugin-helper/{panel.tsx → lifecycle/panel.tsx} +7 -7
- package/client/vendor/paseo-plugin-helper/{pill.tsx → lifecycle/pill.tsx} +51 -18
- package/client/vendor/paseo-plugin-helper/lifecycle/providers.tsx +46 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/scroll-owner.ts +26 -0
- package/client/vendor/paseo-plugin-helper/{surface.tsx → lifecycle/surface.tsx} +6 -6
- package/client/vendor/paseo-plugin-helper/ui/color.ts +1 -0
- package/client/vendor/paseo-plugin-helper/ui/content.tsx +1326 -0
- package/client/vendor/paseo-plugin-helper/ui/controls.tsx +1018 -0
- package/client/vendor/paseo-plugin-helper/{components/DataTable.tsx → ui/data.tsx} +50 -58
- package/client/vendor/paseo-plugin-helper/ui/index.ts +44 -0
- package/client/vendor/paseo-plugin-helper/ui/layout.tsx +263 -0
- package/client/vendor/paseo-plugin-helper/ui/modal.tsx +111 -0
- package/client/vendor/paseo-plugin-helper/ui/plugin-reload-banner.tsx +119 -0
- package/client/vendor/paseo-plugin-helper/{settings-screen.tsx → ui/settings-screen.tsx} +3 -3
- package/client/vendor/paseo-plugin-helper/ui/settings.ts +36 -0
- package/client/vendor/paseo-plugin-helper/ui/text.tsx +821 -0
- package/client/vendor/paseo-plugin-helper/ui/theme.tsx +1 -0
- package/client/vendor/permission-audit/client.tsx +706 -0
- package/client/vendor/permission-audit/index.tsx +1 -0
- package/index.client.tsx +58 -37
- package/index.server.ts +256 -234
- package/npm-shrinkwrap.json +44 -0
- package/package.json +8 -4
- package/paseo-plugin.json +2 -0
- package/screenshots/1-paseo-top-modal-system.jpg +0 -0
- package/screenshots/2-paseo-top-modal-workspace.jpg +0 -0
- package/screenshots/3-paseo-top-modal-settings.jpg +0 -0
- package/screenshots/4-paseo-top-modal-about.jpg +0 -0
- package/screenshots/paseo-top-dashboard.jpg +0 -0
- package/screenshots/paseo-top-general-view.jpg +0 -0
- package/server/resources.ts +98 -0
- package/server/vendor/paseo-plugin-helper/custom-pills.ts +70 -0
- package/server/vendor/paseo-plugin-helper/index.ts +2 -0
- package/server/vendor/paseo-plugin-helper/logger.ts +5 -16
- package/server/vendor/paseo-plugin-helper/rpc-guard.ts +2 -2
- package/server/vendor/paseo-plugin-helper/storage-guard.ts +294 -0
- package/server/vendor/paseo-plugin-helper/storage.ts +36 -2
- package/server/vendor/paseo-plugin-helper/telemetry.ts +486 -0
- package/server/vendor/paseo-plugin-helper/tickets.ts +18 -67
- package/server/vendor/permission-audit/index.ts +1 -0
- package/server/vendor/permission-audit/server.ts +839 -0
- package/shared/helper-version.ts +1 -1
- package/shared/multi-host.ts +153 -159
- package/shared/resources.ts +145 -0
- package/shared/vendor/paseo-plugin-helper/async.ts +14 -7
- package/shared/vendor/paseo-plugin-helper/features.ts +244 -0
- package/shared/vendor/paseo-plugin-helper/forge.ts +27 -0
- package/shared/vendor/paseo-plugin-helper/index.ts +1 -0
- package/shared/vendor/paseo-plugin-helper/tickets.ts +122 -28
- package/shared/vendor/permission-audit/filter.ts +61 -0
- package/shared/vendor/permission-audit/index.ts +2 -0
- package/shared/vendor/permission-audit/shared.ts +119 -0
- package/shared/version.ts +1 -1
- package/client/vendor/paseo-plugin-helper/components/AboutSection.tsx +0 -493
- package/client/vendor/paseo-plugin-helper/components/AttentionBeacon.tsx +0 -250
- package/client/vendor/paseo-plugin-helper/components/Badge.tsx +0 -168
- package/client/vendor/paseo-plugin-helper/components/Button.tsx +0 -204
- package/client/vendor/paseo-plugin-helper/components/Card.tsx +0 -257
- package/client/vendor/paseo-plugin-helper/components/CodeBlock.tsx +0 -196
- package/client/vendor/paseo-plugin-helper/components/Collapsible.tsx +0 -277
- package/client/vendor/paseo-plugin-helper/components/CommandBox.tsx +0 -172
- package/client/vendor/paseo-plugin-helper/components/CopyButton.tsx +0 -180
- package/client/vendor/paseo-plugin-helper/components/EmptyState.tsx +0 -97
- package/client/vendor/paseo-plugin-helper/components/HighlightedText.tsx +0 -70
- package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +0 -88
- package/client/vendor/paseo-plugin-helper/components/InteractiveRow.tsx +0 -142
- package/client/vendor/paseo-plugin-helper/components/KeyValue.tsx +0 -446
- package/client/vendor/paseo-plugin-helper/components/MetricGauge.tsx +0 -247
- package/client/vendor/paseo-plugin-helper/components/ProgressBar.tsx +0 -117
- package/client/vendor/paseo-plugin-helper/components/Responsive.tsx +0 -53
- package/client/vendor/paseo-plugin-helper/components/SearchInput.tsx +0 -132
- package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +0 -87
- package/client/vendor/paseo-plugin-helper/components/Select.tsx +0 -283
- package/client/vendor/paseo-plugin-helper/components/StatusDot.tsx +0 -80
- package/client/vendor/paseo-plugin-helper/components/Tabs.tsx +0 -319
- package/client/vendor/paseo-plugin-helper/components/TextInput.tsx +0 -150
- package/client/vendor/paseo-plugin-helper/components/Toggle.tsx +0 -163
- package/client/vendor/paseo-plugin-helper/components/TruncatedText.tsx +0 -157
- package/client/vendor/paseo-plugin-helper/components/index.ts +0 -26
- package/client/vendor/paseo-plugin-helper/custom-pills.tsx +0 -225
- package/client/vendor/paseo-plugin-helper/forge-icon.tsx +0 -79
- package/client/vendor/paseo-plugin-helper/icon.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/index.ts +0 -30
- package/client/vendor/paseo-plugin-helper/layout/ActionBar.tsx +0 -49
- package/client/vendor/paseo-plugin-helper/layout/FormRow.tsx +0 -103
- package/client/vendor/paseo-plugin-helper/layout/Grid.tsx +0 -65
- package/client/vendor/paseo-plugin-helper/layout/ModalBody.tsx +0 -368
- package/client/vendor/paseo-plugin-helper/layout/ModalContent.tsx +0 -51
- package/client/vendor/paseo-plugin-helper/layout/Row.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/layout/Stack.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/layout/index.ts +0 -7
- package/client/vendor/paseo-plugin-helper/styles/index.ts +0 -1
- package/client/vendor/paseo-plugin-helper/styles/recipes.ts +0 -550
- package/client/vendor/paseo-plugin-helper/theme/flair.ts +0 -76
- package/client/vendor/paseo-plugin-helper/theme/host-variables.ts +0 -121
- package/client/vendor/paseo-plugin-helper/theme/index.ts +0 -7
- package/client/vendor/paseo-plugin-helper/theme/provider.tsx +0 -178
- package/client/vendor/paseo-plugin-helper/theme/responsive.ts +0 -213
- package/client/vendor/paseo-plugin-helper/theme/tokens.ts +0 -200
- package/client/vendor/paseo-plugin-helper/theme/useResponsive.ts +0 -57
- package/client/vendor/paseo-plugin-helper/tickets.tsx +0 -766
- /package/client/vendor/paseo-plugin-helper/{command-center.ts → core/command-center.ts} +0 -0
- /package/client/vendor/paseo-plugin-helper/{snapshot.ts → core/snapshot.ts} +0 -0
- /package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/haptics.ts +0 -0
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
|
-
Pressable,
|
|
6
|
-
StyleSheet,
|
|
7
|
-
StyleProp,
|
|
8
|
-
ViewStyle,
|
|
9
|
-
TextStyle,
|
|
10
|
-
Platform,
|
|
11
|
-
} from "react-native";
|
|
12
|
-
import { usePluginTheme } from "../theme/index";
|
|
13
|
-
import { getClientHost } from "../host";
|
|
14
|
-
import { copyToClipboard } from "../utils/clipboard";
|
|
15
|
-
import {
|
|
16
|
-
truncate,
|
|
17
|
-
truncateMiddle,
|
|
18
|
-
truncatePath,
|
|
19
|
-
TruncatePathOptions,
|
|
20
|
-
} from "../../../../shared/vendor/paseo-plugin-helper/formatters";
|
|
21
|
-
|
|
22
|
-
export type TruncateMode = "end" | "middle" | "path";
|
|
23
|
-
|
|
24
|
-
export interface TruncatedTextProps {
|
|
25
|
-
/** The full, raw text string (e.g. UUID, file path, commit SHA, token) */
|
|
26
|
-
text: string;
|
|
27
|
-
/** Maximum length allowed before truncation. Default: 32 */
|
|
28
|
-
maxLength?: number;
|
|
29
|
-
/** Truncation algorithm: "middle" (UUIDs/hashes), "path" (directory paths), or "end" (standard). Default: "middle" */
|
|
30
|
-
mode?: TruncateMode;
|
|
31
|
-
/** Additional path truncation options when mode="path" */
|
|
32
|
-
pathOptions?: TruncatePathOptions;
|
|
33
|
-
/** Whether to render an inline copy button. Default: true */
|
|
34
|
-
copyable?: boolean;
|
|
35
|
-
/** Use monospace font. Default: true */
|
|
36
|
-
mono?: boolean;
|
|
37
|
-
/** Toast message on successful copy. Default: "Copied" */
|
|
38
|
-
toastMessage?: string;
|
|
39
|
-
/** Custom container style */
|
|
40
|
-
style?: StyleProp<ViewStyle>;
|
|
41
|
-
/** Custom text style */
|
|
42
|
-
textStyle?: StyleProp<TextStyle>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Renders long strings (paths, UUIDs, hashes) shortened with smart truncation,
|
|
47
|
-
* while preserving the full untruncated string for one-click clipboard copying.
|
|
48
|
-
*/
|
|
49
|
-
export function TruncatedText({
|
|
50
|
-
text,
|
|
51
|
-
maxLength = 32,
|
|
52
|
-
mode = "middle",
|
|
53
|
-
pathOptions,
|
|
54
|
-
copyable = true,
|
|
55
|
-
mono = true,
|
|
56
|
-
toastMessage = "Copied",
|
|
57
|
-
style,
|
|
58
|
-
textStyle,
|
|
59
|
-
}: TruncatedTextProps) {
|
|
60
|
-
const { colors, fonts, isCompact, touchTargetMin } = usePluginTheme();
|
|
61
|
-
const { Icon, useToast } = getClientHost();
|
|
62
|
-
const toast = useToast();
|
|
63
|
-
const [copied, setCopied] = useState(false);
|
|
64
|
-
|
|
65
|
-
if (!text) {
|
|
66
|
-
return <Text style={[{ color: colors.foregroundMuted }, textStyle]}>-</Text>;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let formattedText = text;
|
|
70
|
-
if (text.length > maxLength) {
|
|
71
|
-
switch (mode) {
|
|
72
|
-
case "path":
|
|
73
|
-
formattedText = truncatePath(text, maxLength, pathOptions);
|
|
74
|
-
break;
|
|
75
|
-
case "end":
|
|
76
|
-
formattedText = truncate(text, maxLength);
|
|
77
|
-
break;
|
|
78
|
-
case "middle":
|
|
79
|
-
default:
|
|
80
|
-
formattedText = truncateMiddle(text, maxLength);
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const handleCopy = async () => {
|
|
86
|
-
if (!copyable || !text) return;
|
|
87
|
-
const ok = await copyToClipboard(text, {
|
|
88
|
-
toast,
|
|
89
|
-
toastMessage,
|
|
90
|
-
});
|
|
91
|
-
if (ok) {
|
|
92
|
-
setCopied(true);
|
|
93
|
-
setTimeout(() => setCopied(false), 2000);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const fontFamily = mono
|
|
98
|
-
? fonts.mono ?? Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" })
|
|
99
|
-
: undefined;
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<View style={[styles.container, style]}>
|
|
103
|
-
<Text
|
|
104
|
-
selectable
|
|
105
|
-
numberOfLines={1}
|
|
106
|
-
ellipsizeMode="clip"
|
|
107
|
-
accessibilityLabel={text}
|
|
108
|
-
style={[
|
|
109
|
-
styles.text,
|
|
110
|
-
{
|
|
111
|
-
color: colors.foreground,
|
|
112
|
-
fontFamily,
|
|
113
|
-
},
|
|
114
|
-
textStyle,
|
|
115
|
-
]}
|
|
116
|
-
>
|
|
117
|
-
{formattedText}
|
|
118
|
-
</Text>
|
|
119
|
-
|
|
120
|
-
{copyable && (
|
|
121
|
-
<Pressable
|
|
122
|
-
onPress={handleCopy}
|
|
123
|
-
hitSlop={Math.max(8, (touchTargetMin - 20) / 2)}
|
|
124
|
-
style={styles.copyBtn}
|
|
125
|
-
accessibilityRole="button"
|
|
126
|
-
accessibilityLabel={`Copy ${text}`}
|
|
127
|
-
>
|
|
128
|
-
<Icon
|
|
129
|
-
name={copied ? "Check" : "Copy"}
|
|
130
|
-
size={isCompact ? 12 : 13}
|
|
131
|
-
color={copied ? colors.statusSuccess : colors.foregroundMuted}
|
|
132
|
-
/>
|
|
133
|
-
</Pressable>
|
|
134
|
-
)}
|
|
135
|
-
</View>
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const styles = StyleSheet.create({
|
|
140
|
-
container: {
|
|
141
|
-
flexDirection: "row",
|
|
142
|
-
alignItems: "center",
|
|
143
|
-
maxWidth: "100%",
|
|
144
|
-
gap: 6,
|
|
145
|
-
},
|
|
146
|
-
text: {
|
|
147
|
-
fontSize: 12,
|
|
148
|
-
lineHeight: 18,
|
|
149
|
-
flexShrink: 1,
|
|
150
|
-
},
|
|
151
|
-
copyBtn: {
|
|
152
|
-
padding: 3,
|
|
153
|
-
borderRadius: 4,
|
|
154
|
-
justifyContent: "center",
|
|
155
|
-
alignItems: "center",
|
|
156
|
-
},
|
|
157
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export * from "./Button";
|
|
2
|
-
export * from "./InlineButton";
|
|
3
|
-
export * from "./InteractiveRow";
|
|
4
|
-
export * from "./AttentionBeacon";
|
|
5
|
-
export * from "./Badge";
|
|
6
|
-
export * from "./StatusDot";
|
|
7
|
-
export * from "./Card";
|
|
8
|
-
export * from "./Tabs";
|
|
9
|
-
export * from "./CodeBlock";
|
|
10
|
-
export * from "./CopyButton";
|
|
11
|
-
export * from "./SearchInput";
|
|
12
|
-
export * from "./TextInput";
|
|
13
|
-
export * from "./Select";
|
|
14
|
-
export * from "./Toggle";
|
|
15
|
-
export * from "./Collapsible";
|
|
16
|
-
export * from "./ProgressBar";
|
|
17
|
-
export * from "./MetricGauge";
|
|
18
|
-
export * from "./DataTable";
|
|
19
|
-
export * from "./KeyValue";
|
|
20
|
-
export * from "./EmptyState";
|
|
21
|
-
export * from "./Responsive";
|
|
22
|
-
export * from "./AboutSection";
|
|
23
|
-
export * from "./TruncatedText";
|
|
24
|
-
export * from "./CommandBox";
|
|
25
|
-
export * from "./SectionHeader";
|
|
26
|
-
export * from "./HighlightedText";
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import React, { useState, useCallback } from "react";
|
|
2
|
-
import { StyleSheet, Text, View } from "react-native";
|
|
3
|
-
import type { ComposerPillRegistrar, PluginCleanup } from "./host";
|
|
4
|
-
import { getClientHost } from "./host";
|
|
5
|
-
import { usePluginTheme } from "./theme/provider";
|
|
6
|
-
import { useResponsive } from "./theme/useResponsive";
|
|
7
|
-
import type { VisualFlair } from "./theme/flair";
|
|
8
|
-
import type { CustomPillState } from "../../../shared/vendor/paseo-plugin-helper/custom-pills";
|
|
9
|
-
import { Badge } from "./components/Badge";
|
|
10
|
-
import { Button } from "./components/Button";
|
|
11
|
-
import { Card } from "./components/Card";
|
|
12
|
-
import { CodeBlock } from "./components/CodeBlock";
|
|
13
|
-
import { registerComposerPill } from "./pill";
|
|
14
|
-
|
|
15
|
-
export interface CustomPillBodyProps {
|
|
16
|
-
state: CustomPillState;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Standard pill body renderer for a custom metric pill. The host renders the
|
|
21
|
-
* composer pill body itself, so reach for this from a pill's own surface
|
|
22
|
-
* (`renderModal`) rather than from the trackbar; it adapts to responsive
|
|
23
|
-
* compact/mobile modes and shows threshold status.
|
|
24
|
-
*/
|
|
25
|
-
export function CustomPillBody({ state }: CustomPillBodyProps) {
|
|
26
|
-
const { Icon } = getClientHost();
|
|
27
|
-
const { colors } = usePluginTheme();
|
|
28
|
-
const { isCompact } = useResponsive();
|
|
29
|
-
|
|
30
|
-
const title = isCompact && state.compactTitle ? state.compactTitle : state.title;
|
|
31
|
-
const icon = isCompact && state.compactIcon ? state.compactIcon : state.icon;
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<View style={styles.pillContainer}>
|
|
35
|
-
{icon && <Icon name={icon} size={13} color={colors.foreground} />}
|
|
36
|
-
{title ? (
|
|
37
|
-
<Text style={[styles.pillTitle, { color: colors.foreground }]}>{title}</Text>
|
|
38
|
-
) : null}
|
|
39
|
-
<Badge
|
|
40
|
-
label={state.displayValue}
|
|
41
|
-
variant={state.status}
|
|
42
|
-
styleVariant="tinted"
|
|
43
|
-
style={styles.pillBadge}
|
|
44
|
-
/>
|
|
45
|
-
</View>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface CustomPillModalContentProps {
|
|
50
|
-
state: CustomPillState;
|
|
51
|
-
onRefresh?: () => Promise<void> | void;
|
|
52
|
-
isRefreshing?: boolean;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Full modal inspection content for a custom metric pill.
|
|
57
|
-
* Shows status, preformatted command output, last updated time, and quick actions.
|
|
58
|
-
*
|
|
59
|
-
* Sized by the host: the root fills the host-allocated modal frame (flex/fluid)
|
|
60
|
-
* so changing output never drives the dialog size.
|
|
61
|
-
*/
|
|
62
|
-
export function CustomPillModalContent({
|
|
63
|
-
state,
|
|
64
|
-
onRefresh,
|
|
65
|
-
isRefreshing = false,
|
|
66
|
-
}: CustomPillModalContentProps) {
|
|
67
|
-
const { colors, isCompact } = usePluginTheme();
|
|
68
|
-
|
|
69
|
-
const displayText =
|
|
70
|
-
state.modalOutput || state.rawValue || (state.error ? `Error: ${state.error}` : "No output");
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<View style={styles.modalContent}>
|
|
74
|
-
<Card>
|
|
75
|
-
<Card.Header
|
|
76
|
-
title={state.modalTitle ?? state.title}
|
|
77
|
-
subtitle={state.modalDescription}
|
|
78
|
-
icon={state.icon}
|
|
79
|
-
badge={<Badge label={state.displayValue} variant={state.status} />}
|
|
80
|
-
action={
|
|
81
|
-
onRefresh ? (
|
|
82
|
-
<Button
|
|
83
|
-
variant="secondary"
|
|
84
|
-
size="sm"
|
|
85
|
-
icon="RefreshCw"
|
|
86
|
-
loading={isRefreshing}
|
|
87
|
-
label={!isCompact ? "Refresh" : undefined}
|
|
88
|
-
onPress={() => onRefresh()}
|
|
89
|
-
/>
|
|
90
|
-
) : undefined
|
|
91
|
-
}
|
|
92
|
-
/>
|
|
93
|
-
|
|
94
|
-
{/* Monospace Code & Output Box with Built-in Copy */}
|
|
95
|
-
<CodeBlock
|
|
96
|
-
code={displayText}
|
|
97
|
-
title={state.modalTitle ?? state.title}
|
|
98
|
-
maxHeight={280}
|
|
99
|
-
copyable={true}
|
|
100
|
-
/>
|
|
101
|
-
|
|
102
|
-
{/* Footer info */}
|
|
103
|
-
<View style={styles.footerRow}>
|
|
104
|
-
<Text style={[styles.timestampText, { color: colors.foregroundMuted }]}>
|
|
105
|
-
Last updated: {new Date(state.lastUpdated).toLocaleTimeString()}
|
|
106
|
-
</Text>
|
|
107
|
-
</View>
|
|
108
|
-
</Card>
|
|
109
|
-
</View>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export interface RegisterCustomPillsOptions {
|
|
114
|
-
/**
|
|
115
|
-
* The list of custom pill states or definitions.
|
|
116
|
-
*/
|
|
117
|
-
pills: CustomPillState[];
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Callback invoked when a pill needs a fresh refresh or modal command run.
|
|
121
|
-
*/
|
|
122
|
-
onRefreshModal?: (pillId: string) => Promise<{ output?: string; error?: string }>;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Optional visual flair overrides.
|
|
126
|
-
*/
|
|
127
|
-
flair?: Partial<VisualFlair>;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Registers one or more declarative custom metric pills into Paseo's composer trackbar.
|
|
132
|
-
* Automatically handles pill lifecycle, responsive layouts, and drill-down inspection modals.
|
|
133
|
-
*/
|
|
134
|
-
export function registerCustomPills(
|
|
135
|
-
client: ComposerPillRegistrar,
|
|
136
|
-
options: RegisterCustomPillsOptions,
|
|
137
|
-
): PluginCleanup {
|
|
138
|
-
const cleanups: PluginCleanup[] = [];
|
|
139
|
-
|
|
140
|
-
for (const pill of options.pills) {
|
|
141
|
-
const cleanup = registerComposerPill(client, {
|
|
142
|
-
id: pill.id,
|
|
143
|
-
title: pill.title,
|
|
144
|
-
compactTitle: pill.compactTitle,
|
|
145
|
-
icon: pill.icon,
|
|
146
|
-
compactIcon: pill.compactIcon,
|
|
147
|
-
flair: options.flair,
|
|
148
|
-
resolveLabel: () =>
|
|
149
|
-
pill.displayValue ? `${pill.title} ${pill.displayValue}` : pill.title,
|
|
150
|
-
renderModal: () => {
|
|
151
|
-
const [refreshing, setRefreshing] = useState(false);
|
|
152
|
-
const [currentOutput, setCurrentOutput] = useState<string | undefined>(
|
|
153
|
-
pill.modalOutput,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
const handleRefresh = useCallback(async () => {
|
|
157
|
-
if (!options.onRefreshModal) return;
|
|
158
|
-
setRefreshing(true);
|
|
159
|
-
try {
|
|
160
|
-
const res = await options.onRefreshModal(pill.id);
|
|
161
|
-
if (res.output) {
|
|
162
|
-
setCurrentOutput(res.output);
|
|
163
|
-
}
|
|
164
|
-
} finally {
|
|
165
|
-
setRefreshing(false);
|
|
166
|
-
}
|
|
167
|
-
}, [pill.id]);
|
|
168
|
-
|
|
169
|
-
const activeState: CustomPillState = {
|
|
170
|
-
...pill,
|
|
171
|
-
modalOutput: currentOutput ?? pill.modalOutput,
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
return (
|
|
175
|
-
<CustomPillModalContent
|
|
176
|
-
state={activeState}
|
|
177
|
-
onRefresh={options.onRefreshModal ? handleRefresh : undefined}
|
|
178
|
-
isRefreshing={refreshing}
|
|
179
|
-
/>
|
|
180
|
-
);
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
cleanups.push(cleanup);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return () => {
|
|
188
|
-
for (const dispose of cleanups) {
|
|
189
|
-
dispose();
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const styles = StyleSheet.create({
|
|
195
|
-
modalContent: {
|
|
196
|
-
flex: 1,
|
|
197
|
-
minHeight: 0,
|
|
198
|
-
width: "100%",
|
|
199
|
-
padding: 12,
|
|
200
|
-
},
|
|
201
|
-
pillContainer: {
|
|
202
|
-
flexDirection: "row",
|
|
203
|
-
alignItems: "center",
|
|
204
|
-
gap: 6,
|
|
205
|
-
paddingHorizontal: 8,
|
|
206
|
-
paddingVertical: 3,
|
|
207
|
-
},
|
|
208
|
-
pillTitle: {
|
|
209
|
-
fontSize: 12,
|
|
210
|
-
fontWeight: "500",
|
|
211
|
-
},
|
|
212
|
-
pillBadge: {
|
|
213
|
-
paddingVertical: 1,
|
|
214
|
-
paddingHorizontal: 5,
|
|
215
|
-
},
|
|
216
|
-
footerRow: {
|
|
217
|
-
flexDirection: "row",
|
|
218
|
-
justifyContent: "flex-end",
|
|
219
|
-
alignItems: "center",
|
|
220
|
-
marginTop: 8,
|
|
221
|
-
},
|
|
222
|
-
timestampText: {
|
|
223
|
-
fontSize: 11,
|
|
224
|
-
},
|
|
225
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Image, Platform, type ImageStyle, type StyleProp } from "react-native";
|
|
3
|
-
import { Icon } from "./icon";
|
|
4
|
-
import { usePluginTheme } from "./theme/provider";
|
|
5
|
-
import {
|
|
6
|
-
resolveForgeMark,
|
|
7
|
-
type ForgeKind,
|
|
8
|
-
type ForgeMarkInput,
|
|
9
|
-
} from "../../../shared/vendor/paseo-plugin-helper/forge";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Official monochrome forge marks (Simple Icons, CC0 / project trademarks),
|
|
13
|
-
* authored on a 24x24 viewBox. Rendered as inline SVG through a data URI so
|
|
14
|
-
* the helper needs no SVG dependency: exact vector marks on web/Electron,
|
|
15
|
-
* where Paseo renders React Native Web.
|
|
16
|
-
*/
|
|
17
|
-
const FORGE_MARK_PATHS: Partial<Record<ForgeKind, string>> = {
|
|
18
|
-
codeberg:
|
|
19
|
-
"M11.999.747A11.974 11.974 0 0 0 0 12.75c0 2.254.635 4.465 1.833 6.376L11.837 6.19c.072-.092.251-.092.323 0l4.178 5.402h-2.992l.065.239h3.113l.882 1.138h-3.674l.103.374h3.86l.777 1.003h-4.358l.135.483h4.593l.695.894h-5.038l.165.589h5.326l.609.785h-5.717l.182.65h6.038l.562.727h-6.397l.183.65h6.717A12.003 12.003 0 0 0 24 12.75 11.977 11.977 0 0 0 11.999.747zm3.654 19.104.182.65h5.326c.173-.204.353-.433.513-.65zm.385 1.377.18.65h3.563c.233-.198.485-.428.712-.65zm.383 1.377.182.648h1.203c.356-.204.685-.412 1.042-.648zz",
|
|
20
|
-
forgejo:
|
|
21
|
-
"M16.7773 0c1.6018 0 2.9004 1.2986 2.9004 2.9005s-1.2986 2.9004-2.9004 2.9004c-1.0854 0-2.0315-.596-2.5288-1.4787H12.91c-2.3322 0-4.2272 1.8718-4.2649 4.195l-.0007 2.1175a7.0759 7.0759 0 0 1 4.148-1.4205l.1176-.001 1.3385.0002c.4973-.8827 1.4434-1.4788 2.5288-1.4788 1.6018 0 2.9004 1.2986 2.9004 2.9005s-1.2986 2.9004-2.9004 2.9004c-1.0854 0-2.0315-.596-2.5288-1.4787H12.91c-2.3322 0-4.2272 1.8718-4.2649 4.195l-.0007 2.319c.8827.4973 1.4788 1.4434 1.4788 2.5287 0 1.602-1.2986 2.9005-2.9005 2.9005-1.6018 0-2.9004-1.2986-2.9004-2.9005 0-1.0853.596-2.0314 1.4788-2.5287l-.0002-9.9831c0-3.887 3.1195-7.0453 6.9915-7.108l.1176-.001h1.3385C14.7458.5962 15.692 0 16.7773 0ZM7.2227 19.9052c-.6596 0-1.1943.5347-1.1943 1.1943s.5347 1.1943 1.1943 1.1943 1.1944-.5347 1.1944-1.1943-.5348-1.1943-1.1944-1.1943Zm9.5546-10.4644c-.6596 0-1.1944.5347-1.1944 1.1943s.5348 1.1943 1.1944 1.1943c.6596 0 1.1943-.5347 1.1943-1.1943s-.5347-1.1943-1.1943-1.1943Zm0-7.7346c-.6596 0-1.1944.5347-1.1944 1.1943s.5348 1.1943 1.1944 1.1943c.6596 0 1.1943-.5347 1.1943-1.1943s-.5347-1.1943-1.1943-1.1943Z",
|
|
22
|
-
gitea:
|
|
23
|
-
"M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z",
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/** Inline SVG data URI for a custom mark, tinted with the resolved color. */
|
|
27
|
-
export function forgeMarkSource(kind: ForgeKind, color: string): { uri: string } | null {
|
|
28
|
-
const path = FORGE_MARK_PATHS[kind];
|
|
29
|
-
if (!path) return null;
|
|
30
|
-
const svg =
|
|
31
|
-
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">` +
|
|
32
|
-
`<path fill="${color}" d="${path}"/></svg>`;
|
|
33
|
-
return { uri: `data:image/svg+xml,${encodeURIComponent(svg)}` };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface ForgeIconProps extends ForgeMarkInput {
|
|
37
|
-
/** Icon box in points; defaults to 16 to match the host Lucide default. */
|
|
38
|
-
size?: number;
|
|
39
|
-
/** Mark color; defaults to the active theme foreground. */
|
|
40
|
-
color?: string;
|
|
41
|
-
style?: StyleProp<ImageStyle>;
|
|
42
|
-
/** Overrides the default forge-name accessibility label. */
|
|
43
|
-
accessibilityLabel?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Shared forge brand mark. Resolves a host/kind to one mark and renders it:
|
|
48
|
-
* GitHub/GitLab/unknown delegate to the host Lucide set, while Codeberg,
|
|
49
|
-
* Forgejo and Gitea draw their official mono marks inline. On native, where
|
|
50
|
-
* Paseo plugin bundles cannot render SVG, custom marks fall back to their
|
|
51
|
-
* closest Lucide glyph so forges stay distinct.
|
|
52
|
-
*/
|
|
53
|
-
export function ForgeIcon({
|
|
54
|
-
host,
|
|
55
|
-
kind,
|
|
56
|
-
size = 16,
|
|
57
|
-
color,
|
|
58
|
-
style,
|
|
59
|
-
accessibilityLabel,
|
|
60
|
-
}: ForgeIconProps) {
|
|
61
|
-
const { colors } = usePluginTheme();
|
|
62
|
-
const markColor = color ?? colors.foreground;
|
|
63
|
-
const mark = resolveForgeMark({ host, kind });
|
|
64
|
-
const source = mark.custom && Platform.OS === "web" ? forgeMarkSource(mark.kind, markColor) : null;
|
|
65
|
-
|
|
66
|
-
if (!source) {
|
|
67
|
-
return <Icon name={mark.lucideName} size={size} color={markColor} />;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<Image
|
|
72
|
-
accessibilityLabel={accessibilityLabel ?? mark.label}
|
|
73
|
-
accessibilityRole="image"
|
|
74
|
-
accessible
|
|
75
|
-
source={source}
|
|
76
|
-
style={[{ width: size, height: size }, style]}
|
|
77
|
-
/>
|
|
78
|
-
);
|
|
79
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { getClientHost, type HostIconProps } from "./host";
|
|
3
|
-
|
|
4
|
-
let knownIconNames: Set<string> | undefined;
|
|
5
|
-
const warnedIconNames = new Set<string>();
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Optionally registers the set of valid icon names (e.g. Lucide names
|
|
9
|
-
* supported by the host). When set, Icon warns once per unknown name
|
|
10
|
-
* instead of rendering nothing silently.
|
|
11
|
-
*/
|
|
12
|
-
export function setKnownIconNames(names: Iterable<string>): void {
|
|
13
|
-
knownIconNames = new Set(names);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function clearKnownIconNames(): void {
|
|
17
|
-
knownIconNames = undefined;
|
|
18
|
-
warnedIconNames.clear();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function reportUnknownIcon(name: string): void {
|
|
22
|
-
const key = name.trim();
|
|
23
|
-
if (warnedIconNames.has(key)) return;
|
|
24
|
-
warnedIconNames.add(key);
|
|
25
|
-
console.warn(
|
|
26
|
-
`[paseo-plugin-helper Icon] unknown icon name "${name}" — renders nothing; check the Lucide name`,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function Icon(props: HostIconProps) {
|
|
31
|
-
const rawName = typeof props.name === "string" ? props.name : "";
|
|
32
|
-
if (!rawName.trim()) {
|
|
33
|
-
reportUnknownIcon(String(props.name));
|
|
34
|
-
} else if (knownIconNames && !knownIconNames.has(rawName.trim())) {
|
|
35
|
-
reportUnknownIcon(rawName);
|
|
36
|
-
}
|
|
37
|
-
const { Icon: HostIconComponent } = getClientHost();
|
|
38
|
-
return <HostIconComponent {...props} />;
|
|
39
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export * from "./theme/index";
|
|
2
|
-
export * from "./styles/index";
|
|
3
|
-
export * from "./components/index";
|
|
4
|
-
export * from "./layout/index";
|
|
5
|
-
export * from "./pill";
|
|
6
|
-
export * from "./surface";
|
|
7
|
-
export * from "./command-center";
|
|
8
|
-
export * from "./panel";
|
|
9
|
-
export * from "./query";
|
|
10
|
-
export * from "./query-refresh";
|
|
11
|
-
export * from "./snapshot";
|
|
12
|
-
export * from "./settings";
|
|
13
|
-
export * from "./shared-settings";
|
|
14
|
-
export * from "./settings-screen";
|
|
15
|
-
export * from "./utils/clipboard";
|
|
16
|
-
export * from "./utils/haptics";
|
|
17
|
-
export * from "./custom-pills";
|
|
18
|
-
export * from "./host";
|
|
19
|
-
export { Icon } from "./icon";
|
|
20
|
-
export { ForgeIcon, forgeMarkSource, type ForgeIconProps } from "./forge-icon";
|
|
21
|
-
export {
|
|
22
|
-
forgeKindFromHost,
|
|
23
|
-
isForgeKind,
|
|
24
|
-
normalizeForgeHost,
|
|
25
|
-
resolveForgeMark,
|
|
26
|
-
type ForgeKind,
|
|
27
|
-
type ForgeMarkInput,
|
|
28
|
-
type ResolvedForgeMark,
|
|
29
|
-
} from "../../../shared/vendor/paseo-plugin-helper/forge";
|
|
30
|
-
export * from "./tickets";
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import React, { type ReactNode } from "react";
|
|
2
|
-
import { StyleSheet, View, type StyleProp, type ViewStyle } from "react-native";
|
|
3
|
-
import { usePluginTheme } from "../theme/provider";
|
|
4
|
-
|
|
5
|
-
export interface ActionBarProps {
|
|
6
|
-
children: ReactNode;
|
|
7
|
-
align?: "flex-start" | "flex-end" | "center" | "space-between";
|
|
8
|
-
direction?: "row" | "column" | "auto";
|
|
9
|
-
style?: StyleProp<ViewStyle>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Responsive action toolbar for modals and surfaces.
|
|
14
|
-
* Automatically wraps or stacks on compact/mobile layouts.
|
|
15
|
-
*/
|
|
16
|
-
export function ActionBar({
|
|
17
|
-
children,
|
|
18
|
-
align = "flex-end",
|
|
19
|
-
direction = "auto",
|
|
20
|
-
style,
|
|
21
|
-
}: ActionBarProps) {
|
|
22
|
-
const { isCompact, padding } = usePluginTheme();
|
|
23
|
-
|
|
24
|
-
const isColumn = direction === "column" || (direction === "auto" && isCompact);
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<View
|
|
28
|
-
style={[
|
|
29
|
-
styles.container,
|
|
30
|
-
{
|
|
31
|
-
flexDirection: isColumn ? "column" : "row",
|
|
32
|
-
justifyContent: isColumn ? "flex-start" : align,
|
|
33
|
-
alignItems: isColumn ? "stretch" : "center",
|
|
34
|
-
gap: isCompact ? 8 : 10,
|
|
35
|
-
marginTop: padding.vertical,
|
|
36
|
-
},
|
|
37
|
-
style,
|
|
38
|
-
]}
|
|
39
|
-
>
|
|
40
|
-
{children}
|
|
41
|
-
</View>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const styles = StyleSheet.create({
|
|
46
|
-
container: {
|
|
47
|
-
flexWrap: "wrap",
|
|
48
|
-
},
|
|
49
|
-
});
|