feat(ui): Initial schema and folder API

This commit is contained in:
Guillaume Chau
2018-03-04 23:16:35 +01:00
parent 1aee235f42
commit 1751ca1ab2
16 changed files with 198 additions and 185 deletions

View File

@@ -1,32 +1,5 @@
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style>

View File

@@ -0,0 +1,3 @@
module.exports = {
CWD_CHANGED: 'cwd_changed'
}

View File

@@ -0,0 +1,11 @@
const channels = require('../channels')
let cwd = process.cwd()
module.exports = {
get: () => cwd,
set: (value, context) => {
cwd = value
context.pubsub.publish(channels.CWD_CHANGED, { cwdChanged: value })
}
}

View File

@@ -0,0 +1,53 @@
const path = require('path')
const fs = require('fs')
const cwd = require('./cwd')
function list (base, context) {
return new Promise((resolve, reject) => {
fs.readdir(base, 'utf8', (err, files) => {
if (err) {
reject(err)
} else {
resolve(files.map(
file => ({
path: path.join(base, file),
name: file
})
).filter(
file => fs.statSync(file.path).isDirectory()
))
}
})
})
}
function generateFolder (file) {
return {
name: path.basename(file),
path: file
}
}
function getCurrent (args, context) {
const base = cwd.get()
return generateFolder(base)
}
function open (file, context) {
cwd.set(file, context)
return generateFolder(file)
}
function openParent (file, context) {
const newFile = path.dirname(file)
cwd.set(newFile, context)
return generateFolder(newFile)
}
module.exports = {
getCurrent,
list,
open,
openParent
}

View File

@@ -1,11 +1,9 @@
const { db } = require('./utils/db')
const { processUpload } = require('./utils/upload')
// Context passed to all resolvers (third argument)
// eslint-disable-next-line no-unused-vars
module.exports = req => {
return {
db,
processUpload
db
}
}

View File

