Compare commits
52 Commits
feat/trace
...
jazz-bette
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66b5f8d4c8 | ||
|
|
9c6ca9e864 | ||
|
|
858386b5b1 | ||
|
|
f45af0a5cf | ||
|
|
22af329930 | ||
|
|
fc342306e2 | ||
|
|
8e4a9c7211 | ||
|
|
362284f6b7 | ||
|
|
975c7bc785 | ||
|
|
9a1295d4f6 | ||
|
|
256fdfd0db | ||
|
|
4cf2bf5fef | ||
|
|
cae74bd051 | ||
|
|
05a3786e23 | ||
|
|
0fa051a59d | ||
|
|
1378a1ff68 | ||
|
|
5ad093cb6a | ||
|
|
98407c2314 | ||
|
|
65e14c6176 | ||
|
|
9fa79b3a5f | ||
|
|
c90222d32e | ||
|
|
d084b41929 | ||
|
|
65e78014fa | ||
|
|
d693800eb3 | ||
|
|
4ab0b1f4b2 | ||
|
|
9157effdb3 | ||
|
|
30b2820a8c | ||
|
|
bb561e2650 | ||
|
|
7cdf397a01 | ||
|
|
44116b805b | ||
|
|
e93c27910d | ||
|
|
16428cace4 | ||
|
|
f48dabaa1a | ||
|
|
7ff90cb81e | ||
|
|
3a53cc4c00 | ||
|
|
ea6c50b2b8 | ||
|
|
01c07e34e4 | ||
|
|
c89b94aa3b | ||
|
|
01e2977a13 | ||
|
|
41354cb2c1 | ||
|
|
530f9d3e11 | ||
|
|
c965c904bc | ||
|
|
d527ae2db0 | ||
|
|
b897e950bb | ||
|
|
69c92ab908 | ||
|
|
10e1612fd4 | ||
|
|
282a2798c7 | ||
|
|
31b89adb03 | ||
|
|
793787bc66 | ||
|
|
17710122af | ||
|
|
1173884769 | ||
|
|
1c40b3fd6d |
@@ -10,29 +10,12 @@
|
||||
"cojson-storage-indexeddb",
|
||||
"cojson-storage-sqlite",
|
||||
"cojson-transport-ws",
|
||||
"jazz-browser",
|
||||
"jazz-auth-clerk",
|
||||
"jazz-auth-betterauth",
|
||||
"jazz-betterauth-client-plugin",
|
||||
"jazz-betterauth-server-plugin",
|
||||
"jazz-react-auth-betterauth",
|
||||
"jazz-browser-media-images",
|
||||
"jazz-expo",
|
||||
"jazz-inspector",
|
||||
"jazz-inspector-element",
|
||||
"jazz-nodejs",
|
||||
"jazz-react",
|
||||
"jazz-react-core",
|
||||
"jazz-react-auth-clerk",
|
||||
"jazz-react-native-core",
|
||||
"jazz-react-native",
|
||||
"jazz-react-native-media-images",
|
||||
"jazz-richtext-prosemirror",
|
||||
"jazz-richtext-tiptap",
|
||||
"jazz-run",
|
||||
"jazz-svelte",
|
||||
"jazz-tools",
|
||||
"jazz-vue"
|
||||
"jazz-tools"
|
||||
]
|
||||
],
|
||||
"access": "public",
|
||||
|
||||
31
.github/workflows/build-examples.yaml
vendored
31
.github/workflows/build-examples.yaml
vendored
@@ -1,31 +0,0 @@
|
||||
name: Build Examples
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build-examples:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
strategy:
|
||||
matrix:
|
||||
example: [
|
||||
"passkey-svelte",
|
||||
"chat-svelte",
|
||||
"file-share-svelte",
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup Source Code
|
||||
uses: ./.github/actions/source-code/
|
||||
|
||||
- name: Pnpm Build
|
||||
run: |
|
||||
pnpm install
|
||||
pnpm turbo build;
|
||||
working-directory: ./examples/${{ matrix.example }}
|
||||
3
.github/workflows/e2e-rn-test.yml
vendored
3
.github/workflows/e2e-rn-test.yml
vendored
@@ -60,7 +60,8 @@ jobs:
|
||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
|
||||
disable-animations: true
|
||||
working-directory: ./examples/chat-rn-expo/
|
||||
script: ./test/e2e/run.sh
|
||||
# killall due to this issue: https://github.com/ReactiveCircus/android-emulator-runner/issues/385
|
||||
script: ./test/e2e/run.sh && killall -INT crashpad_handler || true
|
||||
|
||||
- name: Copy Maestro Output
|
||||
if: steps.e2e_test.outcome != 'success'
|
||||
|
||||
19
.github/workflows/playwright-homepage.yml
vendored
19
.github/workflows/playwright-homepage.yml
vendored
@@ -10,9 +10,6 @@ jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
strategy:
|
||||
matrix:
|
||||
project: ["homepage/homepage"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -23,27 +20,27 @@ jobs:
|
||||
uses: ./.github/actions/source-code/
|
||||
|
||||
- name: Install root dependencies
|
||||
run: pnpm install && pnpm turbo build
|
||||
run: pnpm install && pnpm exec turbo build --filter="./packages/*"
|
||||
|
||||
- name: Install project dependencies
|
||||
run: pnpm install
|
||||
working-directory: ./${{ matrix.project }}
|
||||
working-directory: ./homepage/homepage
|
||||
|
||||
- name: Pnpm Build
|
||||
run: pnpm turbo build
|
||||
working-directory: ./${{ matrix.project }}
|
||||
run: pnpm exec turbo build
|
||||
working-directory: ./homepage/homepage
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install
|
||||
working-directory: ./${{ matrix.project }}
|
||||
working-directory: ./homepage/homepage
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: pnpm exec playwright test
|
||||
working-directory: ./${{ matrix.project }}
|
||||
working-directory: ./homepage/homepage
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{ hashFiles(format('{0}/package.json', matrix.project)) }}-playwright-report
|
||||
path: ./${{ matrix.project }}/playwright-report/
|
||||
name: homepage-playwright-report
|
||||
path: ./homepage/homepage/playwright-report/
|
||||
retention-days: 30
|
||||
|
||||
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
"examples/organization",
|
||||
"starters/react-passkey-auth",
|
||||
"starters/svelte-passkey-auth",
|
||||
"packages/jazz-svelte"
|
||||
"tests/jazz-svelte"
|
||||
]
|
||||
|
||||
steps:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"jazz-tools.json",
|
||||
"**/ios/**",
|
||||
"**/android/**",
|
||||
"packages/jazz-svelte/**",
|
||||
"tests/jazz-svelte/src/**",
|
||||
"examples/*svelte*/**",
|
||||
"starters/*svelte*/**",
|
||||
"examples/jazz-paper-scissors/src/routeTree.gen.ts",
|
||||
|
||||
@@ -21,11 +21,9 @@
|
||||
"better-sqlite3": "^11.9.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"jazz-react-auth-betterauth": "workspace:*",
|
||||
"jazz-betterauth-client-plugin": "workspace:*",
|
||||
"jazz-betterauth-server-plugin": "workspace:*",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-react-auth-betterauth": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"lucide-react": "^0.510.0",
|
||||
"next": "15.3.2",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAccount } from "jazz-react";
|
||||
import { Account } from "jazz-tools";
|
||||
import { useAccount } from "jazz-tools/react";
|
||||
import {
|
||||
AppWindowMacIcon,
|
||||
FileTextIcon,
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { JazzProvider } from "jazz-react";
|
||||
import { AuthProvider } from "jazz-react-auth-betterauth";
|
||||
import { JazzReactProvider } from "jazz-tools/react";
|
||||
import { type ReactNode, lazy } from "react";
|
||||
|
||||
const JazzDevTools =
|
||||
process.env.NODE_ENV === "production"
|
||||
? () => null
|
||||
: lazy(() =>
|
||||
import("jazz-inspector").then((res) => ({
|
||||
import("jazz-tools/inspector").then((res) => ({
|
||||
default: res.JazzInspector,
|
||||
})),
|
||||
);
|
||||
|
||||
export function JazzAndAuth({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<JazzProvider
|
||||
<JazzReactProvider
|
||||
sync={{
|
||||
peer: "wss://cloud.jazz.tools/?key=betterauth-example@garden.co",
|
||||
}}
|
||||
@@ -28,6 +28,6 @@ export function JazzAndAuth({ children }: { children: ReactNode }) {
|
||||
{children}
|
||||
</AuthProvider>
|
||||
<JazzDevTools />
|
||||
</JazzProvider>
|
||||
</JazzReactProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-react";
|
||||
import { useAuth } from "jazz-react-auth-betterauth";
|
||||
import { Account } from "jazz-tools";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-tools/react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useCallback } from "react";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-react";
|
||||
import { useAuth } from "jazz-react-auth-betterauth";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-tools/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Redirect, Stack } from "expo-router";
|
||||
import { useIsAuthenticated } from "jazz-expo";
|
||||
import { useIsAuthenticated } from "jazz-tools/expo";
|
||||
import React from "react";
|
||||
|
||||
export default function HomeLayout() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Redirect, Stack } from "expo-router";
|
||||
import { useIsAuthenticated } from "jazz-expo";
|
||||
import { useIsAuthenticated } from "jazz-tools/expo";
|
||||
|
||||
export default function UnAuthenticatedLayout() {
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
|
||||
@@ -4,7 +4,7 @@ import { secureStore } from "@clerk/clerk-expo/secure-store";
|
||||
import { useFonts } from "expo-font";
|
||||
import { Slot, useRouter, useSegments } from "expo-router";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import { useIsAuthenticated, useJazzContext } from "jazz-expo";
|
||||
import { useIsAuthenticated, useJazzContext } from "jazz-tools/expo";
|
||||
import React, { useEffect } from "react";
|
||||
import { tokenCache } from "../cache";
|
||||
import { JazzAndAuth } from "../src/auth-context";
|
||||
|
||||
@@ -4,10 +4,10 @@ import clsx from "clsx";
|
||||
import * as Clipboard from "expo-clipboard";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import { useLocalSearchParams } from "expo-router";
|
||||
import { useAccount, useCoState } from "jazz-expo";
|
||||
import { ProgressiveImg } from "jazz-expo";
|
||||
import { createImage } from "jazz-react-native-media-images";
|
||||
import { CoPlainText, Group, Loaded } from "jazz-tools";
|
||||
import { useAccount, useCoState } from "jazz-tools/expo";
|
||||
import { ProgressiveImgNative } from "jazz-tools/expo";
|
||||
import { createImageNative } from "jazz-tools/react-native-media-images";
|
||||
import { useEffect, useLayoutEffect, useState } from "react";
|
||||
import React, {
|
||||
SafeAreaView,
|
||||
@@ -104,7 +104,7 @@ export default function Conversation() {
|
||||
setIsUploading(true);
|
||||
const base64Uri = `data:image/jpeg;base64,${result.assets[0].base64}`;
|
||||
|
||||
const image = await createImage(base64Uri, {
|
||||
const image = await createImageNative(base64Uri, {
|
||||
owner: chat._owner,
|
||||
maxSize: 2048,
|
||||
});
|
||||
@@ -149,15 +149,17 @@ export default function Conversation() {
|
||||
)}
|
||||
>
|
||||
{item.image && (
|
||||
<ProgressiveImg image={item.image} maxWidth={1024}>
|
||||
{({ src, res, originalSize }) => (
|
||||
<ProgressiveImgNative
|
||||
image={item.image}
|
||||
maxWidth={1024}
|
||||
children={({ src }) => (
|
||||
<Image
|
||||
source={{ uri: src }}
|
||||
className="w-48 h-48 rounded-lg mb-2"
|
||||
resizeMode="cover"
|
||||
/>
|
||||
)}
|
||||
</ProgressiveImg>
|
||||
/>
|
||||
)}
|
||||
{item.text && (
|
||||
<Text
|
||||
|
||||
@@ -11,7 +11,7 @@ import React, {
|
||||
} from "react-native";
|
||||
|
||||
import { useUser } from "@clerk/clerk-expo";
|
||||
import { useAccount } from "jazz-expo";
|
||||
import { useAccount } from "jazz-tools/expo";
|
||||
import { Chat } from "../../src/schema";
|
||||
|
||||
export default function ChatScreen() {
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
"expo-sqlite": "15.2.9",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"jazz-expo": "workspace:*",
|
||||
"jazz-react-native-media-images": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"nativewind": "^4.1.21",
|
||||
"react": "19.0.0",
|
||||
@@ -56,7 +54,6 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@types/react": "~19.0.14",
|
||||
"react-test-renderer": "18.3.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "5.8.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useClerk } from "@clerk/clerk-expo";
|
||||
import { JazzProviderWithClerk } from "jazz-expo/auth/clerk";
|
||||
import { JazzExpoProviderWithClerk } from "jazz-tools/expo";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
import { apiKey } from "./apiKey";
|
||||
|
||||
@@ -7,13 +7,13 @@ export function JazzAndAuth({ children }: PropsWithChildren) {
|
||||
const clerk = useClerk();
|
||||
|
||||
return (
|
||||
<JazzProviderWithClerk
|
||||
<JazzExpoProviderWithClerk
|
||||
clerk={clerk}
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</JazzProviderWithClerk>
|
||||
</JazzExpoProviderWithClerk>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"expo-secure-store": "~14.2.3",
|
||||
"expo-sqlite": "~15.2.10",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"jazz-expo": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { JazzProvider } from "jazz-expo";
|
||||
import { JazzExpoProvider } from "jazz-tools/expo";
|
||||
import React, { StrictMode } from "react";
|
||||
import { apiKey } from "./apiKey";
|
||||
import ChatScreen from "./chat";
|
||||
@@ -6,13 +6,13 @@ import ChatScreen from "./chat";
|
||||
export default function App() {
|
||||
return (
|
||||
<StrictMode>
|
||||
<JazzProvider
|
||||
<JazzExpoProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
>
|
||||
<ChatScreen />
|
||||
</JazzProvider>
|
||||
</JazzExpoProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import React, {
|
||||
StyleSheet,
|
||||
} from "react-native";
|
||||
|
||||
import { useAccount, useCoState } from "jazz-expo";
|
||||
import { useAccount, useCoState } from "jazz-tools/expo";
|
||||
import { Chat, Message } from "./schema";
|
||||
|
||||
export default function ChatScreen() {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"clsx": "^2.0.0",
|
||||
"cojson": "workspace:*",
|
||||
"cojson-transport-ws": "workspace:*",
|
||||
"jazz-react-native": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
@@ -49,7 +48,6 @@
|
||||
"eslint": "^8.19.0",
|
||||
"pod-install": "^0.3.5",
|
||||
"prettier": "2.8.8",
|
||||
"react-test-renderer": "18.3.1",
|
||||
"typescript": "5.6.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
useNavigationContainerRef,
|
||||
} from "@react-navigation/native";
|
||||
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||
import { JazzProvider } from "jazz-react-native";
|
||||
import { JazzReactNativeProvider } from "jazz-tools/react-native";
|
||||
import React, { StrictMode, useEffect, useState } from "react";
|
||||
import { Linking } from "react-native";
|
||||
import { apiKey } from "./apiKey";
|
||||
@@ -49,7 +49,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<StrictMode>
|
||||
<JazzProvider
|
||||
<JazzReactNativeProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
@@ -67,7 +67,7 @@ function App() {
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
</JazzProvider>
|
||||
</JazzReactNativeProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Clipboard from "@react-native-clipboard/clipboard";
|
||||
import { useAccount, useCoState } from "jazz-react-native";
|
||||
import { CoPlainText, Group, ID, Loaded, Profile } from "jazz-tools";
|
||||
import { useAccount, useCoState } from "jazz-tools/react-native";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useAcceptInvite } from "jazz-react-native";
|
||||
import { useAcceptInviteNative } from "jazz-tools/react-native";
|
||||
import React from "react";
|
||||
import { Text } from "react-native";
|
||||
import { Chat } from "./schema";
|
||||
@@ -8,7 +8,7 @@ export function HandleInviteScreen({
|
||||
}: {
|
||||
navigation: any;
|
||||
}) {
|
||||
useAcceptInvite({
|
||||
useAcceptInviteNative({
|
||||
invitedObjectSchema: Chat,
|
||||
onAccept: async (chatId) => {
|
||||
navigation.navigate("ChatScreen", { chatId });
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# passkey-svelte
|
||||
|
||||
## 0.0.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1378a1f]
|
||||
- Updated dependencies [0fa051a]
|
||||
- jazz-tools@0.15.0
|
||||
|
||||
## 0.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -65,4 +65,4 @@ If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/routes/+layout.svelte](./src/routes/+layout.svelte) to `{ peer: "ws://localhost:4200" }`.
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzSvelteProvider` in [./src/routes/+layout.svelte](./src/routes/+layout.svelte) to `{ peer: "ws://localhost:4200" }`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-svelte",
|
||||
"version": "0.0.88",
|
||||
"version": "0.0.89",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -25,7 +25,6 @@
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.46.1",
|
||||
"globals": "^15.15.0",
|
||||
"jazz-inspector-element": "workspace:*",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-svelte": "^3.4.0",
|
||||
"svelte": "^5.31.1",
|
||||
@@ -36,8 +35,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"jazz-browser-media-images": "workspace:*",
|
||||
"jazz-svelte": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"tailwindcss": "^4.1.7"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import 'jazz-tools/inspector/register-custom-element';
|
||||
|
||||
import '../app.css';
|
||||
import { JazzProvider } from 'jazz-svelte';
|
||||
import 'jazz-inspector-element';
|
||||
import { page } from '$app/state';
|
||||
import { JazzSvelteProvider } from 'jazz-tools/svelte';
|
||||
import { apiKey } from '../apiKey';
|
||||
import { getRandomUsername } from '$lib/utils';
|
||||
let { children } = $props();
|
||||
@@ -14,14 +14,14 @@
|
||||
</svelte:head>
|
||||
|
||||
<div class="h-full bg-white text-stone-700 dark:text-stone-400 dark:bg-stone-925">
|
||||
<JazzProvider
|
||||
<JazzSvelteProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`
|
||||
}}
|
||||
{defaultProfileName}
|
||||
>
|
||||
{@render children?.()}
|
||||
</JazzProvider>
|
||||
</JazzSvelteProvider>
|
||||
<jazz-inspector></jazz-inspector>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { Chat } from '$lib/schema';
|
||||
import { AccountCoState } from 'jazz-svelte';
|
||||
import { AccountCoState } from 'jazz-tools/svelte';
|
||||
import { Account, Group } from 'jazz-tools';
|
||||
|
||||
const account = new AccountCoState(Account);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { createImage } from 'jazz-browser-media-images';
|
||||
import { AccountCoState, CoState } from 'jazz-svelte';
|
||||
import { createImage } from 'jazz-tools/browser-media-images';
|
||||
import { AccountCoState, CoState } from 'jazz-tools/svelte';
|
||||
import { Account, CoPlainText, type ID } from 'jazz-tools';
|
||||
|
||||
import { page } from '$app/state';
|
||||
|
||||
6
examples/chat-vue/.gitignore
vendored
6
examples/chat-vue/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
dist
|
||||
# env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
||||
# Chat example with Jazz and Vue
|
||||
|
||||
## Getting started
|
||||
|
||||
You can either
|
||||
1. Clone the jazz repository, and run the app within the monorepo.
|
||||
2. Or create a new Jazz project using this example as a template.
|
||||
|
||||
|
||||
### Using the example as a template
|
||||
|
||||
Create a new Jazz project, and use this example as a template.
|
||||
```bash
|
||||
npx create-jazz-app@latest chat-vue-app --example chat-vue
|
||||
```
|
||||
|
||||
Go to the new project directory.
|
||||
```bash
|
||||
cd chat-vue-app
|
||||
```
|
||||
|
||||
Run the dev server.
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Using the monorepo
|
||||
|
||||
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
||||
|
||||
Clone the jazz repository.
|
||||
```bash
|
||||
git clone https://github.com/garden-co/jazz.git
|
||||
```
|
||||
|
||||
Install and build dependencies.
|
||||
```bash
|
||||
pnpm i && npx turbo build
|
||||
```
|
||||
|
||||
Go to the example directory.
|
||||
```bash
|
||||
cd jazz/examples/chat-vue/
|
||||
```
|
||||
|
||||
Start the dev server.
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.
|
||||
|
||||
## Questions / problems / feedback
|
||||
|
||||
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
|
||||
|
||||
## Configuration: sync server
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/main.ts](./src/main.ts) to `{ peer: "ws://localhost:4200" }`.
|
||||
1
examples/chat-vue/env.d.ts
vendored
1
examples/chat-vue/env.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Jazz Chat Vue Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"name": "chat-vue",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build-type-check": "run-p type-check \"build {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-browser": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"jazz-vue": "workspace:*",
|
||||
"vue": "^3.5.11",
|
||||
"vue-router": "^4.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/node": "^22.5.1",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"eslint": "^9.7.0",
|
||||
"eslint-plugin-vue": "^9.28.0",
|
||||
"npm-run-all2": "^6.2.3",
|
||||
"postcss": "^8.4.40",
|
||||
"@tailwindcss/postcss": "^4.1.10",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"typescript": "5.6.2",
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-vue-devtools": "^7.4.6",
|
||||
"vue-tsc": "^2.1.6"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export default {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<AppContainer>
|
||||
<TopBar v-if="me">
|
||||
<p>{{ me.profile?.name }}</p>
|
||||
<button @click="logOut">Log out</button>
|
||||
</TopBar>
|
||||
<router-view />
|
||||
</AppContainer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAccount } from "jazz-vue";
|
||||
import AppContainer from "./components/AppContainer.vue";
|
||||
import TopBar from "./components/TopBar.vue";
|
||||
|
||||
const { me, logOut } = useAccount();
|
||||
</script>
|
||||
@@ -1 +0,0 @@
|
||||
export const apiKey = "chat-example-jazz@garden.co";
|
||||
@@ -1,74 +0,0 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition: color 0.5s, background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||
|
Before Width: | Height: | Size: 276 B |
@@ -1,35 +0,0 @@
|
||||
@import "./base.css";
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col justify-between w-screen h-screen bg-stone-50 dark:bg-black dark:text-white"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "AppContainer",
|
||||
};
|
||||
</script>
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="rounded-2xl text-sm line-clamp-10 text-ellipsis bg-white max-w-full whitespace-pre-wrap dark:bg-stone-700 dark:text-white py-1 px-3 shadow-sm"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "BubbleBody",
|
||||
};
|
||||
</script>
|
||||
@@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<div :class="[alignClass, 'flex flex-col m-2']" role="row">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "BubbleContainer",
|
||||
props: {
|
||||
fromMe: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
alignClass() {
|
||||
return this.fromMe ? "items-end" : "items-start";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<div class="text-xs text-neutral-500 mt-1.5">
|
||||
{{ by }} · {{ formattedTime }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "BubbleInfo",
|
||||
props: {
|
||||
by: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
madeAt: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const formattedTime = computed(() => props.madeAt.toLocaleTimeString());
|
||||
return {
|
||||
formattedTime,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<div class="flex-1 overflow-y-auto flex flex-col-reverse" role="application">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "ChatBody",
|
||||
};
|
||||
</script>
|
||||
@@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<BubbleContainer :fromMe="lastEdit.by?.isMe">
|
||||
<BubbleBody>{{ msg.text }}</BubbleBody>
|
||||
<BubbleInfo :by="lastEdit.by?.profile?.name" :madeAt="lastEdit.madeAt" />
|
||||
</BubbleContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from "vue";
|
||||
import BubbleBody from "./BubbleBody.vue";
|
||||
import BubbleContainer from "./BubbleContainer.vue";
|
||||
import BubbleInfo from "./BubbleInfo.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ChatBubble",
|
||||
components: {
|
||||
BubbleContainer,
|
||||
BubbleBody,
|
||||
BubbleInfo,
|
||||
},
|
||||
props: {
|
||||
msg: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const lastEdit = computed(() => props.msg._edits.text);
|
||||
return {
|
||||
lastEdit,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-3 bg-white border-t shadow-2xl mt-auto dark:bg-transparent dark:border-stone-800"
|
||||
>
|
||||
<label class="sr-only" :for="inputId">Type a message and press Enter</label>
|
||||
<input
|
||||
:id="inputId"
|
||||
v-model="inputValue"
|
||||
class="rounded-full py-2 px-4 text-sm border block w-full dark:bg-black dark:text-white dark:border-stone-700"
|
||||
placeholder="Type a message and press Enter"
|
||||
maxlength="2048"
|
||||
@keydown.enter.prevent="submitMessage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ChatInput",
|
||||
emits: ["submit"],
|
||||
setup(_, { emit }) {
|
||||
const inputId = `input-${Math.random().toString(36).substr(2, 9)}`;
|
||||
const inputValue = ref("");
|
||||
|
||||
function submitMessage() {
|
||||
if (!inputValue.value) return;
|
||||
emit("submit", inputValue.value);
|
||||
inputValue.value = "";
|
||||
}
|
||||
|
||||
return {
|
||||
inputId,
|
||||
inputValue,
|
||||
submitMessage,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="h-full text-base text-stone-500 flex items-center justify-center px-3 md:text-xl"
|
||||
>
|
||||
Start a conversation below.
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "EmptyChatMessage",
|
||||
};
|
||||
</script>
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-3 bg-white w-full flex justify-end gap-1 text-xs border-b dark:bg-transparent dark:border-stone-800"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "TopBar",
|
||||
};
|
||||
</script>
|
||||
@@ -1 +0,0 @@
|
||||
@import "tailwindcss";
|
||||
@@ -1,36 +0,0 @@
|
||||
import { DemoAuthBasicUI, JazzProvider } from "jazz-vue";
|
||||
import { createApp, defineComponent, h } from "vue";
|
||||
import App from "./App.vue";
|
||||
import "./index.css";
|
||||
import { apiKey } from "@/apiKey";
|
||||
import router from "./router";
|
||||
|
||||
const RootComponent = defineComponent({
|
||||
name: "RootComponent",
|
||||
setup() {
|
||||
return () =>
|
||||
h(
|
||||
JazzProvider,
|
||||
{
|
||||
sync: {
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
},
|
||||
},
|
||||
h(
|
||||
DemoAuthBasicUI,
|
||||
{
|
||||
appName: "Jazz Vue Chat",
|
||||
},
|
||||
{
|
||||
default: () => h(App),
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const app = createApp(RootComponent);
|
||||
|
||||
app.use(router);
|
||||
|
||||
app.mount("#app");
|
||||
@@ -1,17 +0,0 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import Chat from "./views/ChatView.vue";
|
||||
import Home from "./views/HomeView.vue";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "Home",
|
||||
component: Home,
|
||||
},
|
||||
{ path: "/chat/:chatId", name: "Chat", component: Chat, props: true },
|
||||
],
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1,7 +0,0 @@
|
||||
import { CoList, CoMap, CoPlainText, coField } from "jazz-tools";
|
||||
|
||||
export class Message extends CoMap {
|
||||
text = coField.ref(CoPlainText);
|
||||
}
|
||||
|
||||
export class Chat extends CoList.Of(coField.ref(Message)) {}
|
||||
@@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<div v-if="chat">
|
||||
<ChatBody>
|
||||
<template v-if="chat.length > 0">
|
||||
<ChatBubble
|
||||
v-for="msg in displayedMessages"
|
||||
:key="msg.id"
|
||||
:msg="msg"
|
||||
/>
|
||||
</template>
|
||||
<EmptyChatMessage v-else />
|
||||
<button
|
||||
v-if="chat.length > showNLastMessages"
|
||||
class="px-4 py-1 block mx-auto my-2 border rounded"
|
||||
@click="showMoreMessages"
|
||||
>
|
||||
Show more
|
||||
</button>
|
||||
</ChatBody>
|
||||
<ChatInput @submit="handleSubmit" />
|
||||
</div>
|
||||
<div v-else class="flex-1 flex justify-center items-center">
|
||||
Loading...
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CoPlainText, type ID } from "jazz-tools";
|
||||
import { useCoState } from "jazz-vue";
|
||||
import { type PropType, computed, defineComponent, ref } from "vue";
|
||||
import ChatBody from "../components/ChatBody.vue";
|
||||
import ChatBubble from "../components/ChatBubble.vue";
|
||||
import ChatInput from "../components/ChatInput.vue";
|
||||
import EmptyChatMessage from "../components/EmptyChatMessage.vue";
|
||||
import { Chat, Message } from "../schema";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ChatView",
|
||||
components: {
|
||||
ChatBody,
|
||||
ChatInput,
|
||||
EmptyChatMessage,
|
||||
ChatBubble,
|
||||
},
|
||||
props: {
|
||||
chatId: {
|
||||
type: String as unknown as PropType<ID<Chat>>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chat = useCoState(Chat, props.chatId, { resolve: { $each: true } });
|
||||
const showNLastMessages = ref(30);
|
||||
|
||||
const displayedMessages = computed(() => {
|
||||
return chat?.value?.slice(-showNLastMessages.value).reverse();
|
||||
});
|
||||
|
||||
function showMoreMessages() {
|
||||
showNLastMessages.value += 10;
|
||||
}
|
||||
|
||||
function handleSubmit(text: string) {
|
||||
chat?.value?.push(
|
||||
Message.create(
|
||||
{ text: CoPlainText.create(text, chat.value._owner) },
|
||||
chat.value._owner,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
chat,
|
||||
showNLastMessages,
|
||||
displayedMessages,
|
||||
showMoreMessages,
|
||||
handleSubmit,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div>Creating a new chat...</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Group } from "jazz-tools";
|
||||
import { useAccount } from "jazz-vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Chat } from "../schema";
|
||||
|
||||
const router = useRouter();
|
||||
const { me } = useAccount();
|
||||
|
||||
if (me.value) {
|
||||
const group = Group.create({ owner: me.value });
|
||||
group.addMember("everyone", "writer");
|
||||
const chat = Chat.create([], { owner: group });
|
||||
router.push(`/chat/${chat.id}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { URL, fileURLToPath } from "node:url";
|
||||
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||
import { defineConfig } from "vite";
|
||||
import vueDevTools from "vite-plugin-vue-devtools";
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue(), vueJsx(), vueDevTools()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -60,4 +60,4 @@ If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/app.tsx](./src/app.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzReactProvider` in [./src/app.tsx](./src/app.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
"dependencies": {
|
||||
"clsx": "^2.0.0",
|
||||
"hash-slash": "workspace:*",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"lucide-react": "^0.274.0",
|
||||
"react": "19.0.0",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { apiKey } from "@/apiKey.ts";
|
||||
import { getRandomUsername, inIframe, onChatLoad } from "@/util.ts";
|
||||
import { useIframeHashRouter } from "hash-slash";
|
||||
import { JazzInspector } from "jazz-inspector";
|
||||
import { JazzProvider, useAccount } from "jazz-react";
|
||||
import { Group } from "jazz-tools";
|
||||
import { JazzInspector } from "jazz-tools/inspector";
|
||||
import { JazzReactProvider, useAccount } from "jazz-tools/react";
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { ChatScreen } from "./chatScreen.tsx";
|
||||
@@ -55,7 +55,7 @@ const defaultProfileName = url.searchParams.get("user") ?? getRandomUsername();
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<ThemeProvider>
|
||||
<StrictMode>
|
||||
<JazzProvider
|
||||
<JazzReactProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
@@ -63,7 +63,7 @@ createRoot(document.getElementById("root")!).render(
|
||||
>
|
||||
<App />
|
||||
<JazzInspector />
|
||||
</JazzProvider>
|
||||
</JazzReactProvider>
|
||||
</StrictMode>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createImage, useAccount, useCoState } from "jazz-react";
|
||||
import { Account, co } from "jazz-tools";
|
||||
import { createImage, useAccount, useCoState } from "jazz-tools/react";
|
||||
import { useState } from "react";
|
||||
import { Chat, Message } from "./schema.ts";
|
||||
import {
|
||||
@@ -19,7 +19,7 @@ export function ChatScreen(props: { chatID: string }) {
|
||||
const chat = useCoState(Chat, props.chatID, {
|
||||
resolve: { $each: { text: true } },
|
||||
});
|
||||
const account = useAccount();
|
||||
const { me } = useAccount();
|
||||
const [showNLastMessages, setShowNLastMessages] = useState(30);
|
||||
|
||||
if (!chat)
|
||||
@@ -50,6 +50,10 @@ export function ChatScreen(props: { chatID: string }) {
|
||||
});
|
||||
};
|
||||
|
||||
if (!me) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChatBody>
|
||||
@@ -57,7 +61,7 @@ export function ChatScreen(props: { chatID: string }) {
|
||||
chat
|
||||
.slice(-showNLastMessages)
|
||||
.reverse() // this plus flex-col-reverse on ChatBody gives us scroll-to-bottom behavior
|
||||
.map((msg) => <ChatBubble me={account.me} msg={msg} key={msg.id} />)
|
||||
.map((msg) => <ChatBubble me={me} msg={msg} key={msg.id} />)
|
||||
) : (
|
||||
<EmptyChatMessage />
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import clsx from "clsx";
|
||||
import { ProgressiveImg } from "jazz-react";
|
||||
import { CoPlainText, ImageDefinition } from "jazz-tools";
|
||||
import { ProgressiveImg } from "jazz-tools/react";
|
||||
import { ImageIcon } from "lucide-react";
|
||||
import { useId, useRef } from "react";
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clerk/clerk-react": "^5.4.1",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-react-auth-clerk": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SignInButton, SignOutButton } from "@clerk/clerk-react";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-react";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-tools/react";
|
||||
|
||||
function App() {
|
||||
const { me } = useAccount();
|
||||
|
||||
@@ -3,8 +3,8 @@ import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
import { JazzInspector } from "jazz-inspector";
|
||||
import { JazzProviderWithClerk } from "jazz-react-auth-clerk";
|
||||
import { JazzInspector } from "jazz-tools/inspector";
|
||||
import { JazzReactProviderWithClerk } from "jazz-tools/react";
|
||||
import { ReactNode } from "react";
|
||||
import { apiKey } from "./apiKey";
|
||||
|
||||
@@ -19,14 +19,14 @@ function JazzProvider({ children }: { children: ReactNode }) {
|
||||
const clerk = useClerk();
|
||||
|
||||
return (
|
||||
<JazzProviderWithClerk
|
||||
<JazzReactProviderWithClerk
|
||||
clerk={clerk}
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</JazzProviderWithClerk>
|
||||
</JazzReactProviderWithClerk>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"jazz-inspector-element": "workspace:*",
|
||||
"jazz-svelte": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"lucide-svelte": "^0.463.0",
|
||||
"svelte-sonner": "^0.3.28"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { JazzProvider } from 'jazz-svelte';
|
||||
import "jazz-inspector-element"
|
||||
import { PasskeyAuthBasicUI } from 'jazz-svelte';
|
||||
import { JazzSvelteProvider } from 'jazz-tools/svelte';
|
||||
import 'jazz-tools/inspector/register-custom-element';
|
||||
import { PasskeyAuthBasicUI } from 'jazz-tools/svelte';
|
||||
import { Toaster } from 'svelte-sonner';
|
||||
import '../app.css';
|
||||
import { FileShareAccount } from '$lib/schema';
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<Toaster richColors />
|
||||
|
||||
<JazzProvider
|
||||
<JazzSvelteProvider
|
||||
AccountSchema={FileShareAccount}
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
@@ -28,4 +28,4 @@
|
||||
{@render children()}
|
||||
</div>
|
||||
</PasskeyAuthBasicUI>
|
||||
</JazzProvider>
|
||||
</JazzSvelteProvider>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { AccountCoState } from 'jazz-svelte';
|
||||
import { AccountCoState } from 'jazz-tools/svelte';
|
||||
import { SharedFile, FileShareAccount } from '$lib/schema';
|
||||
import { FileStream, type Loaded } from 'jazz-tools';
|
||||
import FileItem from '$lib/components/FileItem.svelte';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { CoState } from 'jazz-svelte';
|
||||
import { CoState } from 'jazz-tools/svelte';
|
||||
import { SharedFile } from '$lib/schema';
|
||||
import { File, FileDown, Link2 } from 'lucide-svelte';
|
||||
import { FileStream } from 'jazz-tools';
|
||||
|
||||
@@ -63,4 +63,4 @@ If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzReactProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
"format-and-lint:fix": "biome check . --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { useAccount } from "jazz-react";
|
||||
import { co } from "jazz-tools";
|
||||
import { useAccount } from "jazz-tools/react";
|
||||
import { useRef, useState } from "react";
|
||||
import { JazzAccount } from "./schema";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { JazzInspector } from "jazz-inspector";
|
||||
import { JazzProvider } from "jazz-react";
|
||||
import { JazzInspector } from "jazz-tools/inspector";
|
||||
import { JazzReactProvider } from "jazz-tools/react";
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
@@ -12,7 +12,7 @@ export const APPLICATION_NAME = "Jazz File Stream Example";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<JazzProvider
|
||||
<JazzReactProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
@@ -20,6 +20,6 @@ createRoot(document.getElementById("root")!).render(
|
||||
>
|
||||
<JazzInspector />
|
||||
<App />
|
||||
</JazzProvider>
|
||||
</JazzReactProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
@@ -75,4 +75,4 @@ If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzReactProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"hash-slash": "workspace:*",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useIframeHashRouter } from "hash-slash";
|
||||
import { useAccount, useCoState } from "jazz-react";
|
||||
import { Loaded } from "jazz-tools";
|
||||
import { useAccount, useCoState } from "jazz-tools/react";
|
||||
import { useState } from "react";
|
||||
import { Errors } from "./Errors.tsx";
|
||||
import { LinkToHome } from "./LinkToHome.tsx";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useAccount } from "jazz-react";
|
||||
import { useAccount } from "jazz-tools/react";
|
||||
import { DraftBubbleTeaOrder, JazzAccount } from "./schema";
|
||||
export function DraftIndicator() {
|
||||
const { me } = useAccount(JazzAccount, {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCoState } from "jazz-react";
|
||||
import { useCoState } from "jazz-tools/react";
|
||||
import { LinkToHome } from "./LinkToHome.tsx";
|
||||
import { OrderForm } from "./OrderForm.tsx";
|
||||
import { OrderThumbnail } from "./OrderThumbnail.tsx";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useAccount } from "jazz-react";
|
||||
import { useAccount } from "jazz-tools/react";
|
||||
import { DraftIndicator } from "./DraftIndicator.tsx";
|
||||
import { OrderThumbnail } from "./OrderThumbnail.tsx";
|
||||
import { JazzAccount } from "./schema.ts";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { JazzInspector } from "jazz-inspector";
|
||||
import { JazzProvider } from "jazz-react";
|
||||
import { JazzInspector } from "jazz-tools/inspector";
|
||||
import { JazzReactProvider } from "jazz-tools/react";
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
@@ -9,7 +9,7 @@ import { JazzAccount } from "./schema.ts";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<JazzProvider
|
||||
<JazzReactProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
@@ -17,6 +17,6 @@ createRoot(document.getElementById("root")!).render(
|
||||
>
|
||||
<App />
|
||||
<JazzInspector />
|
||||
</JazzProvider>
|
||||
</JazzReactProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
@@ -63,4 +63,4 @@ If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzReactProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
"format-and-lint:fix": "biome check . --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ProgressiveImg, createImage, useAccount } from "jazz-react";
|
||||
import { ProgressiveImg, createImage, useAccount } from "jazz-tools/react";
|
||||
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||
import { JazzAccount } from "./schema";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { JazzInspector } from "jazz-inspector";
|
||||
import { JazzProvider } from "jazz-react";
|
||||
import { JazzInspector } from "jazz-tools/inspector";
|
||||
import { JazzReactProvider } from "jazz-tools/react";
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
@@ -9,7 +9,7 @@ import { JazzAccount } from "./schema.ts";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<JazzProvider
|
||||
<JazzReactProvider
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
@@ -17,6 +17,6 @@ createRoot(document.getElementById("root")!).render(
|
||||
>
|
||||
<App />
|
||||
<JazzInspector />
|
||||
</JazzProvider>
|
||||
</JazzReactProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"cojson": "workspace:*",
|
||||
"cojson-transport-ws": "workspace:*",
|
||||
"hash-slash": "workspace:*",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LocalNode } from "cojson";
|
||||
import { Breadcrumbs, PageStack } from "jazz-inspector";
|
||||
import type { PageInfo } from "jazz-inspector";
|
||||
import { Breadcrumbs, PageStack } from "jazz-tools/inspector";
|
||||
import type { PageInfo } from "jazz-tools/inspector";
|
||||
import { usePagePath } from "./use-page-path";
|
||||
|
||||
export default function CoJsonViewer({
|
||||
|
||||
@@ -17,8 +17,8 @@ import {
|
||||
Input,
|
||||
PageStack,
|
||||
Select,
|
||||
} from "jazz-inspector";
|
||||
import { AccountOrGroupText } from "jazz-inspector";
|
||||
} from "jazz-tools/inspector";
|
||||
import { AccountOrGroupText } from "jazz-tools/inspector";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { usePagePath } from "./use-page-path";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CoID, RawCoValue } from "cojson";
|
||||
import { PageInfo } from "jazz-inspector";
|
||||
import { PageInfo } from "jazz-tools/inspector";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export function usePagePath(defaultPath?: PageInfo[]) {
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { createOrganization } from "./data";
|
||||
import { createAccount, initializeKvStore } from "./lib";
|
||||
import { FileStream, Group } from "jazz-tools";
|
||||
import { createFile, createOrganization } from "./lib/data";
|
||||
import {
|
||||
addAccount,
|
||||
createAccount,
|
||||
initializeKvStore,
|
||||
inspectCoValue,
|
||||
} from "./lib/utils";
|
||||
|
||||
initializeKvStore();
|
||||
const { account, accountID, accountSecret } = await createAccount();
|
||||
|
||||
const organization = createOrganization();
|
||||
|
||||
test("should add and delete account in dropdown", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByLabel("Account ID").fill(accountID);
|
||||
await page.getByLabel("Account secret").fill(accountSecret);
|
||||
await page.getByRole("button", { name: "Add account" }).click();
|
||||
await addAccount(page, accountID, accountSecret);
|
||||
|
||||
await expect(page.getByText("Jazz CoValue Inspector")).toBeVisible();
|
||||
await page
|
||||
@@ -25,10 +30,7 @@ test("should add and delete account in dropdown", async ({ page }) => {
|
||||
});
|
||||
|
||||
test("should inspect account", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByLabel("Account ID").fill(accountID);
|
||||
await page.getByLabel("Account secret").fill(accountSecret);
|
||||
await page.getByRole("button", { name: "Add account" }).click();
|
||||
await addAccount(page, accountID, accountSecret);
|
||||
await page.getByRole("button", { name: "Inspect my account" }).click();
|
||||
|
||||
await expect(page.getByRole("heading", { name: accountID })).toBeVisible();
|
||||
@@ -39,17 +41,11 @@ test("should inspect account", async ({ page }) => {
|
||||
});
|
||||
|
||||
test("should inspect CoValue", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByLabel("Account ID").fill(accountID);
|
||||
await page.getByLabel("Account secret").fill(accountSecret);
|
||||
await page.getByRole("button", { name: "Add account" }).click();
|
||||
|
||||
const organization = createOrganization();
|
||||
await addAccount(page, accountID, accountSecret);
|
||||
|
||||
await account.waitForAllCoValuesSync(); // Ensures that the organization is uploaded
|
||||
|
||||
await page.getByLabel("CoValue ID").fill(organization.id);
|
||||
await page.getByRole("button", { name: "Inspect CoValue" }).click();
|
||||
await inspectCoValue(page, organization.id);
|
||||
|
||||
await expect(page.getByText(/Garden Computing/)).toHaveCount(2);
|
||||
await expect(
|
||||
@@ -77,6 +73,118 @@ test("should inspect CoValue", async ({ page }) => {
|
||||
await page.getByRole("button", { name: "issues" }).click();
|
||||
await expect(page.getByRole("table").getByRole("row")).toHaveCount(4);
|
||||
|
||||
const table = page.getByRole("table");
|
||||
const row = table.getByRole("row").nth(1);
|
||||
const issue = organization.projects[0].issues[0];
|
||||
|
||||
// Test if table is displaying the Issue data correctly
|
||||
await expect(row.getByRole("cell").nth(0)).toHaveText(issue.title);
|
||||
await expect(row.getByRole("cell").nth(1)).toHaveText(issue.status);
|
||||
await expect(
|
||||
row.getByRole("cell").nth(2).getByRole("button", { name: issue.labels.id }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
row
|
||||
.getByRole("cell")
|
||||
.nth(3)
|
||||
.getByRole("button", { name: issue.reactions.id }),
|
||||
).toBeVisible();
|
||||
|
||||
if (issue.file) {
|
||||
await expect(
|
||||
row.getByRole("cell").nth(4).getByRole("button", { name: issue.file.id }),
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
if (issue.image) {
|
||||
await expect(
|
||||
row
|
||||
.getByRole("cell")
|
||||
.nth(5)
|
||||
.getByRole("button", { name: issue.image.id }),
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
// Test if CoMap/grid view is displaying Issue data correctly
|
||||
await row.getByRole("button", { name: "View" }).click();
|
||||
await expect(page.getByRole("table")).not.toBeVisible();
|
||||
await expect(page.getByText(issue.title)).toBeVisible();
|
||||
await expect(page.getByText(issue.status)).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: /labels/ })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: /reactions/ })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: /file/ })).toBeVisible();
|
||||
|
||||
await expect(page.getByRole("button", { name: /^image/ })).toBeVisible();
|
||||
await page.pause();
|
||||
|
||||
await page.getByRole("button", { name: "projects" }).click();
|
||||
await expect(page.getByRole("table").getByRole("row")).toHaveCount(5);
|
||||
});
|
||||
|
||||
test("should show CoValue type", async ({ page }) => {
|
||||
await addAccount(page, accountID, accountSecret);
|
||||
|
||||
await account.waitForAllCoValuesSync(); // Ensures that the organization is uploaded
|
||||
|
||||
// Test FileStream
|
||||
const file = createFile();
|
||||
await inspectCoValue(page, file.id);
|
||||
await expect(page.getByText("📃 FileStream")).toBeVisible();
|
||||
|
||||
// Test ImageDefinition
|
||||
await inspectCoValue(page, organization.image.id);
|
||||
await expect(page.getByText("🖼️ Image")).toBeVisible();
|
||||
|
||||
// Test CoMap
|
||||
await inspectCoValue(page, organization.id);
|
||||
await expect(page.getByText("{} CoMap")).toBeVisible();
|
||||
|
||||
// Test CoList
|
||||
await inspectCoValue(page, organization.projects.id);
|
||||
await expect(page.getByText("☰ CoList")).toBeVisible();
|
||||
|
||||
// Test CoFeed
|
||||
await inspectCoValue(page, organization.projects[0].issues[0].reactions.id);
|
||||
await expect(page.getByText("≋ CoFeed")).toBeVisible();
|
||||
|
||||
// Test Account
|
||||
await inspectCoValue(page, account.id);
|
||||
await expect(page.getByText("👤 Account")).toBeVisible();
|
||||
|
||||
// Test Group
|
||||
await inspectCoValue(page, organization._owner.id);
|
||||
await expect(page.getByText("👥 Group")).toBeVisible();
|
||||
});
|
||||
|
||||
test("should show Group members", async ({ page }) => {
|
||||
await addAccount(page, accountID, accountSecret);
|
||||
|
||||
organization._owner.castAs(Group).addMember("everyone", "reader");
|
||||
|
||||
await account.waitForAllCoValuesSync(); // Ensures that the organization is uploaded
|
||||
await inspectCoValue(page, organization.id);
|
||||
|
||||
const ownershipText = await page.getByText(/Owned by/).innerText();
|
||||
expect(ownershipText).toContain(`Group <${organization._owner.id}>`);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: `Group <${organization._owner.id}>` })
|
||||
.click();
|
||||
|
||||
const table = page.getByRole("table");
|
||||
|
||||
const row1 = table.getByRole("row").nth(1);
|
||||
await expect(row1.getByRole("cell").nth(0)).toHaveText("everyone");
|
||||
await expect(row1.getByRole("cell").nth(1)).toHaveText("reader");
|
||||
|
||||
const row2 = table.getByRole("row").nth(2);
|
||||
await expect(row2.getByRole("cell").nth(0)).toHaveText(
|
||||
`Inspector test account <${account.id}>`,
|
||||
);
|
||||
await expect(row2.getByRole("cell").nth(1)).toHaveText("admin");
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: `Inspector test account <${account.id}>` })
|
||||
.click();
|
||||
await expect(page.getByText("👤 Account")).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { co, z } from "jazz-tools";
|
||||
import { FileStream, ImageDefinition, co, z } from "jazz-tools";
|
||||
import {
|
||||
Issue,
|
||||
Organization,
|
||||
Project,
|
||||
ReactionType,
|
||||
ReactionsList,
|
||||
} from "./schema";
|
||||
|
||||
const projectsData: {
|
||||
name: string;
|
||||
@@ -7,6 +14,9 @@ const projectsData: {
|
||||
title: string;
|
||||
status: "open" | "closed";
|
||||
labels: string[];
|
||||
reactions?: ReactionType[];
|
||||
file?: boolean;
|
||||
image?: boolean;
|
||||
}[];
|
||||
}[] = [
|
||||
{
|
||||
@@ -28,6 +38,9 @@ const projectsData: {
|
||||
"high priority",
|
||||
"urgent",
|
||||
],
|
||||
reactions: ["thumb-up"],
|
||||
image: true,
|
||||
file: true,
|
||||
},
|
||||
{ title: "Issue 2", status: "closed", labels: ["bug"] },
|
||||
{ title: "Issue 3", status: "open", labels: ["feature", "enhancement"] },
|
||||
@@ -50,26 +63,28 @@ const projectsData: {
|
||||
},
|
||||
];
|
||||
|
||||
const Issue = co.map({
|
||||
title: z.string(),
|
||||
status: z.enum(["open", "closed"]),
|
||||
labels: co.list(z.string()),
|
||||
});
|
||||
export const createFile = () => {
|
||||
const file = FileStream.create();
|
||||
file.start({ mimeType: "image/jpeg" });
|
||||
file.push(new Uint8Array([1, 2, 3]));
|
||||
file.end();
|
||||
return file;
|
||||
};
|
||||
|
||||
const Project = co.map({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
issues: co.list(Issue),
|
||||
});
|
||||
|
||||
const Organization = co.map({
|
||||
name: z.string(),
|
||||
projects: co.list(Project),
|
||||
});
|
||||
export const createImage = () => {
|
||||
return ImageDefinition.create({
|
||||
originalSize: [1920, 1080],
|
||||
placeholderDataURL: "data:image/jpeg;base64,...",
|
||||
});
|
||||
};
|
||||
|
||||
export const createOrganization = () => {
|
||||
return Organization.create({
|
||||
name: "Garden Computing",
|
||||
image: ImageDefinition.create({
|
||||
originalSize: [1920, 1080],
|
||||
placeholderDataURL: "data:image/jpeg;base64,...",
|
||||
}),
|
||||
projects: co.list(Project).create(
|
||||
projectsData.map((project) =>
|
||||
Project.create({
|
||||
@@ -81,6 +96,9 @@ export const createOrganization = () => {
|
||||
title: issue.title,
|
||||
status: issue.status,
|
||||
labels: co.list(z.string()).create(issue.labels),
|
||||
reactions: ReactionsList.create(issue.reactions || []),
|
||||
file: issue.file ? createFile() : undefined,
|
||||
image: issue.image ? createImage() : undefined,
|
||||
}),
|
||||
),
|
||||
),
|
||||
29
examples/inspector/tests/lib/schema.ts
Normal file
29
examples/inspector/tests/lib/schema.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { co, z } from "jazz-tools";
|
||||
|
||||
export const ReactionTypes = ["thumb-up", "thumb-down"] as const;
|
||||
|
||||
export type ReactionType = (typeof ReactionTypes)[number];
|
||||
|
||||
export const ReactionsList = co.feed(z.literal([...ReactionTypes]));
|
||||
|
||||
export const Issue = co.map({
|
||||
title: z.string(),
|
||||
status: z.enum(["open", "closed"]),
|
||||
labels: co.list(z.string()),
|
||||
reactions: ReactionsList,
|
||||
file: z.optional(co.fileStream()),
|
||||
image: z.optional(co.image()),
|
||||
lead: z.optional(co.account()),
|
||||
});
|
||||
|
||||
export const Project = co.map({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
issues: co.list(Issue),
|
||||
});
|
||||
|
||||
export const Organization = co.map({
|
||||
name: z.string(),
|
||||
projects: co.list(Project),
|
||||
image: co.image(),
|
||||
});
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Page } from "@playwright/test";
|
||||
import { createWebSocketPeer } from "cojson-transport-ws";
|
||||
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
||||
import {
|
||||
AuthSecretStorage,
|
||||
InMemoryKVStore,
|
||||
KvStoreContext,
|
||||
co,
|
||||
createJazzContext,
|
||||
randomSessionProvider,
|
||||
z,
|
||||
} from "jazz-tools";
|
||||
|
||||
export const initializeKvStore = () => {
|
||||
@@ -41,3 +40,20 @@ export async function createAccount() {
|
||||
|
||||
return { account, ...credentials };
|
||||
}
|
||||
|
||||
export async function addAccount(
|
||||
page: Page,
|
||||
accountID: string,
|
||||
accountSecret: string,
|
||||
) {
|
||||
await page.goto("/");
|
||||
await page.getByLabel("Account ID").fill(accountID);
|
||||
await page.getByLabel("Account secret").fill(accountSecret);
|
||||
await page.getByRole("button", { name: "Add account" }).click();
|
||||
}
|
||||
|
||||
export async function inspectCoValue(page: Page, coValueId: string) {
|
||||
await page.goto("/");
|
||||
await page.getByLabel("CoValue ID").fill(coValueId);
|
||||
await page.getByRole("button", { name: "Inspect CoValue" }).click();
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"next": "15.3.2",
|
||||
"react": "^19.0.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useAccount } from "jazz-react";
|
||||
import { Account } from "jazz-tools";
|
||||
import { useAccount } from "jazz-tools/react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Home() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user