From b5aa0e79ab93df05997c223b117d0377400dd0c6 Mon Sep 17 00:00:00 2001 From: Michal Kawka Date: Tue, 26 Nov 2024 00:03:04 +0100 Subject: [PATCH 1/3] enable seed editing --- backend/src/server.ts | 12 +-- frontend/src/components/ui/home.tsx | 126 ++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 32 deletions(-) diff --git a/backend/src/server.ts b/backend/src/server.ts index f47dc8b..a35322e 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -8,28 +8,28 @@ import { } 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 {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; @@ -120,13 +120,13 @@ const initializeApp = async () => { app.use(express.urlencoded({limit: '50mb', extended: true})); app.use( cors({ - origin: [getWebsiteDomain()], + // origin: [getWebsiteDomain()], allowedHeaders: [ 'content-type', ...supertokens.getAllCORSHeaders(), 'seed-group', ], - methods: ['GET', 'PUT', 'POST', 'DELETE'], + methods: ['GET', 'PUT', 'POST', 'DELETE', 'PATCH'], credentials: true, }) ); diff --git a/frontend/src/components/ui/home.tsx b/frontend/src/components/ui/home.tsx index a08237c..c7d2d96 100644 --- a/frontend/src/components/ui/home.tsx +++ b/frontend/src/components/ui/home.tsx @@ -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'; @@ -22,7 +22,6 @@ import { AlertDialogHeader, AlertDialogTitle, } from './alert-dialog'; -import {Avatar, AvatarFallback, AvatarImage} from './avatar'; import {Button} from './button'; import { Card, @@ -48,12 +47,6 @@ import { DialogHeader, DialogTitle, } from './dialog'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from './dropdown-menu'; import { Form, FormControl, @@ -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(null); + const responseRef = useRef(null); const serverBaseUrl = getApiBaseUrl(); @@ -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 ( @@ -892,13 +951,6 @@ const Home = () => { )} />
- @@ -917,17 +969,39 @@ const Home = () => {
-
- {`Operation name: ${seedToView?.operationName}`} +
+ {`Operation name: ${seedToView.operationName}`} + {!isEditing ? ( + + ) : ( +
+ + +
+ )}

Matching Arguments

 {
                         >
                           
                             {JSON.stringify(
-                              seedToView?.operationMatchArguments,
+                              seedToView.operationMatchArguments,
                               null,
                               2
                             )}
@@ -945,18 +1019,18 @@ const Home = () => {
                       

Response

                           
-                            {JSON.stringify(seedToView?.seedResponse, null, 2)}
+                            {JSON.stringify(seedToView.seedResponse, null, 2)}
                           
                         
From ac508bb9af63746ab2f88135092f07677b6e90d9 Mon Sep 17 00:00:00 2001 From: Michal Kawka Date: Fri, 29 Nov 2024 20:36:56 +0100 Subject: [PATCH 2/3] enable xspecs cors --- backend/src/server.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/backend/src/server.ts b/backend/src/server.ts index 871081d..78db70a 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -1,14 +1,20 @@ 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'; @@ -16,15 +22,14 @@ 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; @@ -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); @@ -117,8 +122,11 @@ 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: [ @@ -126,7 +134,7 @@ const initializeApp = async () => { ...supertokens.getAllCORSHeaders(), 'seed-group', ], - methods: ['GET', 'PUT', 'POST', 'DELETE'], + methods: ['GET', 'PUT', 'POST', 'DELETE', 'PATCH'], credentials: true, }) ); From 5e2c3cd3e2ddc512624cd8c0f210cb7531f6ec4b Mon Sep 17 00:00:00 2001 From: Michal Kawka Date: Fri, 29 Nov 2024 20:37:40 +0100 Subject: [PATCH 3/3] enable xspecs cors --- .env.example | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.env.example b/.env.example index 55891cb..3c40bc1 100644 --- a/.env.example +++ b/.env.example @@ -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 \ No newline at end of file