Skip to content
Open
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
1 change: 1 addition & 0 deletions apps/desktop/src/settings/DesktopClientSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const clientSettings: ClientSettings = {
confirmQuit: true,
confirmThreadArchive: true,
confirmThreadDelete: false,
confirmThreadUnpin: false,
dismissedProviderUpdateNotificationKeys: [],
diffIgnoreWhitespace: true,
environmentIdentificationMode: "artwork",
Expand Down
18 changes: 17 additions & 1 deletion apps/web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,7 @@ export default function Sidebar() {
const autoSettleOnMerge = useClientSettings((s) => s.sidebarAutoSettleOnMerge);
const confirmThreadDelete = useClientSettings((s) => s.confirmThreadDelete);
const confirmThreadArchive = useClientSettings((s) => s.confirmThreadArchive);
const confirmThreadUnpin = useClientSettings((s) => s.confirmThreadUnpin);
const sidebarProjectSortOrder = useClientSettings((s) => s.sidebarProjectSortOrder);
const timestampFormat = useClientSettings((s) => s.timestampFormat);
const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
Expand Down Expand Up @@ -2647,6 +2648,21 @@ export default function Sidebar() {
const attemptUnpin = useCallback(
(threadRef: ScopedThreadRef) => {
void (async () => {
if (confirmThreadUnpin) {
const api = readLocalApi();
const thread = threadByKeyRef.current.get(scopedThreadKey(threadRef));
if (api) {
const confirmed = await settlePromise(() =>
api.dialogs.confirm(
[
`Unpin thread "${thread?.title ?? "this thread"}"?`,
"This will move the thread out of your pinned section.",
].join("\n"),
),
);
if (confirmed._tag === "Failure" || !confirmed.value) return;
}
}
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
const result = await unpinThread(threadRef);
if (result._tag === "Failure" && !isAtomCommandInterrupted(result)) {
const error = squashAtomCommandFailure(result);
Expand All @@ -2660,7 +2676,7 @@ export default function Sidebar() {
}
})();
},
[unpinThread],
[confirmThreadUnpin, unpinThread],
);

const handlePinnedDragEnd = useCallback(
Expand Down
31 changes: 31 additions & 0 deletions apps/web/src/components/settings/SettingsPanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,9 @@ export function useSettingsRestore(onRestored?: () => void) {
...(settings.confirmThreadDelete !== DEFAULT_UNIFIED_SETTINGS.confirmThreadDelete
? ["Delete confirmation"]
: []),
...(settings.confirmThreadUnpin !== DEFAULT_UNIFIED_SETTINGS.confirmThreadUnpin
? ["Unpin confirmation"]
: []),
...(settings.confirmQuit !== DEFAULT_UNIFIED_SETTINGS.confirmQuit
? ["Quit confirmation"]
: []),
Expand All @@ -547,6 +550,7 @@ export function useSettingsRestore(onRestored?: () => void) {
settings.confirmQuit,
settings.confirmThreadArchive,
settings.confirmThreadDelete,
settings.confirmThreadUnpin,
settings.addProjectBaseDirectory,
settings.defaultThreadEnvMode,
settings.newWorktreesStartFromOrigin,
Expand Down Expand Up @@ -658,6 +662,7 @@ export function useSettingsRestore(onRestored?: () => void) {
addProjectBaseDirectory: DEFAULT_UNIFIED_SETTINGS.addProjectBaseDirectory,
confirmThreadArchive: DEFAULT_UNIFIED_SETTINGS.confirmThreadArchive,
confirmThreadDelete: DEFAULT_UNIFIED_SETTINGS.confirmThreadDelete,
confirmThreadUnpin: DEFAULT_UNIFIED_SETTINGS.confirmThreadUnpin,
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
confirmQuit: DEFAULT_UNIFIED_SETTINGS.confirmQuit,
textGenerationModelSelection: DEFAULT_UNIFIED_SETTINGS.textGenerationModelSelection,
fontFamilySans: DEFAULT_UNIFIED_SETTINGS.fontFamilySans,
Expand Down Expand Up @@ -2227,6 +2232,32 @@ export function GeneralSettingsPanel() {
}
/>

<SettingsRow
Comment thread
UtkarshUsername marked this conversation as resolved.
{...searchableSetting("unpin-confirmation")}
description="Ask before unpinning a thread from the pinned section."
resetAction={
settings.confirmThreadUnpin !== DEFAULT_UNIFIED_SETTINGS.confirmThreadUnpin ? (
<SettingResetButton
label="unpin confirmation"
onClick={() =>
updateSettings({
confirmThreadUnpin: DEFAULT_UNIFIED_SETTINGS.confirmThreadUnpin,
})
}
/>
) : null
}
control={
<Switch
checked={settings.confirmThreadUnpin}
onCheckedChange={(checked) =>
updateSettings({ confirmThreadUnpin: Boolean(checked) })
}
aria-label="Confirm thread unpinning"
/>
}
/>

<SettingsRow
{...searchableSetting("archive-confirmation")}
description="Require a second click on the inline archive action before a thread is archived."
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/components/settings/settingsSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ export const SETTINGS_SEARCH_ITEMS = [
title: "Add project starts in",
to: "/settings/general",
},
{
id: "unpin-confirmation",
title: "Unpin confirmation",
to: "/settings/general",
},
{
id: "archive-confirmation",
title: "Archive confirmation",
Expand Down
16 changes: 15 additions & 1 deletion apps/web/src/hooks/useThreadActionMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export function useThreadActionMenu(input: {
const autoSettleOnMerge = useClientSettings((s) => s.sidebarAutoSettleOnMerge);
const confirmThreadDelete = useClientSettings((s) => s.confirmThreadDelete);
const confirmThreadArchive = useClientSettings((s) => s.confirmThreadArchive);
const confirmThreadUnpin = useClientSettings((s) => s.confirmThreadUnpin);
const timestampFormat = useClientSettings((s) => s.timestampFormat);
const { copyToClipboard: copyPathToClipboard } = useCopyToClipboard<{ path: string }>({
onCopy: ({ path }) => {
Expand Down Expand Up @@ -215,9 +216,21 @@ export function useThreadActionMenu(input: {
case "pin":
await reportFailure("Failed to pin thread", () => pinThread(threadRef));
return;
case "unpin":
case "unpin": {
if (confirmThreadUnpin) {
const confirmed = await settlePromise(() =>
api.dialogs.confirm(
[
`Unpin thread "${thread.title}"?`,
"This will move the thread out of your pinned section.",
].join("\n"),
),
);
if (confirmed._tag === "Failure" || !confirmed.value) return;
}
await reportFailure("Failed to unpin thread", () => unpinThread(threadRef));
return;
}
case "rename":
onStartRename();
return;
Expand Down Expand Up @@ -315,6 +328,7 @@ export function useThreadActionMenu(input: {
changeRequest,
confirmThreadArchive,
confirmThreadDelete,
confirmThreadUnpin,
copyBranchToClipboard,
copyPathToClipboard,
copyThreadIdToClipboard,
Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export const ClientSettingsSchema = Schema.Struct({
confirmQuit: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))),
confirmThreadArchive: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
confirmThreadDelete: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))),
confirmThreadUnpin: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
dismissedProviderUpdateNotificationKeys: Schema.Array(TrimmedNonEmptyString).pipe(
Schema.withDecodingDefault(Effect.succeed([])),
),
Expand Down Expand Up @@ -867,6 +868,7 @@ export const ClientSettingsPatch = Schema.Struct({
confirmQuit: Schema.optionalKey(Schema.Boolean),
confirmThreadArchive: Schema.optionalKey(Schema.Boolean),
confirmThreadDelete: Schema.optionalKey(Schema.Boolean),
confirmThreadUnpin: Schema.optionalKey(Schema.Boolean),
diffIgnoreWhitespace: Schema.optionalKey(Schema.Boolean),
environmentIdentificationMode: Schema.optionalKey(EnvironmentIdentificationMode),
glassOpacity: Schema.optionalKey(GlassOpacity),
Expand Down
Loading