Skip to content

Commit 153eb16

Browse files
committed
feat: add display for masked text, copy unmasked text
1 parent 32f558d commit 153eb16

File tree

3 files changed

+89
-14
lines changed

3 files changed

+89
-14
lines changed

main/snippets/AuthCodeBlock.jsx

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,22 @@ export const AuthCodeBlock = ({
55
highlight,
66
children,
77
}) => {
8-
const [processedChildren, setProcessedChildren] = useState(children);
8+
const [displayText, setDisplayText] = useState(children);
9+
const [copyText, setCopyText] = useState(children);
10+
const wrapperRef = React.useRef(null);
911

1012
useEffect(() => {
1113
let unsubscribe = null;
1214

1315
function init() {
16+
if (!window.autorun || !window.rootStore) {
17+
return;
18+
}
19+
1420
unsubscribe = window.autorun(() => {
15-
let processedChildren = children;
21+
let processedChildrenForDisplay = children;
22+
let processedChildrenForCopy = children;
23+
1624
for (const [
1725
key,
1826
value,
@@ -21,12 +29,27 @@ export const AuthCodeBlock = ({
2129
/[.*+?^${}()|[\]\\]/g,
2230
String.raw`\$&`
2331
);
24-
processedChildren = processedChildren.replaceAll(
32+
33+
// For display: mask client secret if it's not the placeholder
34+
let displayValue = value;
35+
if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
36+
displayValue = value.substring(0, 3) + "*****MASKED*****";
37+
}
38+
39+
processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(
40+
new RegExp(escapedKey, "g"),
41+
displayValue
42+
);
43+
44+
// For copy: use the actual value (unmasked)
45+
processedChildrenForCopy = processedChildrenForCopy.replaceAll(
2546
new RegExp(escapedKey, "g"),
2647
value
2748
);
2849
}
29-
setProcessedChildren(processedChildren);
50+
51+
setDisplayText(processedChildrenForDisplay);
52+
setCopyText(processedChildrenForCopy);
3053
});
3154
}
3255

@@ -42,15 +65,65 @@ export const AuthCodeBlock = ({
4265
};
4366
}, [children]);
4467

68+
// Override clipboard write to copy unmasked text
69+
useEffect(() => {
70+
if (!wrapperRef.current) return;
71+
72+
const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
73+
let isOverriding = false;
74+
75+
const handleClick = (e) => {
76+
const button = e.target.closest('[data-testid="copy-code-button"]');
77+
if (!button || !wrapperRef.current.contains(button)) return;
78+
79+
// Set flag to override next clipboard write
80+
isOverriding = true;
81+
82+
// Override writeText temporarily
83+
navigator.clipboard.writeText = (text) => {
84+
85+
if (isOverriding) {
86+
isOverriding = false;
87+
// Restore original immediately
88+
navigator.clipboard.writeText = originalWriteText;
89+
// Write our copyText instead
90+
return originalWriteText(copyText);
91+
}
92+
return originalWriteText(text);
93+
};
94+
95+
// Reset after a short delay in case the write doesn't happen
96+
setTimeout(() => {
97+
if (isOverriding) {
98+
isOverriding = false;
99+
navigator.clipboard.writeText = originalWriteText;
100+
}
101+
}, 100);
102+
};
103+
104+
const wrapper = wrapperRef.current;
105+
wrapper.addEventListener('click', handleClick, true);
106+
107+
return () => {
108+
wrapper.removeEventListener('click', handleClick, true);
109+
// Restore original if still overridden
110+
if (navigator.clipboard.writeText !== originalWriteText) {
111+
navigator.clipboard.writeText = originalWriteText;
112+
}
113+
};
114+
}, [copyText]);
115+
45116
return (
46-
<CodeBlock
47-
filename={filename}
48-
icon={icon}
49-
language={language}
50-
lines
51-
highlight={highlight}
52-
>
53-
{processedChildren}
54-
</CodeBlock>
117+
<div ref={wrapperRef}>
118+
<CodeBlock
119+
filename={filename}
120+
icon={icon}
121+
language={language}
122+
lines
123+
highlight={highlight}
124+
>
125+
{displayText}
126+
</CodeBlock>
127+
</div>
55128
);
56129
};

main/snippets/recipe.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,9 @@ export const CreateInteractiveApp = ({
684684
const init = () => setStoreReady(true);
685685

686686
if (window.rootStore) {
687-
// If this create component is re-mounted, clear any selected client
687+
// If this create component is re-mounted, clear any selected client information
688688
window.rootStore.clientStore.setSelectedClient(null);
689+
window.rootStore.clientStore.setSelectedClientSecret(undefined);
689690
init();
690691
} else {
691692
window.addEventListener('adu:storeReady', init);

ui/src/stores/client-store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class ClientStore {
5959
reset() {
6060
this.clients = [];
6161
this.selectedClientId = null;
62+
this.selectedClientSecret = undefined;
6263
}
6364

6465
setSelectedClient(clientId: string | null) {

0 commit comments

Comments
 (0)