From 0f37f674069f765cabf1e56325fd8df499db11a0 Mon Sep 17 00:00:00 2001 From: ThatNerdSquared <72814106+ThatNerdSquared@users.noreply.github.com> Date: Tue, 16 Jul 2024 05:09:10 -0700 Subject: [PATCH] fix(Timers): alert sound failure, close window on start pref (#13457) * fix(Timers): alert sound failure, close window on start pref * Update CHANGELOG.md * Update CHANGELOG.md and optimise images --------- Co-authored-by: Milena Araujo Co-authored-by: raycastbot --- extensions/timers/CHANGELOG.md | 8 ++ extensions/timers/package-lock.json | 72 +++++++------- extensions/timers/package.json | 8 +- .../timers/src/backend/stopwatchBackend.ts | 3 +- extensions/timers/src/backend/timerBackend.ts | 2 +- .../src/components/CustomTimerListItem.tsx | 53 ++++++++++ .../timers/src/components/RenameAction.tsx | 20 ++++ .../src/{ => components}/RenameView.tsx | 24 +++-- .../src/components/RunningTimerListItem.tsx | 43 ++++++++ extensions/timers/src/manageStopwatches.tsx | 18 ++-- extensions/timers/src/manageTimers.tsx | 98 ++----------------- extensions/timers/src/startCustomTimer.tsx | 5 +- 12 files changed, 199 insertions(+), 155 deletions(-) create mode 100644 extensions/timers/src/components/CustomTimerListItem.tsx create mode 100644 extensions/timers/src/components/RenameAction.tsx rename extensions/timers/src/{ => components}/RenameView.tsx (60%) create mode 100644 extensions/timers/src/components/RunningTimerListItem.tsx diff --git a/extensions/timers/CHANGELOG.md b/extensions/timers/CHANGELOG.md index ab0f09a1e4..ba10f8aba0 100644 --- a/extensions/timers/CHANGELOG.md +++ b/extensions/timers/CHANGELOG.md @@ -1,6 +1,14 @@ # Timers Changelog +## [Bugfixes and improvements] - 2024-07-16 + +- Fix bug where alert sound would not play if osascript notification command failed due to lack of permissions +- Fix bug where quicklink-root-presets would not close properly if "Automatically close window on start" was disabled +- Add icons to "Manage Timers" and "Manage Stopwatches" command actions +- Various code improvements + ## [Persistent commands, codebase cleanup] - 2024-05-19 + - Add preference to keep "Manage Timers" and "Manage Stopwatches" commands open on timer/stopwatch start - Various refactors around the codebase diff --git a/extensions/timers/package-lock.json b/extensions/timers/package-lock.json index a6befb530c..071c37d57f 100644 --- a/extensions/timers/package-lock.json +++ b/extensions/timers/package-lock.json @@ -7,14 +7,14 @@ "name": "timers", "license": "MIT", "dependencies": { - "@raycast/api": "^1.65.1" + "@raycast/api": "^1.78.1" }, "devDependencies": { "@raycast/eslint-config": "^1.0.8", - "@types/node": "~20.11.5", - "@types/react": "^18.2.48", + "@types/node": "~20.14.10", + "@types/react": "^18.3.3", "eslint": "^8.56.0", - "typescript": "^5.3.3" + "typescript": "^5.5.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -195,22 +195,22 @@ } }, "node_modules/@raycast/api": { - "version": "1.65.1", - "resolved": "https://registry.npmjs.org/@raycast/api/-/api-1.65.1.tgz", - "integrity": "sha512-TnlaEyzRMXzHQ7QnT6MpeIz2K1Uap5eQHRqHCXde9ksiplRAdV/nW2XJY1djlGfdQOxhQZfgJZNqhqmV9fa3Bg==", + "version": "1.78.1", + "resolved": "https://registry.npmjs.org/@raycast/api/-/api-1.78.1.tgz", + "integrity": "sha512-DZ3KdS/fIZba7PHzBpWYU2w3MXnr/RC7RgwAlU839G0pIwayP6/gwecsmJPRdQ3wuHIH4iX91aUthBKmTib9WQ==", "hasInstallScript": true, "dependencies": { "@types/node": "^20.8.10", - "@types/react": "^18.2.27", - "react": "18.2.0" + "@types/react": "^18.3.3", + "react": "18.3.1" }, "bin": { "ray": "bin/ray" }, "peerDependencies": { "@types/node": "20.8.10", - "@types/react": "18.2.27", - "react-devtools": "4.28.4" + "@types/react": "18.3.3", + "react-devtools": "5.2.0" }, "peerDependenciesMeta": { "@types/node": { @@ -268,33 +268,27 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", - "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.2.48", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", - "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, "node_modules/@types/semver": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", @@ -714,12 +708,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1136,9 +1130,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -1709,9 +1703,9 @@ ] }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -1948,9 +1942,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/extensions/timers/package.json b/extensions/timers/package.json index 482072d1fe..2c2b878626 100644 --- a/extensions/timers/package.json +++ b/extensions/timers/package.json @@ -317,14 +317,14 @@ } ], "dependencies": { - "@raycast/api": "^1.65.1" + "@raycast/api": "^1.78.1" }, "devDependencies": { "@raycast/eslint-config": "^1.0.8", - "@types/node": "~20.11.5", - "@types/react": "^18.2.48", + "@types/node": "~20.14.10", + "@types/react": "^18.3.3", "eslint": "^8.56.0", - "typescript": "^5.3.3" + "typescript": "^5.5.3" }, "scripts": { "build": "ray build -e dist", diff --git a/extensions/timers/src/backend/stopwatchBackend.ts b/extensions/timers/src/backend/stopwatchBackend.ts index 3991cf01c1..bbb04feceb 100644 --- a/extensions/timers/src/backend/stopwatchBackend.ts +++ b/extensions/timers/src/backend/stopwatchBackend.ts @@ -1,4 +1,4 @@ -import { environment, popToRoot } from "@raycast/api"; +import { environment } from "@raycast/api"; import { execSync } from "child_process"; import { randomUUID } from "crypto"; import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs"; @@ -56,7 +56,6 @@ const startStopwatch = async ({ swName = "Untitled", launchedFromMenuBar = false swStore.push(newTimer); writeFileSync(SWPATH, JSON.stringify(swStore)); - popToRoot(); showHudOrToast({ msg: `Stopwatch "${swName}" started!`, launchedFromMenuBar: launchedFromMenuBar, isErr: false }); }; diff --git a/extensions/timers/src/backend/timerBackend.ts b/extensions/timers/src/backend/timerBackend.ts index 5bd98f25e9..450c9a6b73 100644 --- a/extensions/timers/src/backend/timerBackend.ts +++ b/extensions/timers/src/backend/timerBackend.ts @@ -59,7 +59,7 @@ async function startTimer({ cmdParts.push(`while [ -f "${dismissFile}" ]; do ${afplayString}; done`); } cmdParts.push(`rm "${masterName}"; else echo "Timer deleted"; fi`); - exec(cmdParts.join(" && "), (error, stderr) => { + exec(cmdParts.join(" ; "), (error, stderr) => { if (error) { console.log(`error: ${error.message}`); return; diff --git a/extensions/timers/src/components/CustomTimerListItem.tsx b/extensions/timers/src/components/CustomTimerListItem.tsx new file mode 100644 index 0000000000..0da0ce7de3 --- /dev/null +++ b/extensions/timers/src/components/CustomTimerListItem.tsx @@ -0,0 +1,53 @@ +import { Action, ActionPanel, Icon, List } from "@raycast/api"; +import { CommandLinkParams, CustomTimer } from "../backend/types"; +import { formatTime } from "../backend/formatUtils"; +import useTimers from "../hooks/useTimers"; +import RenameAction from "./RenameAction"; + +const createPresetLink = (ctID: string): string => { + const payload: CommandLinkParams = { timerID: ctID }; + const encodedPayload = encodeURIComponent(JSON.stringify(payload)); + return `raycast://extensions/ThatNerd/timers/manageTimers?context=${encodedPayload}`; +}; + +export default function CustomTimerListItem(props: { customTimer: CustomTimer; id: string }) { + const { handleStartCT, handleDeleteCT } = useTimers(); + return ( + + handleStartCT({ customTimer: props.customTimer })} + /> + + handleDeleteCT(props.id)} + /> + + + } + /> + ); +} diff --git a/extensions/timers/src/components/RenameAction.tsx b/extensions/timers/src/components/RenameAction.tsx new file mode 100644 index 0000000000..ef610fa7bb --- /dev/null +++ b/extensions/timers/src/components/RenameAction.tsx @@ -0,0 +1,20 @@ +import { Action, Icon, useNavigation } from "@raycast/api"; +import { RenameView, RenameViewProps } from "./RenameView"; + +interface RenameActionProps extends RenameViewProps { + renameLabel: string; +} + +export default function RenameAction(props: RenameActionProps) { + const { push } = useNavigation(); + + return ( + + push() + } + /> + ); +} diff --git a/extensions/timers/src/RenameView.tsx b/extensions/timers/src/components/RenameView.tsx similarity index 60% rename from extensions/timers/src/RenameView.tsx rename to extensions/timers/src/components/RenameView.tsx index 13c82319c0..f20734be99 100644 --- a/extensions/timers/src/RenameView.tsx +++ b/extensions/timers/src/components/RenameView.tsx @@ -1,14 +1,22 @@ -import { Action, ActionPanel, Form, popToRoot, Toast } from "@raycast/api"; -import { renameStopwatch } from "./backend/stopwatchBackend"; -import { renameCustomTimer, renameTimer } from "./backend/timerBackend"; +import { Action, ActionPanel, Form, Toast, useNavigation } from "@raycast/api"; +import { renameStopwatch } from "../backend/stopwatchBackend"; +import { renameCustomTimer, renameTimer } from "../backend/timerBackend"; +import { showHudOrToast } from "../backend/utils"; -export default function RenameView(props: { currentName: string; originalFile: string; ctID: string | null }) { +interface RenameViewProps { + currentName: string; + originalFile: string; + ctID: string | null; +} + +function RenameView(props: RenameViewProps) { + const { pop } = useNavigation(); const handleSubmit = (newName: string) => { if (newName === "" || newName === props.currentName) { const toast = new Toast({ style: Toast.Style.Failure, title: "No new name given!" }); toast.show(); } else { - popToRoot(); + pop(); switch (props.originalFile) { case "customTimer": renameCustomTimer(props.ctID ? props.ctID : "-99", newName); @@ -20,8 +28,8 @@ export default function RenameView(props: { currentName: string; originalFile: s renameTimer(props.originalFile, newName); break; } - const toast = new Toast({ style: Toast.Style.Success, title: `Renamed to ${newName}!` }); - toast.show(); + + showHudOrToast({ msg: `Renamed to ${newName}!`, launchedFromMenuBar: false, isErr: false }); } }; @@ -37,3 +45,5 @@ export default function RenameView(props: { currentName: string; originalFile: s ); } + +export { type RenameViewProps, RenameView }; diff --git a/extensions/timers/src/components/RunningTimerListItem.tsx b/extensions/timers/src/components/RunningTimerListItem.tsx new file mode 100644 index 0000000000..df6c1e90f1 --- /dev/null +++ b/extensions/timers/src/components/RunningTimerListItem.tsx @@ -0,0 +1,43 @@ +import { Action, ActionPanel, Color, Icon, List } from "@raycast/api"; +import { Timer } from "../backend/types"; +import { formatDateTime, formatTime } from "../backend/formatUtils"; +import useTimers from "../hooks/useTimers"; +import RenameAction from "./RenameAction"; + +interface RunningTimerListItemProps { + timer: Timer; +} + +const runningLabel = { tag: { value: "Running", color: Color.Yellow } }; +const finishedLabel = { tag: { value: "Finished!", color: Color.Green } }; + +export default function RunningTimerListItem({ timer }: RunningTimerListItemProps) { + const { handleStopTimer, handleCreateCT } = useTimers(); + return ( + + handleStopTimer(timer)} /> + + handleCreateCT(timer)} + /> + + } + /> + ); +} diff --git a/extensions/timers/src/manageStopwatches.tsx b/extensions/timers/src/manageStopwatches.tsx index 52db8b5678..53f3f32c94 100644 --- a/extensions/timers/src/manageStopwatches.tsx +++ b/extensions/timers/src/manageStopwatches.tsx @@ -1,9 +1,9 @@ -import { Action, ActionPanel, Color, Icon, List, useNavigation } from "@raycast/api"; +import { Action, ActionPanel, Color, Icon, List } from "@raycast/api"; import { useEffect } from "react"; import useStopwatches from "./hooks/useStopwatches"; -import RenameView from "./RenameView"; import { formatTime, formatDateTime } from "./backend/formatUtils"; import { Stopwatch } from "./backend/types"; +import RenameAction from "./components/RenameAction"; export default function Command() { const { @@ -16,7 +16,6 @@ export default function Command() { handlePauseSW, handleUnpauseSW, } = useStopwatches(); - const { push } = useNavigation(); useEffect(() => { refreshSWes(); @@ -48,14 +47,11 @@ export default function Command() { actions={ {sw.lastPaused == "----" ? ( - handlePauseSW(sw.swID)} /> + handlePauseSW(sw.swID)} /> ) : ( - handleUnpauseSW(sw.swID)} /> + handleUnpauseSW(sw.swID)} /> )} - push()} - /> + handleRestartSW(sw)} /> handleStopSW(sw)} /> @@ -82,7 +80,7 @@ export default function Command() { subtitle={"Press Enter to start a stopwatch"} actions={ - handleStartSW({})} /> + handleStartSW({})} /> } /> diff --git a/extensions/timers/src/manageTimers.tsx b/extensions/timers/src/manageTimers.tsx index b6345a35a4..25ce8c457f 100644 --- a/extensions/timers/src/manageTimers.tsx +++ b/extensions/timers/src/manageTimers.tsx @@ -1,11 +1,11 @@ -import { Action, ActionPanel, Color, Icon, LaunchProps, List, Toast, showToast, useNavigation } from "@raycast/api"; +import { Action, ActionPanel, Icon, LaunchProps, List, Toast, popToRoot, showToast, useNavigation } from "@raycast/api"; import { useEffect } from "react"; import useTimers from "./hooks/useTimers"; -import RenameView from "./RenameView"; import CustomTimerView from "./startCustomTimer"; -import { formatDateTime, formatTime } from "./backend/formatUtils"; import { CommandLinkParams } from "./backend/types"; import { readCustomTimers, startTimer } from "./backend/timerBackend"; +import RunningTimerListItem from "./components/RunningTimerListItem"; +import CustomTimerListItem from "./components/CustomTimerListItem"; export default function Command(props: LaunchProps<{ launchContext: CommandLinkParams }>) { if (props.launchContext?.timerID) { @@ -17,6 +17,7 @@ export default function Command(props: LaunchProps<{ launchContext: CommandLinkP title: "This custom timer no longer exists!", }); } else { + popToRoot(); startTimer({ timeInSeconds: ct.timeInSeconds, timerName: ct.name, @@ -26,16 +27,7 @@ export default function Command(props: LaunchProps<{ launchContext: CommandLinkP } } - const { - timers, - customTimers, - isLoading, - refreshTimers, - handleStopTimer, - handleStartCT, - handleCreateCT, - handleDeleteCT, - } = useTimers(); + const { timers, customTimers, isLoading, refreshTimers } = useTimers(); const { push } = useNavigation(); useEffect(() => { @@ -45,50 +37,10 @@ export default function Command(props: LaunchProps<{ launchContext: CommandLinkP }, 1000); }, []); - const runningIcon = { tag: { value: "Running", color: Color.Yellow } }; - const finishedIcon = { tag: { value: "Finished!", color: Color.Green } }; - - const createPresetLink = (ctID: string): string => { - const payload: CommandLinkParams = { timerID: ctID }; - const encodedPayload = encodeURIComponent(JSON.stringify(payload)); - return `raycast://extensions/ThatNerd/timers/manageTimers?context=${encodedPayload}`; - }; - return ( - {timers?.map((timer) => ( - - handleStopTimer(timer)} /> - - push() - } - /> - handleCreateCT(timer)} - /> - - } - /> - ))} + {timers?.map((timer) => )} push()} /> @@ -109,42 +62,7 @@ export default function Command(props: LaunchProps<{ launchContext: CommandLinkP ?.sort((a, b) => { return customTimers[a].timeInSeconds - customTimers[b].timeInSeconds; }) - .map((ctID) => ( - - handleStartCT({ customTimer: customTimers[ctID] })} /> - - push( - , - ) - } - /> - handleDeleteCT(ctID)} - /> - - - } - /> - ))} + .map((ctID) => )} ); diff --git a/extensions/timers/src/startCustomTimer.tsx b/extensions/timers/src/startCustomTimer.tsx index 1de69eb76e..a4151114c1 100644 --- a/extensions/timers/src/startCustomTimer.tsx +++ b/extensions/timers/src/startCustomTimer.tsx @@ -1,4 +1,4 @@ -import { Action, ActionPanel, closeMainWindow, Form, getPreferenceValues, Toast } from "@raycast/api"; +import { Action, ActionPanel, Form, getPreferenceValues, Toast, useNavigation } from "@raycast/api"; import { useState } from "react"; import { soundData } from "./backend/soundData"; import { checkForOverlyLoudAlert, createCustomTimer, ensureCTFileExists, startTimer } from "./backend/timerBackend"; @@ -9,6 +9,7 @@ export default function CustomTimerView(props: { arguments: CTInlineArgs }) { const [hourErr, setHourErr] = useState(); const [minErr, setMinErr] = useState(); const [secErr, setSecErr] = useState(); + const { pop } = useNavigation(); const prefs: Preferences = getPreferenceValues(); @@ -25,7 +26,7 @@ export default function CustomTimerView(props: { arguments: CTInlineArgs }) { setSecErr("Seconds must be a number!"); } else { if (!checkForOverlyLoudAlert()) return; - closeMainWindow(); + pop(); const timerName = values.name ? values.name : "Untitled"; const timeInSeconds = 3600 * Number(values.hours) + 60 * Number(values.minutes) + Number(values.seconds); startTimer({