@@ -1,56 +1,25 @@
const shortid = require('shortid')
const channels = require('./channels')
const cwd = require('./connectors/cwd')
const folders = require('./connectors/folders')
module.exports = {
Counter: {
countStr: counter => `Current count: ${counter.count}`
Folder: {
children: (folder, args, context) => folders.list(folder.path, context)
},
Query: {
hello: (root, { name }) => `Hello ${name || 'World'}!`,
messages: (root, args, { db }) => db.get('messages').value(),
uploads: (root, args, { db }) => db.get('uploads').value()
cwd: () => cwd.get(),
folderCurrent: (root, args, context) => folders.getCurrent(args, context)
},
Mutation: {
messageAdd: (root, { input }, { pubsub, db }) => {
const message = {
id: shortid.generate(),
text: input.text
}
db
.get('messages')
.push(message)
.last()
.write()
pubsub.publish('messages', { messageAdded: message })
return message
},
singleUpload: (root, { file }, { processUpload }) => processUpload(file),
multipleUpload: (root, { files }, { processUpload }) => Promise.all(files.map(processUpload))
folderOpen: (root, { path }, context) => folders.open(path, context),
folderOpenParent: (root, args, context) => folders.openParent(cwd.get(), context)
},
Subscription: {
counter: {
subscribe: (parent, args, { pubsub }) => {
const channel = Math.random().toString(36).substring(2, 15) // random channel name
let count = 0
setInterval(() => pubsub.publish(
channel,
{
// eslint-disable-next-line no-plusplus
counter: { count: count++ }
}
), 2000)
return pubsub.asyncIterator(channel)
}
},
messageAdded: {
subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator('messages')
cwdChanged: {
subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator(channels.CWD_CHANGED)
}
}
}

View File

@@ -1,54 +1,134 @@
module.exports = `
# It will increment!
type Counter {
# Number of increments
count: Int!
# Full message for testing
countStr: String
}
# A text message send by users
type Message {
type ConsoleLog {
id: ID!
# Message content
text: String!
message: String!
label: String
tag: String
type: ConsoleLogType!
}
# Input from user to create a message
input MessageInput {
# Message content
text: String!
enum ConsoleLogType {
log
warn
error
info
done
}
scalar Upload
type File {
id: ID!
type Folder {
name: String!
path: String!
filename: String!
mimetype: String!
encoding: String!
children: [Folder]
}
type Project {
id: ID!
name: String!
path: String!
favorite: Int
features: [Feature]
plugins: [Plugin]
}
input ProjectCreateInput {
path: String!
}
input ProjectImportInput {
path: String!
}
type Version {
current: String!
latest: String
}
type GitHubStats {
stars: Int
}
type Plugin {
id: ID!
version: Version!
official: Boolean
installed: Boolean
website: String
description: String
githubStats: GitHubStats
prompts: [Prompt]
}
input PluginSearchInput {
terms: String!
}
type Feature {
id: ID!
label: String!
description: String!
link: String!
enabled: Boolean!
}
enum PromptType {
input
confirm
list
rawlist
expand
checkbox
password
editor
}
type PromptChoice {
value: String!
}
type PromptError {
message: String!
link: String
}
type Prompt {
id: ID!
enabled: Boolean!
type: PromptType!
name: String
message: String
description: String
link: String
choices: [PromptChoice]
currentValue: String
error: PromptError
}
input PromptInput {
id: ID!
value: String!
}
type Query {
# Test query with a parameter
hello(name: String): String!
# List of messages sent by users
messages: [Message]
uploads: [File]
cwd: String!
folderCurrent: Folder
projects: [Project]
projectCurrent: Project
pluginSearch (input: PluginSearchInput!): [Plugin]
}
type Mutation {
# Add a message and publish it on 'messages' subscription channel
messageAdd (input: MessageInput!): Message!
singleUpload (file: Upload!): File!
multipleUpload (files: [Upload!]!): [File!]!
folderOpen (path: String!): Folder
folderOpenParent: Folder
projectCreate (input: ProjectCreateInput!): Project!
projectImport (input: ProjectImportInput!): Project!
projectSetFavorite (id: ID!, favorite: Int!): Project!
pluginAdd (id: ID!): Plugin
promptAnswer (input: PromptInput!): Prompt
}
type Subscription {
# This will update every 2 seconds
counter: Counter!
# When a new message is added
messageAdded: Message!
consoleLogAdded: ConsoleLog!
cwdChanged: String!
}
`

View File

@@ -9,8 +9,7 @@ const db = new Lowdb(new FileSync(resolve(__dirname, '../../../live/db.json')))
// Seed an empty DB
db.defaults({
messages: [],
uploads: []
projects: []
}).write()
module.exports = {

View File

@@ -1,38 +0,0 @@
const { createWriteStream } = require('fs')
const mkdirp = require('mkdirp')
const shortid = require('shortid')
const { db } = require('./db')
const uploadDir = require('path').resolve(__dirname, '../../../live/uploads')
// Ensure upload directory exists
mkdirp.sync(uploadDir)
const storeUpload = async ({ stream, filename }) => {
const id = shortid.generate()
const path = `${uploadDir}/${id}-${filename}`
return new Promise((resolve, reject) =>
stream
.pipe(createWriteStream(path))
.on('finish', () => resolve({ id, path }))
.on('error', reject)
)
}
const recordFile = file =>
db
.get('uploads')
.push(file)
.last()
.write()
const processUpload = async upload => {
const { stream, filename, mimetype, encoding } = await upload
const { id, path } = await storeUpload({ stream, filename })
return recordFile({ id, filename, mimetype, encoding, path })
}
module.exports = {
processUpload
}

View File

@@ -1,3 +0,0 @@
query HelloWorld ($name: String) {
hello (name: $name)
}

View File

@@ -1,7 +0,0 @@
#import "./MessageFragment.gql"
mutation messageAdd ($input: MessageInput!) {
messageAdd (input: $input) {
...Message
}
}

View File

@@ -1,7 +0,0 @@
#import "./MessageFragment.gql"
subscription messageAdded {
messageAdded {
...Message
}
}

View File

@@ -1,4 +0,0 @@
fragment Message on Message {
id
text
}

View File

@@ -1,7 +0,0 @@
#import "./MessageFragment.gql"
query messages {
messages {
...Message
}
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View File

@@ -1,18 +1,11 @@
<template>
<div class="home">
<img src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/ApolloExample.vue'
export default {
name: 'home',
components: {
HelloWorld
}
name: 'home'
}
</script>