├── packages ├── react-cli │ ├── src │ │ ├── index.ts │ │ ├── playground.tsx │ │ └── cli.css │ ├── img │ │ └── cli.png │ ├── tsup.config.js │ ├── vite.config.ts │ ├── index.html │ ├── package.json │ ├── README.md │ └── CHANGELOG.md └── react-databrowser │ ├── src │ ├── index.ts │ ├── types │ │ └── index.ts │ ├── components │ │ ├── ui │ │ │ ├── skeleton.tsx │ │ │ ├── label.tsx │ │ │ ├── toaster.tsx │ │ │ ├── input.tsx │ │ │ ├── separator.tsx │ │ │ ├── textarea.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── spinner.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── popover.tsx │ │ │ ├── badge.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── button.tsx │ │ │ ├── table.tsx │ │ │ ├── use-toast.ts │ │ │ ├── alert-dialog.tsx │ │ │ ├── dialog.tsx │ │ │ ├── toast.tsx │ │ │ └── select.tsx │ │ └── databrowser │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useDebounce.ts │ │ │ ├── useFetchTTLBy.ts │ │ │ ├── useDeleteKey.ts │ │ │ ├── useAddData.ts │ │ │ ├── useUpdateTTL.ts │ │ │ ├── useUpdateStringAndJSON.ts │ │ │ ├── useFetchSingleDataByKey │ │ │ │ ├── utils.ts │ │ │ │ ├── index.ts │ │ │ │ └── fetch-data-types.ts │ │ │ └── useFetchPaginatedKeys.ts │ │ │ ├── components │ │ │ ├── sidebar │ │ │ │ ├── skeleton-buttons.tsx │ │ │ │ ├── sidebar-missing-data.tsx │ │ │ │ ├── display-db-size.tsx │ │ │ │ ├── reload-button.tsx │ │ │ │ ├── data-type-selector.tsx │ │ │ │ ├── data-key-buttons.tsx │ │ │ │ └── index.tsx │ │ │ ├── icons │ │ │ │ └── icon-braces.tsx │ │ │ ├── data-display-container │ │ │ │ ├── data-loading.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── data-ttl-actions.tsx │ │ │ │ ├── delete-alert-dialog.tsx │ │ │ │ ├── missing-data-display.tsx │ │ │ │ ├── data-delete.tsx │ │ │ │ ├── display-scrollarea.tsx │ │ │ │ ├── data-value-edit.tsx │ │ │ │ ├── ttl-popover.tsx │ │ │ │ ├── data-table.tsx │ │ │ │ └── data-display.tsx │ │ │ └── add-data │ │ │ │ └── add-data-dialog.tsx │ │ │ ├── type-tag.tsx │ │ │ ├── index.tsx │ │ │ └── copy-to-clipboard-button.tsx │ ├── globals.css │ ├── playground.tsx │ ├── store.tsx │ └── lib │ │ ├── utils.ts │ │ └── clients.ts │ ├── postcss.config.js │ ├── tsup.config.js │ ├── index.html │ ├── components.json │ ├── vite.config.ts │ ├── tailwind.config.js │ ├── package.json │ ├── README.md │ └── CHANGELOG.md ├── pnpm-workspace.yaml ├── .prettierrc ├── examples └── nextjs13 │ ├── public │ ├── favicon.ico │ ├── vercel.svg │ ├── thirteen.svg │ └── next.svg │ ├── e2e │ ├── utils │ │ └── index.ts │ ├── databrowser.test.ts │ ├── databrowser-add-delete.test.ts │ ├── databrowser-string.test.ts │ ├── databrowser-edit-string.test.ts │ ├── databrower-pagination.test.ts │ ├── databrowser-ttl.test.ts │ ├── databrowser-list.test.ts │ ├── databrowser-freesearch.test.ts │ ├── databrowser-set.test.ts │ ├── databrowser-hash.test.ts │ ├── databrowser-zset.test.ts │ ├── databrowser-json.test.ts │ ├── databrowser-edit-json.test.ts │ └── databrowser-test-reset-e2e.test.ts │ ├── next.config.js │ ├── app │ ├── head.tsx │ ├── global.css │ ├── page.tsx │ ├── welcome │ │ └── page.tsx │ ├── databrowser │ │ └── page.tsx │ ├── init │ │ └── page.tsx │ ├── layout.tsx │ └── custom-commands │ │ └── page.tsx │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ ├── playwright.config.ts │ └── README.md ├── .husky ├── pre-commit └── pre-push ├── .changeset ├── config.json └── README.md ├── turbo.json ├── .gitignore ├── .github └── workflows │ ├── main.yaml │ └── changesets.yaml ├── package.json ├── biome.json └── README.md /packages/react-cli/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./redis-cli.js"; 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - examples/* -------------------------------------------------------------------------------- /packages/react-databrowser/src/index.ts: -------------------------------------------------------------------------------- 1 | export { Databrowser } from "@/components/databrowser"; 2 | -------------------------------------------------------------------------------- /packages/react-cli/img/cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/react-ui/main/packages/react-cli/img/cli.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-tailwindcss"], 3 | "printWidth": 120, 4 | "useTabs": false 5 | } -------------------------------------------------------------------------------- /examples/nextjs13/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/react-ui/main/examples/nextjs13/public/favicon.ico -------------------------------------------------------------------------------- /examples/nextjs13/e2e/utils/index.ts: -------------------------------------------------------------------------------- 1 | export const generateRandomString = () => (Math.random() + 1).toString(36).substring(7); 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | if [ -z "$DISABLE_HUSKY" ]; then 5 | npx lint-staged 6 | fi -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | 5 | 6 | if [ -z "$DISABLE_HUSKY" ]; then 7 | pnpm test 8 | fi -------------------------------------------------------------------------------- /packages/react-databrowser/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /examples/nextjs13/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | experimental: { 4 | appDir: true, 5 | }, 6 | }; 7 | 8 | module.exports = nextConfig; 9 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export const RedisDataTypes = ["All Types", "string", "list", "hash", "set", "zset", "json", "stream"] as const; 2 | 3 | export type RedisDataTypeUnion = (typeof RedisDataTypes)[number]; 4 | export type ActionVariants = "reset" | "filter" | "search" | "next" | "prev"; 5 | -------------------------------------------------------------------------------- /packages/react-databrowser/tsup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts"], 5 | format: ["cjs", "esm"], 6 | splitting: true, 7 | sourcemap: false, 8 | clean: true, 9 | dts: true, 10 | minify: true, 11 | minifyWhitespace: true, 12 | }); 13 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /packages/react-cli/tsup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts"], 5 | format: ["cjs", "esm"], 6 | splitting: false, 7 | sourcemap: false, 8 | clean: true, 9 | bundle: true, 10 | dts: true, 11 | minify: true, 12 | minifyWhitespace: true, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | 3 | function Skeleton({ className, ...props }: React.HTMLAttributes) { 4 | return ( 5 |
6 | ); 7 | } 8 | 9 | export { Skeleton }; 10 | -------------------------------------------------------------------------------- /examples/nextjs13/app/head.tsx: -------------------------------------------------------------------------------- 1 | export default function Head() { 2 | return ( 3 | <> 4 | Create Next App 5 | 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/react-cli/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | export default ({ mode }: { mode: string }) => { 5 | const env = loadEnv(mode, process.cwd(), ""); 6 | return defineConfig({ 7 | define: { 8 | "process.env": env, 9 | }, 10 | plugins: [react()], 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./useAddData"; 2 | export * from "./useDebounce"; 3 | export * from "./useDeleteKey"; 4 | export * from "./useFetchPaginatedKeys"; 5 | export * from "./useFetchSingleDataByKey"; 6 | export * from "./useFetchTTLBy"; 7 | export * from "./useUpdateStringAndJSON"; 8 | export * from "./useUpdateTTL"; 9 | -------------------------------------------------------------------------------- /packages/react-cli/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CLI Playground 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["dist/**", ".next/**"] 7 | }, 8 | "dev": { 9 | "dependsOn": ["^build"], 10 | "cache": false 11 | }, 12 | "test": { 13 | "dependsOn": ["^build"], 14 | "cache": false 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/react-databrowser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Databrowser Playground 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/react-databrowser/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": false 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/react-databrowser/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | export default ({ mode }: { mode: string }) => { 6 | const env = loadEnv(mode, process.cwd(), ""); 7 | return defineConfig({ 8 | define: { 9 | "process.env": env, 10 | }, 11 | plugins: [react(), tsconfigPaths()], 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/components/sidebar/skeleton-buttons.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@/components/ui/skeleton"; 2 | 3 | const DEFAULT_SKELETON_COUNT = 10; 4 | export const LoadingSkeleton = () => ( 5 |
6 | {Array(DEFAULT_SKELETON_COUNT) 7 | .fill(0) 8 | .map((_, idx) => ( 9 | 10 | ))} 11 |
12 | ); 13 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/hooks/useDebounce.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | export function useDebounce(value: T, delay: number): T { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const handler = setTimeout(() => { 8 | setDebouncedValue(value); 9 | }, delay); 10 | 11 | return () => { 12 | clearTimeout(handler); 13 | }; 14 | }, [value, delay]); 15 | 16 | return debouncedValue; 17 | } 18 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /examples/nextjs13/app/global.css: -------------------------------------------------------------------------------- 1 | .nav-container { 2 | display: flex; 3 | gap: 20px; 4 | padding: 10px 20px; 5 | background-color: #F5F5F5; 6 | margin-bottom: 20px; 7 | border-radius: 0 !important;; 8 | } 9 | 10 | .nav-link { 11 | padding: 8px 16px; 12 | color: black; 13 | text-decoration: none; 14 | border-radius: 4px; 15 | background-color:#cfceced0; 16 | transition: 17 | background-color 0.3s ease, 18 | color 0.3s ease; 19 | } 20 | 21 | .nav-link:hover { 22 | background-color: #555; 23 | color: #eee; 24 | } 25 | -------------------------------------------------------------------------------- /examples/nextjs13/e2e/databrowser.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test("Check the missing data text", async ({ page }) => { 4 | await page.goto("http://localhost:3000/databrowser"); 5 | // Wait for the element to be in the DOM. 6 | const missingDataElement = page.locator('[data-testid="missing-data"]'); 7 | 8 | // Get the text content of the element and compare it to the expected value. 9 | const missingDataText = await missingDataElement.textContent(); 10 | expect(missingDataText).toBe("Select a record from the list"); 11 | }); 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .env 3 | 4 | # dependencies 5 | **node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | .pnpm-debug.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | .turbo 40 | dist 41 | -------------------------------------------------------------------------------- /examples/nextjs13/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { RedisCli } from "@upstash/react-cli"; 3 | 4 | export default function Home() { 5 | const upstashRedisRestUrl = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL; 6 | if (!upstashRedisRestUrl) { 7 | return
UPSTASH_REDIS_REST_URL not set
; 8 | } 9 | const upstashRedisRestToken = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN; 10 | if (!upstashRedisRestToken) { 11 | return
UPSTASH_REDIS_REST_TOKEN not set
; 12 | } 13 | 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /examples/nextjs13/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | .env* 39 | 40 | # vscode 41 | 42 | .vscode -------------------------------------------------------------------------------- /examples/nextjs13/app/welcome/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { RedisCli } from "@upstash/react-cli"; 3 | 4 | export default function Home() { 5 | const upstashRedisRestUrl = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL; 6 | if (!upstashRedisRestUrl) { 7 | return
UPSTASH_REDIS_REST_URL not set
; 8 | } 9 | const upstashRedisRestToken = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN; 10 | if (!upstashRedisRestToken) { 11 | return
UPSTASH_REDIS_REST_TOKEN not set
; 12 | } 13 | 14 | return Custom
} />; 15 | } 16 | -------------------------------------------------------------------------------- /examples/nextjs13/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - "**" 7 | 8 | jobs: 9 | Build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout Repo 13 | uses: actions/checkout@v3 14 | 15 | - name: Use PNPM 16 | uses: pnpm/action-setup@v3.0.0 17 | with: 18 | version: 9.0.0 19 | 20 | - name: Use Node.js 18 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: 18 24 | cache: "pnpm" 25 | 26 | - name: Install 27 | run: pnpm install 28 | 29 | - name: Build for production 30 | run: pnpm build 31 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/hooks/useFetchTTLBy.ts: -------------------------------------------------------------------------------- 1 | import { useDatabrowser } from "@/store"; 2 | import { useQuery } from "@tanstack/react-query"; 3 | 4 | export const useFetchTTLByKey = (dataKey?: string) => { 5 | const { redis } = useDatabrowser(); 6 | 7 | const { isLoading, error, data } = useQuery({ 8 | queryKey: ["useFetchTTLByKey", dataKey], 9 | queryFn: async () => { 10 | if (dataKey === undefined) { 11 | throw new Error("Key is missing!"); 12 | } 13 | const stringValue = await redis.ttl(dataKey); 14 | return stringValue; 15 | }, 16 | }); 17 | return { isLoading, error, data }; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/components/icons/icon-braces.tsx: -------------------------------------------------------------------------------- 1 | export function IconBraces() { 2 | return ( 3 | 13 | 14 | 15 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /examples/nextjs13/app/databrowser/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Databrowser } from "@upstash/react-databrowser"; 3 | import "@upstash/react-databrowser/dist/index.css"; 4 | 5 | export default function DatabrowserDemo() { 6 | const upstashRedisRestUrl = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL; 7 | if (!upstashRedisRestUrl) { 8 | return
UPSTASH_REDIS_REST_URL not set
; 9 | } 10 | const upstashRedisRestToken = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN; 11 | if (!upstashRedisRestToken) { 12 | return
UPSTASH_REDIS_REST_TOKEN not set
; 13 | } 14 | 15 | return ; 16 | } 17 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer components { 6 | .ttl-with-gray-bg { 7 | @apply flex h-[25px] w-[120px] items-center justify-center gap-[2px] rounded-md bg-[#00000008] px-2 py-1 text-sm text-[#00000099]; 8 | } 9 | 10 | .save-changes-btn { 11 | @apply inline-flex h-10 items-center justify-center rounded-md border border-neutral-200 bg-green-600 px-4 py-2 text-sm font-medium text-white ring-offset-white transition-colors hover:bg-green-600/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/hooks/useDeleteKey.ts: -------------------------------------------------------------------------------- 1 | import { queryClient } from "@/lib/clients"; 2 | import { useDatabrowser } from "@/store"; 3 | import { useMutation } from "@tanstack/react-query"; 4 | 5 | export const useDeleteKey = () => { 6 | const { redis } = useDatabrowser(); 7 | 8 | const deleteKey = useMutation({ 9 | mutationFn: async (dataKey?: string) => { 10 | if (dataKey === undefined) { 11 | throw new Error("Key is missing!"); 12 | } 13 | 14 | return Boolean(await redis.del(dataKey)); 15 | }, 16 | onSuccess: () => 17 | queryClient.invalidateQueries({ 18 | queryKey: ["useFetchPaginatedKeys"], 19 | }), 20 | }); 21 | 22 | return deleteKey; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/components/sidebar/sidebar-missing-data.tsx: -------------------------------------------------------------------------------- 1 | export const SidebarMissingData = () => { 2 | return ( 3 |
4 |
5 |
6 |
7 |

Data on a break

8 |

9 | "Quick, lure it back with some CLI magic!" 10 |

11 |
12 |
13 |
14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /examples/nextjs13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "baseUrl": ".", 23 | "paths": { 24 | "@/*": ["./*"] 25 | } 26 | }, 27 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 28 | "exclude": ["node_modules"] 29 | } 30 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as LabelPrimitive from "@radix-ui/react-label"; 3 | import { cva, type VariantProps } from "class-variance-authority"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"); 8 | 9 | const Label = React.forwardRef< 10 | React.ElementRef, 11 | React.ComponentPropsWithoutRef & VariantProps 12 | >(({ className, ...props }, ref) => ( 13 | 14 | )); 15 | Label.displayName = LabelPrimitive.Root.displayName; 16 | 17 | export { Label }; 18 | -------------------------------------------------------------------------------- /examples/nextjs13/app/init/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { RedisCli } from "@upstash/react-cli"; 3 | 4 | export default function Home() { 5 | const upstashRedisRestUrl = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL; 6 | if (!upstashRedisRestUrl) { 7 | return
UPSTASH_REDIS_REST_URL not set
; 8 | } 9 | const upstashRedisRestToken = process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN; 10 | if (!upstashRedisRestToken) { 11 | return
UPSTASH_REDIS_REST_TOKEN not set
; 12 | } 13 | 14 | return ( 15 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from "@/components/ui/toast"; 2 | import { useToast } from "@/components/ui/use-toast"; 3 | 4 | export function Toaster() { 5 | const { toasts } = useToast(); 6 | 7 | return ( 8 | 9 | {toasts.map(({ id, title, description, action, ...props }) => ( 10 | 11 |
12 | {title && {title}} 13 | {description && {description}} 14 |
15 | {action} 16 | 17 |
18 | ))} 19 | 20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/databrowser/components/sidebar/display-db-size.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@/components/ui/skeleton"; 2 | import { useDatabrowser } from "@/store"; 3 | import { useQuery } from "@tanstack/react-query"; 4 | 5 | export const DisplayDbSize = () => { 6 | const { redis } = useDatabrowser(); 7 | const { isLoading, error, data } = useQuery({ 8 | queryKey: ["useFetchDbSize"], 9 | queryFn: async () => { 10 | return await redis.dbsize(); 11 | }, 12 | }); 13 | 14 | if (isLoading || error) { 15 | return ( 16 |
17 | Total: 18 |
19 | ); 20 | } 21 | return
Total: {data}
; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export type InputProps = React.InputHTMLAttributes; 6 | 7 | const Input = React.forwardRef(({ className, type, ...props }, ref) => { 8 | return ( 9 | 18 | ); 19 | }); 20 | Input.displayName = "Input"; 21 | 22 | export { Input }; 23 | -------------------------------------------------------------------------------- /examples/nextjs13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs13", 3 | "version": "0.3.22", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "test": "playwright test" 11 | }, 12 | "dependencies": { 13 | "@next/font": "13.3.0", 14 | "@types/node": "18.15.11", 15 | "@types/react": "18.0.37", 16 | "@types/react-dom": "18.0.11", 17 | "@upstash/react-cli": "workspace:*", 18 | "@upstash/react-databrowser": "workspace:*", 19 | "next": "13.3.0", 20 | "react": "18.2.0", 21 | "react-dom": "18.2.0", 22 | "typescript": "5.0.4" 23 | }, 24 | "devDependencies": { 25 | "playwright": "^1.38.1", 26 | "@playwright/test": "^1.38.1", 27 | "autoprefixer": "^10.4.14", 28 | "postcss": "^8.4.31", 29 | "tailwindcss": "^3.3.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as SeparatorPrimitive from "@radix-ui/react-separator"; 3 | 4 | import { cn } from "@/lib/utils"; 5 | 6 | const Separator = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => ( 10 | 21 | )); 22 | Separator.displayName = SeparatorPrimitive.Root.displayName; 23 | 24 | export { Separator }; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@upstash/react-ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "turbo run build", 7 | "dev": "turbo run dev --parallel", 8 | "test": "turbo run test", 9 | "fmt": "pnpm biome check . --apply-unsafe ", 10 | "prepare": "husky install", 11 | "bump-versions": "pnpm changeset version && pnpm install" 12 | }, 13 | "devDependencies": { 14 | "@changesets/cli": "^2.26.1", 15 | "husky": "^8.0.1", 16 | "lint-staged": "^13.0.3", 17 | "prettier": "^3.0.3", 18 | "prettier-plugin-tailwindcss": "^0.5.5", 19 | "turbo": "^1.9.3", 20 | "@biomejs/biome": "^1.2.2" 21 | }, 22 | "lint-staged": { 23 | "**/*.{js,ts,tsx}": [ 24 | "pnpm fmt", 25 | "prettier --write --ignore-unknown" 26 | ] 27 | }, 28 | "engines": { 29 | "node": ">=18.0.0" 30 | }, 31 | "packageManager": "pnpm@9.0.0" 32 | } 33 | -------------------------------------------------------------------------------- /packages/react-databrowser/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export type TextareaProps = React.TextareaHTMLAttributes; 6 | 7 | const Textarea = React.forwardRef(({ className, ...props }, ref) => { 8 | return ( 9 |