Skip to content

Commit

Permalink
Merge pull request #37 from xolvio/chore/enable-seed-editing
Browse files Browse the repository at this point in the history
`Chore`: Enable seed editing
  • Loading branch information
coolchock authored Dec 2, 2024
2 parents 81d3ce4 + 5e2c3cd commit 4f21786
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 39 deletions.
13 changes: 8 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# GITHUB_CLIENT_ID=
# GITHUB_CLIENT_SECRET=
# AZURE_CLIENT_ID=
# AZURE_CLIENT_SECRET=

# APOLLO_API_KEY=
# POSTGRES_USER=myuser
# POSTGRES_PASSWORD=mypassword
# POSTGRES_DB=instant_mock_db
# POSTGRES_HOST=postgres_db
# POSTGRES_PORT=5432
# BACKEND_PORT=3008
# FRONTEND_DEV_SERVER_PORT=3009
24 changes: 16 additions & 8 deletions backend/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import './loadEnv';
import 'reflect-metadata';
import {EntityManager, EntityRepository, MikroORM, RequestContext,} from '@mikro-orm/core';
import {
EntityManager,
EntityRepository,
MikroORM,
RequestContext,
} from '@mikro-orm/core';
import cors from 'cors';
import express from 'express';
import figlet from 'figlet';
import fs from 'fs';
import path from 'path';
import supertokens from 'supertokens-node';
import swaggerJsdoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express';
import * as Undici from 'undici';
import figlet from 'figlet';
import {getWebsiteDomain, SuperTokensConfig} from './config/supertokens';
import Client from './graphql/client';
import {authMiddleware} from './middleware/auth';
import {ApolloApiKey} from './models/apolloApiKey';
import {Seed} from './models/seed';
import {SeedGroup} from './models/seedGroup';
import apolloApiKeysRoutes from './routes/apolloApiKey';
import avatarRoutes from './routes/avatar';
import authRoutes from './routes/auth';
import avatarRoutes from './routes/avatar';
import graphqlRoutes from './routes/graphql';
import graphsRoutes from './routes/graphs';
import proposalsRoutes from './routes/proposals';
import seedGroupsRoutes from './routes/seedGroups';
import seedsRoutes from './routes/seeds';
import {logger} from './utilities/logger';
import fs from 'fs';

const isTypescript = __filename.endsWith('.ts');
const ProxyAgent = Undici.ProxyAgent;
Expand Down Expand Up @@ -80,7 +85,7 @@ const initializeApp = async () => {
const mikroOrmConfig = {
...(await import(
`./mikro-orm.${process.env.MIKRO_ORM_DRIVER || 'sqlite'}${isTypescript ? '.ts' : '.js'}`
).then((module) => module.default)),
).then((module) => module.default)),
};

