Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade JS dependencies to latest versions #66

Merged
merged 9 commits into from
Nov 2, 2024
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "17.x"
node-version: "20.x"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little bizarre - CI specified 17.x, but our Vercel deployment was still using 14.x (it doesn't even support non-LTS versions). Now, they're both using 20.x.

- name: Install dependencies
run: npm install
- name: Run lint
Expand Down
6 changes: 2 additions & 4 deletions components/WorkflowCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ const WorkflowCard = ({ workflow, isSearchResult }: WorkflowCardProps) => {

// Be default we should use the <a> tag for the cards so search crawlers can find the URLs.
const LinkCard = ({ children }: { children: React.ReactNode }) => (
<Link href={destination}>
<a className={CARD_STYLE} onClick={trackClick}>
{children}
</a>
<Link href={destination} className={CARD_STYLE} onClick={trackClick}>
{children}
Comment on lines -26 to +27
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<Link> components now render directly as <a> tags as of Next 13. See this for more details. I ran their suggested codemod to upgrade our usages.

</Link>
);

Expand Down
9 changes: 5 additions & 4 deletions components/WorkflowTags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ export default function WorkflowTags({ tags }: { tags: string[] }) {
return (
<div className="flex mt-1 flex-wrap">
{tags.map((tag, id) => (
<Link key={id} href={`/categories/${tag}`}>
<a className="rounded-full text-black dark:text-white bg-pill-light dark:bg-pill-dark px-5 my-1 mr-2 text-sm flex flex-col justify-center text-center hover:opacity-60">
{tag}
</a>
<Link
key={id}
href={`/categories/${tag}`}
className="rounded-full text-black dark:text-white bg-pill-light dark:bg-pill-dark px-5 my-1 mr-2 text-sm flex flex-col justify-center text-center hover:opacity-60">
{tag}
</Link>
))}
</div>
Expand Down
26 changes: 12 additions & 14 deletions components/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,18 @@ const Footer = () => (
</div>
<p className="text-center text-black dark:text-white">
Made with ❤️ by{" "}
<Link href="https://www.warp.dev">
<a
className="underline hover:opacity-60"
onClick={(e) => {
gtag.event({
action: "click_on_footer_landing_page",
category: "Click on Landing Page",
label: "Click on Landing Page via Footer",
value: window.location.pathname,
});
}}
>
the Warp Team and community
</a>
<Link
href="https://www.warp.dev"
className="underline hover:opacity-60"
onClick={(e) => {
gtag.event({
action: "click_on_footer_landing_page",
category: "Click on Landing Page",
label: "Click on Landing Page via Footer",
value: window.location.pathname,
});
}}>
the Warp Team and community
</Link>
</p>
</footer>
Expand Down
9 changes: 4 additions & 5 deletions components/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import Head from "next/head";
import algoliasearch from "algoliasearch/lite";
import { InstantSearch } from "react-instantsearch-dom";

import { liteClient } from "algoliasearch/lite";
import { InstantSearch } from 'react-instantsearch';
import NavBar from "./navbar";
import Footer from "./footer";
import CustomHits from "./search/CustomHits";

export const siteTitle = "Commands.dev - Find commands at the speed of thought";
export const siteDescription =
"Commands.dev is a searchable, templated catalog of popular terminal commands curated from across the internet.";
const searchClient = algoliasearch(
const searchClient = liteClient(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY!
);
Expand Down Expand Up @@ -50,7 +49,7 @@ export default function Layout({
<meta name="og:title" content={siteTitle} />
<meta name="twitter:card" content="summary_large_image" />
</Head>
<InstantSearch searchClient={searchClient} indexName="workflow_specs">
<InstantSearch searchClient={searchClient} future={{ preserveSharedStateOnUnmount: true }} indexName="workflow_specs">
<NavBar />
{/* Show children if query is empty */}
<main className="grow md:mx-[7rem] mx-[1rem]">
Expand Down
25 changes: 12 additions & 13 deletions components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import * as gtag from "../lib/gtag";
export default function NavBar() {
let [mobileSearchBoxOpen, setMobileSearchBoxOpen] = useState(false);
const mobileSearchButton = useRef<HTMLButtonElement>(null);
useEffect( () => {
if ( !! mobileSearchBoxOpen ) {
useEffect(() => {
if (!!mobileSearchBoxOpen) {
return;
}
mobileSearchButton?.current?.focus();
}, [ mobileSearchBoxOpen ] )
}, [mobileSearchBoxOpen])
return (
<div className="sticky top-0 dark:bg-navbar-dark bg-navbar-light shadow-xs pb-4" role="banner">
<div className="flex-col">
Expand Down Expand Up @@ -55,10 +55,11 @@ export default function NavBar() {
>
<LogoIcon />
</a>
<Link href="/">
<a className="font-semibold text-xl text-black dark:text-white tracking-tighter" aria-label="Commands Home">
Commands
</a>
<Link
href="/"
className="font-semibold text-xl text-black dark:text-white tracking-tighter"
aria-label="Commands Home">
Commands
</Link>
</div>
<div className="hidden md:flex w-screen">
Expand All @@ -75,12 +76,10 @@ export default function NavBar() {
<SearchIcon />
</button>
<nav>
<Link href="/about">
<a className="hover:opacity-60 md:px-7 px-2">
<span className="text-l font-normal mt-4 text-back dark:text-white">
About
</span>
</a>
<Link href="/about" className="hover:opacity-60 md:px-7 px-2">
<span className="text-l font-normal mt-4 text-back dark:text-white">
About
</span>
</Link>
<a
href="https://github.com/warpdotdev/workflows#contributing"
Expand Down
35 changes: 14 additions & 21 deletions components/search/CustomHits.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import { connectStateResults } from "react-instantsearch-dom";
import { SearchState, SearchResults } from "react-instantsearch-core";
import { useInstantSearch } from 'react-instantsearch';
import { WorkflowCards } from "../WorkflowCard";
import { Workflow } from "warp-workflows";

function Hits({
searchState,
searchResults,
children,
}: {
searchState: SearchState;
searchResults: SearchResults;
children: React.ReactNode;
}) {
if (!searchState.query || searchState.query.length == 0) {
function Hits({ children }: { children: React.ReactNode }) {
const { results } = useInstantSearch();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

connectStateResults was removed in react-instantsearch v7. They recommend getting the same information about state/results from this useInstantSearch() hook instead.

if (!results.query || results.query.length == 0) {
return <>{children}</>;
} else if (searchResults?.hits.length > 0) {
const workflows: Workflow[] = searchResults!.hits.map(
} else if (results?.hits.length > 0) {
const workflows: Workflow[] = results!.hits.map(
({ slug, name, description, tags }) =>
({
slug,
name,
description,
tags: Array.isArray(tags) ? tags : [tags],
} as Workflow)
({
slug,
name,
description,
tags: Array.isArray(tags) ? tags : [tags],
} as Workflow)
);
return <WorkflowCards workflows={workflows} isSearchResults={true} />;
} else {
Expand All @@ -39,4 +32,4 @@ function Hits({
}
}

export default connectStateResults(Hits);
export default Hits;
18 changes: 16 additions & 2 deletions components/search/CustomSearchBox.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { connectSearchBox } from "react-instantsearch-dom";
import { useSearchBox } from 'react-instantsearch';
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { SearchIcon } from "../icons/search";
import { useHotkeys } from "react-hotkeys-hook";
import { useRouter } from "next/router";

function SearchBox({ refine }: { refine: Dispatch<SetStateAction<string>> }) {
interface SearchBoxProps {
refine: Dispatch<SetStateAction<string>>;
}

function SearchBox({ refine }: SearchBoxProps) {
let [searchBarState, setSearchBarState] = useState("");
useHotkeys("ctrl+k", () => {
if (document != null) {
Expand Down Expand Up @@ -44,4 +48,14 @@ function SearchBox({ refine }: { refine: Dispatch<SetStateAction<string>> }) {
);
}

function connectSearchBox(Component: any) {
const SearchBox = (props: any) => {
const data = useSearchBox(props);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar story here - useSearchBox replaced connectSearchBox. This is lightly adapted from their documentation.

return <Component {...props} {...data} />;
};

return SearchBox;
}

export default connectSearchBox(SearchBox);
22 changes: 17 additions & 5 deletions components/search/MobileSearchBox.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { connectSearchBox } from "react-instantsearch-dom";
import { useSearchBox } from 'react-instantsearch';
import React, { Dispatch, SetStateAction, useEffect, useState } from "react";
import { CancelIcon } from "../icons/cancel";
import { useRouter } from "next/router";

interface MobileSearchBoxProps {
refine: Dispatch<SetStateAction<string>>;
onCloseCallback: () => void;
}

function SearchBox({
refine,
onCloseCallback,
}: {
refine: Dispatch<SetStateAction<string>>;
onCloseCallback: () => void;
}) {
}: MobileSearchBoxProps) {
let [searchBarState, setSearchBarState] = useState("");
useEffect(() => {
let searchBar = document.querySelector(
Expand Down Expand Up @@ -51,4 +53,14 @@ function SearchBox({
);
}

function connectSearchBox(Component: any) {
const SearchBox = (props: any) => {
const data = useSearchBox(props);

return <Component {...props} {...data} />;
};

return SearchBox;
}

export default connectSearchBox(SearchBox);
25 changes: 11 additions & 14 deletions lib/build-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// It is run whenever the next js project is built. (It is called with the `postbuild` command in package.json.)
// Reference: https://www.contentful.com/blog/2021/07/02/add-algolia-instantsearch-to-nextjs-app/
import * as dotenv from "dotenv";
import algoliasearch from "algoliasearch";
import { algoliasearch } from "algoliasearch";
import { getSortedWorkflowsData } from "./workflows";

(async function () {
Expand Down Expand Up @@ -32,23 +32,20 @@ import { getSortedWorkflowsData } from "./workflows";
process.env.ALGOLIA_SEARCH_ADMIN_KEY!
);

// Initialize the index with the algolia index name we set up
const index = client.initIndex("workflow_specs");

const indexName = "workflow_specs";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In version 4 of algoliasearch, you called initIndex on a client, which would then use that index for all future calls. Now, you provide the index to those individual calls. See here for more info.


// Clear all objects before rewriting to remove specs that were deleted
// from the Algolia index.
index.clearObjects();
client.clearObjects({ indexName });

// Save the objects
const algoliaResponse = await index.saveObjects(transformed);

console.log(
`🎉 Sucessfully added ${
algoliaResponse.objectIDs.length
} records to Algolia search. Object IDs:\n${algoliaResponse.objectIDs.join(
"\n"
)}`
);
const algoliaResponse = await client.saveObjects({ indexName, objects: transformed });

const objectIdsAdded = algoliaResponse.reduce<string[]>((acc, response) => {
return acc.concat(response.objectIDs);
}, []);

console.log(`🎉 Sucessfully added ${objectIdsAdded.length} records to Algolia search. Object IDs:\n${objectIdsAdded.join("\n")}`);
} catch (error) {
console.log(error);
}
Expand Down
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
Loading
Loading