Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript Conversion #111

Merged
merged 13 commits into from
Jan 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"herrmannplatz.npm-dependency-links"
]
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Fragment, useState, useLayoutEffect, useEffect } from 'react';
import { Fragment, useState, useLayoutEffect, useEffect, ReactNode } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { Upload, X, File } from 'tabler-icons-react';
import { Upload, X, File, IconProps } from 'tabler-icons-react';
import { Toggle } from './Toggle';

import Parameter from './Parameter';
Expand All @@ -15,6 +15,7 @@ import { useAuth } from '../firebase/fbAuth';

import { firebaseApp } from "../firebase/firebaseClient";
import { getDoc, getFirestore, doc } from "firebase/firestore";
import Router from 'next/router';


export const FormStates = {
Expand Down Expand Up @@ -205,11 +206,11 @@ const ConfirmationStep = ({ form, ...props }) => {
</div>
);
};

const dropzoneKids = (status) => {
if (status.accepted) {
return <UploadIcon className={'bg-green-500'} status={status} />;
}
return (
return (status.accepted) ?
<UploadIcon className={'bg-green-500'} status={status} />
:
<div className={`flex flex-col justify-center items-center space-y-6`}>
<UploadIcon status={status} />
<div>
Expand All @@ -221,9 +222,13 @@ const dropzoneKids = (status) => {
</Text>
</div>
</div>
);
};
const UploadIcon = ({ status }) => {

interface UploadIconProps extends IconProps {
status
}

const UploadIcon: React.FC<UploadIconProps> = ({ status }) => {
if (status.accepted) {
return <Upload size={80} />;
} else if (status.rejected) {
Expand All @@ -235,28 +240,30 @@ const UploadIcon = ({ status }) => {
const DispatchStep = ({ id, form, ...props }) => {
const { userId, authService } = useAuth();

const onDropFile = async (file) => {
console.log("Submitting Experiment!!!")
submitExperiment(form.values, userId).then(async (expId) =>{
console.log(`Uploading file for ${expId}`)
const res = await uploadExec(expId, file[0]);
if (res) {
console.log("Handing experiment " + expId + " to the backend")
const response = await fetch(`/api/experiments/${expId}`,{
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json'}),
credentials: 'same-origin',
body: JSON.stringify({id: expId})
})
console.log("Response from backend received", response)
} else {
alert("Failed to upload experiment file to the backend server, is it running?")
throw new Error('Upload failed')
}
}).catch( error => console.log("Error uploading experiment: ", error))
}

return (
<Dropzone
onDrop={async (file) => {
console.log("Submitting Experiment!!!")
submitExperiment(form.values, userId).then( (expId) =>{
console.log(expId)

console.log(`Uploading file for ${expId}`)
const res = uploadExec(expId, file[0]);
if (res == null) {
throw new Error('Upload failed')
} else{
console.log("Handing experiment " + expId + " to the backend")
fetch(`/api/experiments/${expId}`,{
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json'}),
credentials: 'same-origin',
body: JSON.stringify({id: expId})
})
}
}).catch( error => console.log(error))
}}
onDrop={onDropFile}
onReject={(file) => console.log('NOPE, file rejected', file)}
maxSize={3 * 1024 ** 2}
className='flex-1 flex flex-col justify-center m-4 items-center'
Expand All @@ -265,15 +272,15 @@ const DispatchStep = ({ id, form, ...props }) => {
'application/java-archive':['.jar']
}}
>
{(status) => dropzoneKids(status)}
<>{ (status) => dropzoneKids(status) }</>
</Dropzone>
);
};

const NewExp = ({ formState, setFormState, copyID, setCopyId, ...rest }) => {
const form = useForm({
initialValues: {
parameters: formList([]),
parameters: formList([] as any[]), // TODO type for parameters will remove the need for `any` here
name: '',
description: '',
fileOutput: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ const Parameter = ({ form, type, index, ...rest }) => {
<Component form={form} type={type} index={index} {...rest} />
<ActionIcon
color='red'
variant='hover'
onClick={() => form.removeListItem('parameters', index)}
className='ml-2'
>
<Trash size={12} />
<Trash/>
</ActionIcon>
</div>
);
Expand Down
File renamed without changes.
67 changes: 34 additions & 33 deletions apps/frontend/firebase/db.js → apps/frontend/firebase/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,54 @@ import { getDownloadURL, getStorage, ref, uploadBytes } from "firebase/storage";
// Initialize Cloud Firestore and get a reference to the service
const db = getFirestore(firebaseApp);
const storage = getStorage(firebaseApp);
const experiments = collection(db,"Experiments")
const experiments = collection(db, "Experiments")

export const submitExperiment = async (values, userId) => {
const newExperiment = doc(experiments)
console.log("Experiment submitted. Values:", values);
setDoc(newExperiment,{
setDoc(newExperiment, {
creator: userId,
name: values.name,
description: values.description,
verbose: values.verbose,
workers: values.nWorkers,
expId: newExperiment.id,
fileOutput: values.fileOutput,
resultOutput: values.resultOutput,
finished: false,
created: Date.now(),
params: JSON.stringify({
params: values.parameters,
})
name: values.name,
description: values.description,
verbose: values.verbose,
workers: values.nWorkers,
expId: newExperiment.id,
fileOutput: values.fileOutput,
resultOutput: values.resultOutput,
finished: false,
created: Date.now(),
params: JSON.stringify({
params: values.parameters,
})
})
console.log("Created Experiment: " + newExperiment.id)
return newExperiment.id
};


export const uploadExec = async (id, file) => {
const fileRef = ref(storage, "experiment"+id)
uploadBytes(fileRef, file).then((snapshot) => {
const experimentRef = doc(db,"Experiments",id)
updateDoc(experimentRef,{
file: "experiment"+id
const fileRef = ref(storage, "experiment" + id)
return await uploadBytes(fileRef, file).then((snapshot) => {
const experimentRef = doc(db, "Experiments", id)
updateDoc(experimentRef, {
file: "experiment" + id
}).then(() => {
console.log("Uploaded file for experiment " + id)
return true
}).catch(error => console.log(error))
}).catch(error => console.log("Upload doc error: ", error))
return true
}).catch(error =>{
console.log(error)
}).catch(error => {
console.log("Upload bytes error: ", error)
return false
} )
})
};

export const getDocById = (id) => {
getDoc(doc(db, "Experiments", id)).then(docSnap => {
if (docSnap.exists()) {
return docSnap.data();
} else {
console.log("No such document!");
console.log("No such document!");
}
})

Expand All @@ -62,43 +62,44 @@ export const getDocById = (id) => {
export const downloadExp = (event) => {
const id = event.target.getAttribute('data-id')
console.log(`Downloading results for ${id}`)
const fileRef = ref(storage,`results/result${id}.csv`)
const fileRef = ref(storage, `results/result${id}.csv`)
getDownloadURL(fileRef).then(url => {
const anchor = document.createElement('a')
anchor.href = url
anchor.download = `result${id}.csv`
document.body.appendChild(anchor)
anchor.click()
document.body.removeChild(anchor)
}).catch(error => console.log(error))
}).catch(error => console.log("Get download url for exp error: ", error))
}

export const downloadExpZip = (event) => {
const id = event.target.getAttribute('data-id')
console.log(`Downloading results for ${id}`)
const fileRef = ref(storage,`results/result${id}.zip`)
const fileRef = ref(storage, `results/result${id}.zip`)
getDownloadURL(fileRef).then(url => {
const anchor = document.createElement('a')
anchor.href = url
anchor.download = `result${id}.csv`
document.body.appendChild(anchor)
anchor.click()
document.body.removeChild(anchor)
}).catch(error => console.log(error))
}).catch(error => console.log("Upload download url for zip error: ", error))
}

export const subscribeToExp = (id, callback) => {
const unsubscribe = onSnapshot(doc(db,"Experiments",id), doc =>{
console.log(`exp ${id} has been updated: `,doc.data())
callback(doc.data())})
const unsubscribe = onSnapshot(doc(db, "Experiments", id), doc => {
console.log(`exp ${id} data updated: `, doc.data())
callback(doc.data())
})
return unsubscribe
}


export const listenToExperiments = (uid, callback) => {
const q = query(experiments, where("creator","==",uid))
const q = query(experiments, where("creator", "==", uid))
const unsubscribe = onSnapshot(q, (snapshot) => {
var result = []
let result: unknown[] = []
snapshot.forEach(doc => result.push(doc.data()))
callback(result)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,45 @@ import React, {
useContext,
createContext,
useDebugValue,
FC
} from 'react';
import { firebaseApp } from './firebaseClient';
import { createUserWithEmailAndPassword, getAuth, onAuthStateChanged, signInWithEmailAndPassword, signOut } from 'firebase/auth'
import { createUserWithEmailAndPassword, getAuth, onAuthStateChanged, signInWithEmailAndPassword, signOut, User } from 'firebase/auth'

const AuthContext = createContext({});
export interface AuthContextType {
user: User | null;
userId: String | null;
authService; // TODO find a way to make a type for this, ideally without duplicating all the function names
}

const AuthContext = createContext<AuthContextType>({
user: null,
userId: null,
authService: null
});

export const useAuth = () => useContext(AuthContext);

export const AuthProvider = ({ children }) => {
const [auth, _] = useState(getAuth(firebaseApp));
interface AuthProviderProps {
children: React.ReactNode;
}

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [auth] = useState(getAuth(firebaseApp));

const [user, setUser] = useState();
useDebugValue('Current User:', user);
const [loading, setLoading] = useState(false); // TODO is their loading blocker still a relevant concept for firebase?
const [user, setUser] = useState<User | null>(null);
useDebugValue(`Current User: ${user}`);
const [loading, setLoading] = useState(true);

// TODO this duplicates the setting functionality in signInWithEmailAndPassword, but not sure which is best practice now
useEffect(() => onAuthStateChanged(auth, (newUser) => {
console.log("OnAuthStateChanged fired", newUser);
setUser(newUser);
setLoading(false);
if (newUser) {
console.log("User is signed in");
setUser(newUser);
} else {
console.log("No user signed in");
}
}), [auth]);

const authService = {
Expand All @@ -41,17 +61,17 @@ export const AuthProvider = ({ children }) => {
return user?.photoURL;
}, [user]),

signInWithEmailAndPassword: async (email, password) => {
signInWithEmailAndPassword: async (email: string, password: string) => {
return await signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
console.log("sign in success, UserCred is ", userCredential);
setUser(userCredential.user);
// no need to set state because onAuthStateChanged will pick it up
}).catch((error) => {
console.error('Firebase sign in error', error);
throw error;
});
},
signUpWithEmailAndPassword: async (email, password) => {
signUpWithEmailAndPassword: async (email: string, password: string) => {
return await createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
console.log("sign up success, UserCred is ", userCredential);
Expand All @@ -71,12 +91,13 @@ export const AuthProvider = ({ children }) => {
return (
<AuthContext.Provider value={{
user,
userId: authService?.userId,
userId: authService?.userId || null,
authService }
}>
{loading ? (
<div>
<h1>Loading...</h1>
<h1>Authenticating...</h1>
<p>If you see this text for more than a few seconds, something is wrong.</p>
</div>
) : (
children
Expand Down
5 changes: 5 additions & 0 deletions apps/frontend/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
Loading