full switch to jotai, finishes schema version query fixes

This commit is contained in:
Emmaline Autumn 2024-09-05 05:22:29 -06:00
parent b529445851
commit 84cbea8ce1
12 changed files with 148 additions and 91 deletions

2
.gitignore vendored
View File

@ -43,3 +43,5 @@ temp.json
temp.md
.dragonshoard/
certificates

View File

@ -3,33 +3,70 @@ import { auth } from "@/auth";
import { isEmailVerified } from "@/util/isEmailVerified";
import { redirect } from "next/navigation";
import { prisma } from "@/prisma/prismaClient";
import { Schema } from "@/types";
export const saveSchemaDb = async (s: Schema) => {
export const saveSchemaDb = async (s: Schema, version: number) => {
const sesh = await auth();
if (!sesh?.user?.id) return;
const { id } = await prisma.schema.upsert({
const { id, SchemaRevision } = await prisma.schema.upsert({
// data: {
// ...s,
// },
create: {
...s,
version: 0,
name: s.name,
SchemaRevision: {
create: {
fields: s.fields,
types: s.types,
},
},
authorId: sesh.user.id,
id: undefined,
},
update: s,
update: {
name: s.name,
},
where: {
id: s.id,
},
select: {
id: true,
include: {
// id: true,
SchemaRevision: {
where: {
version: s.version,
},
select: {
version: true,
isFinal: true,
},
},
},
});
// const schema2 = await prisma.schema.findUnique({where:{id}})
if (
!SchemaRevision.at(0) ||
SchemaRevision[0].version < version ||
SchemaRevision[0].isFinal
) {
await prisma.schemaRevision.create({
data: {
schemaId: id,
types: s.types,
fields: s.fields,
version,
},
});
}
redirect(`/game-systems/${s.gameSystemId}/schema/${id}`);
};
export const findSchema = async (id: string): Promise<Schema | null> => {
export const findSchema = async (
id: string,
version: number,
): Promise<Schema | null> => {
const schema = await prisma.schema.findFirst({
where: {
id,
@ -42,17 +79,33 @@ export const findSchema = async (id: string): Promise<Schema | null> => {
// },
// },
// },
select: {
id: true,
name: true,
schema: true,
types: true,
include: {
SchemaRevision: {
where: {
version,
},
select: {
version: true,
fields: true,
types: true,
},
},
},
// select: {
// id: true,
// name: true,
// },
});
if (!schema) return null;
if (!schema?.SchemaRevision[0]) return null;
return schema as Schema;
return {
fields: schema.SchemaRevision[0].fields,
types: schema.SchemaRevision[0].types,
id: schema.id,
gameSystemId: schema.gameSystemId,
name: schema.name,
} as Schema;
};
export const createSchema = async (form: FormData) => {
@ -67,9 +120,6 @@ export const createSchema = async (form: FormData) => {
const { id } = await prisma.schema.create({
data: {
name,
schema: "{}",
types: "{}",
version: 0,
gameSystemId: gsId,
authorId: session.user.id,
},

View File

@ -20,6 +20,8 @@ export const { handlers, signIn, signOut, auth } = NextAuth(async () => {
Discord({
clientId,
clientSecret,
// redirectProxyUrl:
// "https://bottomsurgery.local:3000/api/auth/callback/discord",
}),
Credentials({
credentials: {

View File

@ -1,15 +1,14 @@
// import { useRecoilValue } from "recoil";
import { SchemaEditAtom } from "../../recoil/atoms/schema";
import { TEMPLATE_TYPES } from "../../constants/TemplateTypes";
import { FC, PropsWithChildren } from "react";
import { useAtom } from "jotai";
import { InputBinder } from "@/types";
interface IProps {
bind: InputBinder;
}
export const FieldTypeInput: FC<PropsWithChildren<IProps>> = ({ bind }) => {
// const schema = useRecoilValue(SchemaEditAtom);
const [schema] = useAtom(SchemaEditAtom);
return (

View File

@ -14,10 +14,10 @@ import { FieldTypes } from "./fieldtypes";
import { findSchema, saveSchemaDb } from "@/actions/Schemas/index";
import { useToast } from "../toast";
import { useAtom } from "jotai";
import { Schema } from "@/types";
import { Schema, TypeType } from "@/types";
export const SchemaBuilder: FC = () => {
const [schema, setSchema] = useAtom(SchemaEditAtom);
const [schema, setSchema] = useAtom<Schema>(SchemaEditAtom);
// const resetSchema = useResetRecoilState(SchemaEditAtom);
const { createToast } = useToast();
const { update: updateSchema, bindProperty: bindSchemaProperty } =
@ -30,7 +30,7 @@ export const SchemaBuilder: FC = () => {
useEffect(() => {
if (schemaId !== "create" && schemaId !== schema.id)
findSchema(schemaId).then((sc) => {
findSchema(schemaId, 0).then((sc) => {
if (!sc) return;
setSchema(sc);
});
@ -70,7 +70,7 @@ export const SchemaBuilder: FC = () => {
const saveSchema = useCallback(async () => {
createToast({ msg: "Saving Schema", fading: true });
await saveSchemaDb(schema);
await saveSchemaDb(schema, schema.version);
}, [createToast, schema]);
const selectTypeForEdit = useCallback((typeKey: string) => {

View File

@ -17,6 +17,13 @@ export default function SignIn() {
type="password"
name="password"
/>
<button
role="button"
type="submit"
className="w-full p-2 rounded-lg bg-primary-500"
>
Sign In
</button>
</form>
<div className="flex items-center gap-1">
<div className="dark:border-dark-500 border-primary-600 flex-grow border-b"></div>
@ -24,7 +31,10 @@ export default function SignIn() {
<div className="dark:border-dark-500 border-primary-600 flex-grow border-b"></div>
</div>
<form action={signInWithDiscord}>
<button className="w-full p-2 bg-[#816ab1] rounded-lg" type="submit">
<button
className="w-full p-2 bg-[#816ab1] rounded-lg flex items-center justify-center"
type="submit"
>
<Icon icon="Discord" className="mr-4 inline-block" />
Sign in with Discord
</button>

View File

@ -1,10 +1,10 @@
import { PublicationAtom } from "@/recoil/atoms/publication";
import { useState, useEffect, useCallback, useRef, ReactNode } from "react";
import { useRecoilValue } from "recoil";
import { TTCQueryResolver } from "../ttcQuery/TTCResolvers";
import { useAtom } from "jotai";
export function Resolver({ resolver }: { resolver: string }) {
const parser = useRecoilValue(PublicationAtom);
const [parser] = useAtom(PublicationAtom);
const [res] = useState(new TTCQueryResolver(parser));
const [content, setContent] = useState<ReactNode>("");
useEffect(() => {
@ -15,7 +15,7 @@ export function Resolver({ resolver }: { resolver: string }) {
<resolved.display />
) : (
resolved?.display
)
),
);
}, [resolver, res]);
return <span>{content}</span>;
@ -31,7 +31,7 @@ export function OnDemandResolver({
template: string;
title?: string;
}) {
const parser = useRecoilValue(PublicationAtom);
const [parser] = useAtom(PublicationAtom);
const res = useRef(new TTCQueryResolver(parser));
const [content, setContent] = useState<ReactNode>("");
const generateContent = useCallback(() => {

View File

@ -5,11 +5,13 @@ import { Poppable } from "../poppables/components/poppable";
import { Accordion, AccordionContent } from "../accordion";
import { OnDemandResolver, Resolver } from "./Resolver";
// import "crypto";
export const TokenRenderers = new Map<string, TokenRenderer<any>>();
export function buildIdentifierMap(): [
TokenIdentifierMap,
IdentifierRegistration
IdentifierRegistration,
] {
const TokenIdentifiers = new Map<string, TokenIdentifier<any>>();
@ -17,7 +19,7 @@ export function buildIdentifierMap(): [
type: string,
match: RegExp,
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<M>,
renderFunction: TokenRenderer<M>
renderFunction: TokenRenderer<M>,
): void;
function registerIdentifier<M>(
type: string,
@ -25,7 +27,7 @@ export function buildIdentifierMap(): [
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<M>,
renderFunction: TokenRenderer<M>,
openTagRx: RegExp,
closeTagRx: RegExp
closeTagRx: RegExp,
): void;
function registerIdentifier<M = Record<string, string>>(
type: string,
@ -33,7 +35,7 @@ export function buildIdentifierMap(): [
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<M>,
renderFunction: TokenRenderer<M>,
openTagRx?: RegExp,
closeTagRx?: RegExp
closeTagRx?: RegExp,
) {
TokenIdentifiers.set(type, {
rx: match,
@ -54,7 +56,7 @@ export function buildIdentifierMap(): [
start,
end,
new RegExp(openTagRx, "g"),
new RegExp(closeTagRx, "g")
new RegExp(closeTagRx, "g"),
);
}
: undefined,
@ -125,7 +127,7 @@ export const buildOnlyDefaultElements = () => {
);
},
/(?<![\/\?])(?:\[\])+/g,
/\/\[\]/g
/\/\[\]/g,
);
// card
@ -170,7 +172,7 @@ export const buildOnlyDefaultElements = () => {
);
},
/\[\[/g,
/\]\]/g
/\]\]/g,
);
// fenced code block
@ -192,7 +194,7 @@ export const buildOnlyDefaultElements = () => {
{token.content}
</pre>
);
}
},
);
// list
@ -231,7 +233,7 @@ export const buildOnlyDefaultElements = () => {
</ul>
</>
);
}
},
);
// ordered-list
@ -271,7 +273,7 @@ export const buildOnlyDefaultElements = () => {
</ol>
</>
);
}
},
);
// ordered list-item
@ -300,7 +302,7 @@ export const buildOnlyDefaultElements = () => {
))}
</li>
);
}
},
);
// heading
@ -336,7 +338,7 @@ export const buildOnlyDefaultElements = () => {
{token.content}
</div>
);
}
},
);
// image
@ -373,7 +375,7 @@ export const buildOnlyDefaultElements = () => {
}
// eslint-disable-next-line @next/next/no-img-element
return <img src={metadata.src} alt={token.content} />;
}
},
);
// anchor
@ -417,7 +419,7 @@ export const buildOnlyDefaultElements = () => {
{token.content}
</Link>
);
}
},
);
// inline-code
@ -440,7 +442,7 @@ export const buildOnlyDefaultElements = () => {
{token.content}
</span>
);
}
},
);
// bold
@ -458,7 +460,7 @@ export const buildOnlyDefaultElements = () => {
},
(token) => {
return <span className="font-bold">{token.content}</span>;
}
},
);
// italic
@ -477,7 +479,7 @@ export const buildOnlyDefaultElements = () => {
},
(token) => {
return <span className="italic">{token.content}</span>;
}
},
);
// popover
@ -513,7 +515,7 @@ export const buildOnlyDefaultElements = () => {
</span>
</Poppable>
);
}
},
);
// accordion
@ -543,7 +545,7 @@ export const buildOnlyDefaultElements = () => {
</Accordion>
</div>
);
}
},
);
// paragraph
@ -569,7 +571,7 @@ export const buildOnlyDefaultElements = () => {
})}
</div>
);
}
},
);
// horizontal rule
@ -587,7 +589,7 @@ export const buildOnlyDefaultElements = () => {
},
() => {
return <div className="w-full border-b border-mixed-500 my-3"></div>;
}
},
);
// comment
@ -605,7 +607,7 @@ export const buildOnlyDefaultElements = () => {
},
() => {
return <></>;
}
},
);
// frontmatter
@ -624,7 +626,7 @@ export const buildOnlyDefaultElements = () => {
},
(token) => {
return <>{token.raw}</>;
}
},
);
// table
@ -655,8 +657,8 @@ export const buildOnlyDefaultElements = () => {
r
.split("|")
.map((c) => c.trim())
.filter((c) => !!c)
)
.filter((c) => !!c),
),
);
let headerRows: string[][] = [],
@ -679,7 +681,7 @@ export const buildOnlyDefaultElements = () => {
}
const maxColumns = Math.max(
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length)
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length),
);
return {
@ -770,7 +772,7 @@ export const buildOnlyDefaultElements = () => {
)}
</table>
);
}
},
);
// resolver
@ -797,7 +799,7 @@ export const buildOnlyDefaultElements = () => {
if (t.content.startsWith("Error"))
return <span className="red-500">{t.content}</span>;
return <Resolver resolver={t.content} />;
}
},
);
// on-demand resolver
@ -839,7 +841,7 @@ export const buildOnlyDefaultElements = () => {
title={t.metadata.title}
/>
);
}
},
);
return TokenIdentifiers;
@ -848,7 +850,7 @@ export const buildOnlyDefaultElements = () => {
function findMatchingClosedParenthesis(
str: string,
openRegex: RegExp,
closedRegex: RegExp
closedRegex: RegExp,
): number | null {
let openings = 0;
let closings = 0;
@ -904,7 +906,7 @@ function search(
start: number,
end: number,
openRx: RegExp,
closeRx: RegExp
closeRx: RegExp,
): SearchResult {
const oldEnd = end;
@ -912,7 +914,7 @@ function search(
s,
// s.substring(0, end - start),
openRx,
closeRx
closeRx,
);
if (newEnd === null)

View File

@ -1,9 +1,14 @@
import { TTCQueryParser } from "@/lib/ttcQuery/TTCQueryParser";
import { atom } from "recoil";
import { atom } from "jotai";
// import { atom } from "recoil";
export const PublicationAtom = atom({
key: "publication",
default: new TTCQueryParser({
path: { to: { dice: "2d6" } },
}),
});
// export const PublicationAtom = atom({
// key: "publication",
// default: new TTCQueryParser({
// path: { to: { dice: "2d6" } },
// }),
// });
export const PublicationAtom = atom(
new TTCQueryParser({ path: { to: { dice: "2d6" } } }),
);

View File

@ -1,5 +1,6 @@
// import { atom } from "recoil";
import { Schema } from "@/types";
import { atom } from "jotai";
// export const SchemaEditAtom = atom<Schema>({
@ -12,4 +13,5 @@ export const SchemaEditAtom = atom<Schema>({
id: "",
types: {},
fields: {},
version: 0,
});

View File

@ -1,10 +1,6 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@ -22,23 +18,11 @@
}
],
"paths": {
"@/*": [
"./*"
]
"@/*": ["./*"]
},
"target": "es2022"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
],
"exclude": [
"node_modules"
],
"files": [
"global.d.ts",
"./components/mdeditor/TextEditor.tsx"
]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"],
"files": ["global.d.ts", "types.d.ts", "./components/mdeditor/TextEditor.tsx"]
}

3
types.d.ts vendored
View File

@ -87,7 +87,8 @@ type Schema = {
name: string;
fields: SchemaFields;
types: SchemaTypes;
gameSystemId?: string;
version: number;
gameSystemId?: string | null;
};
// Input Binder