mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-02-07 23:48:29 -06:00
feat(ui): Initial schema and folder API
This commit is contained in:
@@ -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>
|
||||
|
||||
3
packages/@vue/cli-ui/src/graphql-api/channels.js
Normal file
3
packages/@vue/cli-ui/src/graphql-api/channels.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
CWD_CHANGED: 'cwd_changed'
|
||||
}
|
||||
11
packages/@vue/cli-ui/src/graphql-api/connectors/cwd.js
Normal file
11
packages/@vue/cli-ui/src/graphql-api/connectors/cwd.js
Normal 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 })
|
||||
}
|
||||
}
|
||||
53
packages/@vue/cli-ui/src/graphql-api/connectors/folders.js
Normal file
53
packages/@vue/cli-ui/src/graphql-api/connectors/folders.js
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!
|
||||
}
|
||||
`
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
query HelloWorld ($name: String) {
|
||||
hello (name: $name)
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#import "./MessageFragment.gql"
|
||||
|
||||
mutation messageAdd ($input: MessageInput!) {
|
||||
messageAdd (input: $input) {
|
||||
...Message
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#import "./MessageFragment.gql"
|
||||
|
||||
subscription messageAdded {
|
||||
messageAdded {
|
||||
...Message
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
fragment Message on Message {
|
||||
id
|
||||
text
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#import "./MessageFragment.gql"
|
||||
|
||||
query messages {
|
||||
messages {
|
||||
...Message
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user