Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { useQuery } from '@tanstack/react-query';
import { Array as EffectArray, Order, pipe } from 'effect';
import { useState } from 'react';

import type { SchemaBrowserTypesQuery } from '../../../generated/graphql';
import { schemaBrowserQueryOptions } from '../../../hooks/useSchemaBrowserQuery';
import { Loading } from '../../Loading';
import type { SchemaBrowserTypesQuery } from '../../../../generated/graphql';
import { schemaBrowserQueryOptions } from '../../../../hooks/useSchemaBrowserQuery';
import { Loading } from '../../../Loading';

export type SchemaBrowserType = NonNullable<SchemaBrowserTypesQuery['space']>['types'][number];
type ExtendedSchemaBrowserType = SchemaBrowserType & { slug: string };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import { Label, Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react';
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/16/solid';
import { Array as EffectArray, String as EffectString, Schema, pipe } from 'effect';
import type { UseFormSetValue } from 'react-hook-form';

import type { InsertAppSchema } from '../../../schema.js';
import { classnames } from '../../../utils/classnames.js';
import { useFieldContext } from '../../../../context/form.js';
import { classnames } from '../../../../utils/classnames.js';

class TypeOption extends Schema.Class<TypeOption>('/hypergraph/typesync/models/TypeOption')({
id: Schema.NonEmptyTrimmedString,
Expand All @@ -27,20 +26,12 @@ const typeOptions: Array<TypeOption> = [
];

export function TypeCombobox({
typePropertyIdx,
typeIdx,
value,
onTypeSelected,
id,
name,
schemaTypes = [],
}: Readonly<{
/** the index of this type selection field in the properties array. Types.AppSchemaForm.types[idx].properties[typeInputIdx] */
typePropertyIdx: number;
/** the index of the type within the schema array Types.AppSchemaForm.types[typeIdx] */
typeIdx: number;
/** the current value */
value: string;
/** set the value in the form when the user selects a value */
onTypeSelected: UseFormSetValue<InsertAppSchema>;
id: string;
name: string;
/**
* A list of types within the defined schema that the user can use as a relation
* This allows the user to specify the property as a relationship to a type in the schema
Expand All @@ -49,6 +40,8 @@ export function TypeCombobox({
*/
schemaTypes?: Array<string> | undefined;
}>) {
const field = useFieldContext<string>();

const relationTypeOptions = pipe(
schemaTypes,
EffectArray.filter((_type) => EffectString.isNonEmpty(_type)),
Expand All @@ -60,23 +53,20 @@ export function TypeCombobox({
return (
<Listbox
as="div"
id={`types.${typeIdx}.properties.${typePropertyIdx}.type_name`}
name={`types.${typeIdx}.properties.${typePropertyIdx}.type_name`}
value={value}
id={id}
name={name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(value) => {
if (value) {
onTypeSelected(`types.${typeIdx}.properties.${typePropertyIdx}.type_name`, value, {
shouldDirty: true,
shouldTouch: true,
shouldValidate: true,
});
field.handleChange(value);
}
}}
>
<Label className="sr-only">Prop type</Label>
<div className="relative">
<ListboxButton className="grid w-full cursor-default grid-cols-1 rounded-md bg-slate-900 py-1.5 pr-2 pl-3 text-left text-white outline-1 -outline-offset-1 outline-gray-500 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6">
<span className="col-start-1 row-start-1 truncate pr-6">{value}</span>
<span className="col-start-1 row-start-1 truncate pr-6">{field.state.value}</span>
<ChevronUpDownIcon
aria-hidden="true"
className="col-start-1 row-start-1 size-5 self-center justify-self-end text-gray-300 sm:size-4"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createFormHook } from '@tanstack/react-form';

import { fieldContext, formContext } from '../../../context/form.js';
import {
FormComponentRadioGroup,
FormComponentTextArea,
FormComponentTextField,
SubmitButton,
} from '../../FormComponents/index.js';
import { TypeCombobox } from './SchemaBuilder/TypeCombobox.js';

export const { useAppForm } = createFormHook({
fieldComponents: {
FormComponentTextField,
FormComponentTextArea,
FormComponentRadioGroup,
TypeCombobox,
},
formComponents: {
SubmitButton,
},
fieldContext,
formContext,
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useQuery } from '@tanstack/react-query';
import type { CSSProperties } from 'react';
import { type ThemedToken, codeToTokens } from 'shiki';

import type { AppSchema } from '../../../schema.js';
import { classnames } from '../../../utils/classnames.js';
import type * as Types from './types.js';
import * as Utils from './utils.js';

enum FontStyle {
Expand All @@ -20,7 +20,7 @@ enum FontStyle {
type CodeChunk = ThemedToken;
type CodeLine = { chunks: Array<CodeChunk>; style: 'added' | 'deleted' | null };

export function SchemaPreview({ schema }: Readonly<{ schema: Types.AppSchemaForm }>) {
export function SchemaPreview({ schema }: Readonly<{ schema: AppSchema }>) {
const { code, hash } = Utils.buildAppSchemaFormCode(schema);
const { data } = useQuery({
queryKey: ['App', 'schema', 'preview', hash] as const,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import type { AppSchemaField, AppSchemaForm } from './types.js';
import type { AppSchema } from '../../../schema.js';

function fieldToEntityString({
name,
typeName,
type_name,
nullable = false,
optional = false,
description,
}: AppSchemaField): string {
}: AppSchema['types'][number]['properties'][number]): string {
// Add JSDoc comment if description exists
const jsDoc = description ? ` /** ${description} */\n` : '';

// Convert type to Entity type
const entityType = (() => {
switch (true) {
case typeName === 'Text':
case type_name === 'Text':
return 'Type.Text';
case typeName === 'Number':
case type_name === 'Number':
return 'Type.Number';
case typeName === 'Boolean':
case type_name === 'Boolean':
return 'Type.Boolean';
case typeName === 'Date':
case type_name === 'Date':
return 'Type.Date';
case typeName === 'Url':
case type_name === 'Url':
return 'Type.Url';
case typeName === 'Point':
case type_name === 'Point':
return 'Type.Point';
case typeName.startsWith('Relation'):
case type_name.startsWith('Relation'):
// renders the type as `Type.Relation(Entity)`
return `Type.${typeName}`;
return `Type.${type_name}`;
Comment on lines -16 to +30
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@nikgraf one of my follow-up PRs will be to update the schema type to come over as camelCase, instead of snake_case when the data is pulled from the database. When I do that, this will be updated.

Copy link
Collaborator

Choose a reason for hiding this comment

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

👍 btw also fine to keep snake case if there is a good reason. just was curious

default:
// how to handle complex types
return 'Type.Text';
Expand All @@ -46,7 +46,7 @@ function fieldToEntityString({

function typeDefinitionToString(type: {
name: string;
properties: Readonly<Array<AppSchemaField>>;
properties: ReadonlyArray<AppSchema['types'][number]['properties'][number]>;
}): string | null {
if (!type.name) {
return null;
Expand Down Expand Up @@ -97,7 +97,7 @@ ${fieldStrings.join(',\n')}
* @param schema the app schema being built by the user
* @returns a typescript string representation of the schema as well as a 20bit hash to pass to the useQuery hook
*/
export function buildAppSchemaFormCode(schema: AppSchemaForm): Readonly<{ code: string; hash: string }> {
export function buildAppSchemaFormCode(schema: AppSchema): Readonly<{ code: string; hash: string }> {
const fileCommentStatement = '// src/schema.ts';
const importStatement = `import { Entity, Type } from '@graphprotocol/hypergraph';\nimport * as Schema from 'effect/Schema';`;
const typeDefinitions = schema.types
Expand Down
Loading
Loading