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

Browser File IO - add Apollo Client and relate-scripts component in sidebar #1201

Closed
wants to merge 3 commits into from
Closed
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
1,474 changes: 1,310 additions & 164 deletions LICENSES.txt

Large diffs are not rendered by default.

623 changes: 383 additions & 240 deletions NOTICE.txt

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion build_scripts/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ module.exports = {
host: '0.0.0.0',
port: 8080,
disableHostCheck: true,
hot: !helpers.isProduction
hot: !helpers.isProduction,
proxy: {
Copy link
Author

Choose a reason for hiding this comment

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

proxy for now until we use params passed from Desktop and a potential CORS issue that was being experienced

context: ['/graphql', '/files'],
target: 'http://localhost:3000'
}
}
}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@
"@testing-library/jest-dom": "^5.3.0",
"@testing-library/react": "^9.0.1",
"@testing-library/react-hooks": "^2.0.1",
"@types/apollo-upload-client": "^14.1.0",
"@types/jest": "^24.9.0",
"@types/lodash-es": "^4.17.3",
"@types/react": "^16.9.23",
"@types/react-redux": "^7.1.9",
"@types/styled-components": "^5.1.1",
Expand Down Expand Up @@ -140,12 +142,14 @@
"xml2js": "^0.4.19"
},
"dependencies": {
"@apollo/client": "^3.2.0",
"@literal-jsx/parser": "^0.1.7",
"@mdx-js/runtime": "^1.6.1",
"@neo4j/browser-lambda-parser": "1.0.5",
"@relate-by-ui/css": "1.0.5",
"@relate-by-ui/relatable": "1.0.1",
"@relate-by-ui/saved-scripts": "^1.0.4",
"apollo-upload-client": "^14.1.2",
"ascii-data-table": "^2.1.1",
"canvg": "^1.5.3",
"codemirror": "^5.29.0",
Expand All @@ -156,6 +160,7 @@
"deepmerge": "^2.1.1",
"file-saver": "^1.3.8",
"firebase": "^7.13.1",
"graphql": "^15.3.0",
"isomorphic-fetch": "^2.2.1",
"jsonic": "^0.3.0",
"jszip": "^3.2.2",
Expand All @@ -165,7 +170,7 @@
"react": "^16.9.0",
"react-dnd": "9.3.2",
"react-dnd-html5-backend": "9.3.2",
"react-dom": "^16.8.1",
"react-dom": "^16.9.0",
"react-redux": "^5.0.7",
"react-spring": "^8.0.27",
"react-suber": "1.0.4",
Expand Down
22 changes: 21 additions & 1 deletion src/browser/AppInit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { BusProvider } from 'react-suber'
import App from './modules/App/App'
import reducers from 'shared/rootReducer'
import epics from 'shared/rootEpic'
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'
import { createUploadLink } from 'apollo-upload-client'

import { createReduxMiddleware, getAll, applyKeys } from 'services/localstorage'
import { APP_START } from 'shared/modules/app/appDuck'
Expand Down Expand Up @@ -89,13 +91,31 @@ const url = window.location.href
// Signal app upstart (for epics)
store.dispatch({ type: APP_START, url, env })

// @todo: will clean this up in later work
// Apollo Client (https://medium.com/@enespalaz/file-upload-with-graphql-9a4927775ef7)
const apolloCache = new InMemoryCache()

const uploadLink = createUploadLink({
uri: '/graphql',
headers: {
'keep-alive': 'true'
}
})

const client = new ApolloClient({
cache: apolloCache,
link: uploadLink
})

const AppInit = () => {
return (
<Provider store={store}>
<BusProvider bus={bus}>
<>
<GlobalStyle />
<App />
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</>
</BusProvider>
</Provider>
Expand Down
2 changes: 2 additions & 0 deletions src/browser/modules/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import DocumentsDrawer from './Documents'
import AboutDrawer from './About'
import SettingsDrawer from './Settings'
import Favorites from './favorites'
import RelateScripts from './relate-scripts'
import StaticScripts from './static-scripts'
import TabNavigation from 'browser-components/TabNavigation/Navigation'
import { DrawerHeader } from 'browser-components/drawer'
Expand Down Expand Up @@ -89,6 +90,7 @@ const Sidebar = ({
<>
<DrawerHeader>Favorites</DrawerHeader>
<Favorites />
<RelateScripts />
{showStaticScripts && <StaticScripts />}
</>
)
Expand Down
3 changes: 2 additions & 1 deletion src/browser/modules/Sidebar/favorites.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ const mapFavoritesStateToProps = state => {
return {
scriptsNamespace: SLASH,
scripts,
folders
folders,
title: 'Local Cache Scripts'
}
}
const mapFavoritesDispatchToProps = (dispatch, ownProps) => ({
Expand Down
173 changes: 173 additions & 0 deletions src/browser/modules/Sidebar/relate-scripts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Copyright (c) 2002-2020 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.com]
* This file is part of Neo4j.
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import { useEffect, useState } from 'react'
import { withBus } from 'react-suber'
import { connect } from 'react-redux'
import MyScripts from '@relate-by-ui/saved-scripts'
import { useQuery, gql, useMutation } from '@apollo/client'
import path from 'path'

import * as editor from 'shared/modules/editor/editorDuck'
import { executeCommand } from 'shared/modules/commands/commandsDuck'
import { SLASH } from 'shared/services/export-favorites'
import {
getProjectFilesQueryVars,
removeProjectFileMutationVars,
mapRelateFavorites,
ProjectFile,
Favorite
} from './relate-scripts.utils'

const GET_PROJECT_FILES = gql`
query GetProject($projectId: String!, $filterValue: String!) {
getProject(name: $projectId) {
files(
filters: [{ field: "extension", type: EQUALS, value: $filterValue }]
) {
name
directory
extension
downloadToken
}
}
}
`
const DELETE_PROJECT_FILE = gql`
mutation RemoveFile($projectId: String!, $filePath: String!) {
removeProjectFile(name: $projectId, filePath: $filePath) {
name
directory
}
}
`

interface ProjectFilesResult {
getProject: { files: ProjectFile[] }
}

interface ProjectVariables {
projectId: string
}

function RelateScripts(props: any): JSX.Element {
// @todo: handling loading and error?? Pass to MyScripts??
const { data, refetch } = useQuery<ProjectFilesResult, ProjectVariables>(
GET_PROJECT_FILES,
{
variables: getProjectFilesQueryVars
}
)
const [removeFavorite] = useMutation(DELETE_PROJECT_FILE)

const [scripts, setScripts] = useState<Favorite[]>([])

useEffect(() => {
let isStillMounted = true
if (data) {
const getRelateFilePromises = data.getProject.files.map(
mapRelateFavorites
)
Promise.all(getRelateFilePromises).then((files: Favorite[]) => {
if (isStillMounted) {
setScripts(files)
}
})
}
return () => {
isStillMounted = false
}
}, [data])

useEffect(() => {
// refetch only once sidebar is closed once
// i.e. 'data' is already present
if (data && refetch) {
refetch()
}
}, [])

return MyScripts({
...props,
scripts,
isRelateScripts: true,
onRemoveScript: favorite => {
const directory = favorite.path.substring(1) // @todo: adding in SLASH to path
const filePath = path.join(directory, favorite.name)
return removeFavorite({
variables: removeProjectFileMutationVars(filePath),
update: (cache, { data: { removeProjectFile } }) => {
const data = cache.readQuery<ProjectFilesResult>({
query: GET_PROJECT_FILES,
variables: getProjectFilesQueryVars
})
const filteredProjectFiles = data?.getProject.files.filter(
file =>
file.directory !== removeProjectFile.directory ||
file.name !== removeProjectFile.name
)
cache.writeQuery({
query: GET_PROJECT_FILES,
data: {
getProject: {
files: filteredProjectFiles
}
},
variables: getProjectFilesQueryVars
})
}
})
}
})
}

const mapFavoritesStateToProps = () => {
return {
scriptsNamespace: SLASH,
title: 'Project Scripts'
}
}

const mapFavoritesDispatchToProps = (
dispatch: any,
ownProps: { bus: { send: any } }
) => ({
onSelectScript: (favorite: any) =>
ownProps.bus.send(
editor.EDIT_CONTENT,
editor.editContent(favorite.id, favorite.contents)
),
onExecScript: (favorite: any) => dispatch(executeCommand(favorite.contents)),
onExportScripts: Function.prototype,
onUpdateFolder: Function.prototype,
onRemoveFolder: Function.prototype
})

const mergeProps = (stateProps: any, dispatchProps: any) => {
return {
...stateProps,
...dispatchProps
}
}

export default withBus(
connect(
mapFavoritesStateToProps,
mapFavoritesDispatchToProps,
mergeProps
)(RelateScripts)
)
49 changes: 49 additions & 0 deletions src/browser/modules/Sidebar/relate-scripts.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import remote from 'services/remote'
import { SLASH, CYPHER_FILE_EXTENSION } from 'shared/services/export-favorites'
import { pick } from 'lodash-es'
import uuid from 'uuid'

export interface ProjectFile {
downloadToken: string
name: string
directory: string
}

export interface Favorite {
id: string
name: string
path: string
contents: string
}

// @todo: add documentation...

// will be a function once projectid is available
export const getProjectFilesQueryVars = {
projectId: 'project-03688c10-a811-4c0c-85d4-581e88c2183a',
filterValue: CYPHER_FILE_EXTENSION
}

export const removeProjectFileMutationVars = (
filePath: string
): { projectId: string; filePath: string } => ({
...pick(getProjectFilesQueryVars, ['projectId']),
filePath
})

export const mapRelateFavorites = async ({
downloadToken,
name,
directory
}: ProjectFile): Promise<Favorite> => ({
id: uuid.v4(),
name,
path: directory.startsWith('.') ? SLASH : `${SLASH}${directory}`, // @todo: need to look into this
contents: await getProjectCypherFileContents(downloadToken, name)
})

const getProjectCypherFileContents = (token: string, name: string) =>
remote
.request('GET', `/files/${token}/${name}`)
.then(body => body.text())
.catch(e => console.log('++err', e)) // ?
Loading