DI.orm = await MikroORM.init(mikroOrmConfig);
Expand Down Expand Up @@ -117,16 +122,19 @@ const initializeApp = async () => {
cors({
origin: (origin, callback) => {
const allowedOrigins = [getWebsiteDomain()];
const regex = /^(https:\/\/[a-zA-Z0-9-]+\.narrative\.tech|https?:\/\/localhost(:\d+)?)$/;
if (!origin || allowedOrigins.includes(origin) || regex.test(origin)) callback(null, true);
const regex =
/^(https:\/\/[a-zA-Z0-9-]+\.narrative\.tech|https?:\/\/localhost(:\d+)?|https:\/\/[a-zA-Z0-9-]+\.xspecs\.io)$/;

if (!origin || allowedOrigins.includes(origin) || regex.test(origin))
callback(null, true);
else callback(new Error('Not allowed by CORS'));
},
allowedHeaders: [
'content-type',
...supertokens.getAllCORSHeaders(),
'seed-group',
],
methods: ['GET', 'PUT', 'POST', 'DELETE'],
methods: ['GET', 'PUT', 'POST', 'DELETE', 'PATCH'],
credentials: true,
})
);
Expand Down
126 changes: 100 additions & 26 deletions frontend/src/components/ui/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {Seed} from '@/models/Seed';
import {ApolloSandbox} from '@apollo/sandbox/react';
import {HandleRequest} from '@apollo/sandbox/src/helpers/postMessageRelayHelpers';
import {zodResolver} from '@hookform/resolvers/zod';
import {ChevronsUpDown, LogOut, Plus, Settings, Trash} from 'lucide-react';
import React, {useCallback, useEffect, useState} from 'react';
import {ChevronsUpDown, Plus, Settings, Trash} from 'lucide-react';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {useForm} from 'react-hook-form';
import {useNavigate} from 'react-router';
import {z} from 'zod';
Expand All @@ -22,7 +22,6 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from './alert-dialog';
import {Avatar, AvatarFallback, AvatarImage} from './avatar';
import {Button} from './button';
import {
Card,
Expand All @@ -48,12 +47,6 @@ import {
DialogHeader,
DialogTitle,
} from './dialog';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from './dropdown-menu';
import {
Form,
FormControl,
Expand Down Expand Up @@ -118,6 +111,9 @@ const Home = () => {
const [selectedTab, setSelectedTab] = useState('sandbox');
const [selectedVariant, setSelectedVariant] = useState(null);
const [variants, setVariants] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const matchArgumentsRef = useRef<HTMLPreElement>(null);
const responseRef = useRef<HTMLPreElement>(null);

const serverBaseUrl = getApiBaseUrl();

Expand Down Expand Up @@ -488,6 +484,69 @@ const Home = () => {
setIsDeleteDialogOpen(true);
};

const handleCancel = () => {
setIsEditing(false);
if (matchArgumentsRef.current) {
matchArgumentsRef.current.textContent = JSON.stringify(
seedToView.operationMatchArguments,
null,
2
);
}
if (responseRef.current) {
responseRef.current.textContent = JSON.stringify(
seedToView.seedResponse,
null,
2
);
}
};

const handleSave = async () => {
try {
const updatedMatchArguments =
matchArgumentsRef.current?.textContent || '';
const updatedResponse = responseRef.current?.textContent || '';

const payload = {
id: seedToView.id,
operationName: seedToView.operationName,
seedResponse: JSON.parse(updatedResponse),
operationMatchArguments: JSON.parse(updatedMatchArguments),
seedGroupId: selectedSeedGroup.id,
graphId: seedToView.graphId,
variantName: seedToView.variantName,
oldOperationMatchArguments: seedToView.operationMatchArguments,
};

console.log('server base url: ', serverBaseUrl);
const response = await fetch(`${serverBaseUrl}/api/seeds`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});

if (!response.ok) {
throw new Error('Failed to update seed data');
}
setIsEditing(false);
toast({
title: 'Seed Updated Successfully',
description: 'Your changes have been saved.',
});
} catch (error) {
console.log('Error updating seed:', error);
toast({
title: 'Error Updating Seed',
description:
'An error occurred while saving your changes. Please try again.',
variant: 'destructive',
});
}
};

return (
<Tabs value={selectedTab} onValueChange={setSelectedTab} className="w-full">
<Toaster />
Expand Down Expand Up @@ -892,13 +951,6 @@ const Home = () => {
)}
/>
<div className="flex space-x-2">
<Button
id="cancel-seed-button"
type="button"
variant="secondary"
>
Discard
</Button>
<Button id="save-seed-button" type="submit">
Save seed
</Button>
Expand All @@ -917,25 +969,47 @@ const Home = () => {
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex items-center mb-2">
<span>{`Operation name: ${seedToView?.operationName}`}</span>
<div className="flex items-center justify-between mb-2">
<span>{`Operation name: ${seedToView.operationName}`}</span>
{!isEditing ? (
<Button onClick={() => setIsEditing(true)}>
Edit seed
</Button>
) : (
<div className="flex space-x-2">
<Button
id="discard-changes-button"
type="button"
variant="secondary"
onClick={handleCancel}
>
Discard Changes
</Button>
<Button
id="save-changes-button"
onClick={handleSave}
>
Save Changes
</Button>
</div>
)}
</div>
<div>
<h3 className="font-semibold">Matching Arguments</h3>
<pre
// ref={matchArgumentsRef}
// contentEditable={isEditing}
ref={matchArgumentsRef}
contentEditable={isEditing}
suppressContentEditableWarning={true}
className={`bg-gray-100 p-4 rounded overflow-auto focus:border-primary focus:outline-none ${
false
isEditing
? 'border-[1px] border-[hsl(var(--primary))]'
: 'border-[1px] border-transparent'
}`}
style={{minHeight: '100px'}}
>
<code className="text-sm">
{JSON.stringify(
seedToView?.operationMatchArguments,
seedToView.operationMatchArguments,
null,
2
)}
Expand All @@ -945,18 +1019,18 @@ const Home = () => {
<div>
<h3 className="font-semibold">Response</h3>
<pre
// ref={responseRef}
// contentEditable={isEditing}
ref={responseRef}
contentEditable={isEditing}
suppressContentEditableWarning={true}
className={`bg-gray-100 p-4 rounded overflow-auto focus:border-primary focus:outline-none ${
false
isEditing
? 'border-[1px] border-[hsl(var(--primary))]'
: 'border-[1px] border-transparent'
}`}
style={{minHeight: '100px'}}
>
<code className="text-sm">
{JSON.stringify(seedToView?.seedResponse, null, 2)}
{JSON.stringify(seedToView.seedResponse, null, 2)}
</code>
</pre>
</div>
Expand Down

0 comments on commit 4f21786

Please sign in to comment.