From 7c753ee518d4a89606a6cfc05ae7b6b97ea575d2 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Wed, 5 Jul 2017 16:41:52 -0300 Subject: [PATCH 01/17] create-plugin --- bin/cli-plugins | 51 ++++++++++++++++++- client/coral-framework/helpers/plugins.js | 5 +- package.json | 1 + scripts/templates/plugin/client/.babelrc | 14 +++++ .../templates/plugin/client/.eslintrc.json | 23 +++++++++ scripts/templates/plugin/client/index.js | 20 ++++++++ .../templates/plugin/client/translations.yml | 15 ++++++ scripts/templates/plugin/index.js | 1 + 8 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 scripts/templates/plugin/client/.babelrc create mode 100644 scripts/templates/plugin/client/.eslintrc.json create mode 100644 scripts/templates/plugin/client/index.js create mode 100644 scripts/templates/plugin/client/translations.yml create mode 100644 scripts/templates/plugin/index.js diff --git a/bin/cli-plugins b/bin/cli-plugins index b1dee381b..6dc127697 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -8,13 +8,14 @@ // https://yarnpkg.com/ const program = require('./commander'); +const inquirer = require('inquirer'); // Make things colorful! require('colors'); const emoji = require('node-emoji'); const dir = process.cwd(); -const fs = require('fs'); +const fs = require('fs-extra'); const path = require('path'); const spawn = require('cross-spawn'); const semver = require('semver'); @@ -272,10 +273,58 @@ async function reconcilePluginDeps({skipLocal, skipRemote, dryRun, upgradeRemote console.log(`✨ Done in ${totalTime}s.`); } +async function createSeedPlugin() { + const pluginsDir = path.join(dir, 'plugins'); + + function pluginNameExists(pluginName) { + const pluginNames = fs.readdirSync(pluginsDir); + return !!pluginNames + .filter((pn) => pn === pluginName).length; + } + + let answers = await inquirer.prompt([ + { + type: 'input', + name: 'pluginName', + message: 'Plugin Name: i.e talk-plugin-permalink', + validate: (input) => { + + if (pluginNameExists(input)) { + return 'Please, choose another name. That name already exists'; + } + + if (input && input.length > 0) { + return true; + } + + return 'Plugin Name is required.'; + } + } + ]); + + // Creating plugin seed + + const seedTemplatePlugin = path.join(dir, 'scripts/templates/plugin'); + const newPluginPath = path.join(pluginsDir, answers.pluginName); + + try { + fs.copySync(seedTemplatePlugin, newPluginPath); + + console.log('Success!'); + } catch (err) { + console.error(err); + } +} + //============================================================================== // Setting up the program command line arguments. //============================================================================== +program + .command('create') + .description('creates a seed plugin') + .action(createSeedPlugin); + program .command('list') .description('') diff --git a/client/coral-framework/helpers/plugins.js b/client/coral-framework/helpers/plugins.js index ab5e3080e..fcd0e6db6 100644 --- a/client/coral-framework/helpers/plugins.js +++ b/client/coral-framework/helpers/plugins.js @@ -15,9 +15,9 @@ function getSlotComponents(slot) { // Filter out components that have been disabled in `plugin_config` return flatten(plugins - + // Filter out components that have been disabled in `plugin_config` - .filter((o) => !pluginConfig || !pluginConfig[o.plugin] || !pluginConfig[o.plugin].disable_components) + .filter((o) => o.module.slots && (!pluginConfig || !pluginConfig[o.plugin] || !pluginConfig[o.plugin].disable_components)) .filter((o) => o.module.slots[slot]) .map((o) => o.module.slots[slot])); @@ -78,6 +78,7 @@ export function getSlotsFragments(slots) { } const components = uniq(flattenDeep(slots.map((slot) => { return plugins + .filter((o) => o.module.slots) .filter((o) => o.module.slots[slot]) .map((o) => o.module.slots[slot]); }))); diff --git a/package.json b/package.json index 382846cef..218381896 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "express": "^4.15.2", "express-session": "^1.15.1", "form-data": "^2.1.2", + "fs-extra": "^3.0.1", "gql-merge": "^0.0.4", "graphql": "^0.9.1", "graphql-errors": "^2.1.0", diff --git a/scripts/templates/plugin/client/.babelrc b/scripts/templates/plugin/client/.babelrc new file mode 100644 index 000000000..60be246eb --- /dev/null +++ b/scripts/templates/plugin/client/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "add-module-exports", + "transform-class-properties", + "transform-decorators-legacy", + "transform-object-assign", + "transform-object-rest-spread", + "transform-async-to-generator", + "transform-react-jsx" + ] +} \ No newline at end of file diff --git a/scripts/templates/plugin/client/.eslintrc.json b/scripts/templates/plugin/client/.eslintrc.json new file mode 100644 index 000000000..9fe56bd14 --- /dev/null +++ b/scripts/templates/plugin/client/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "rules": { + "react/jsx-uses-react": "error", + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] + } +} diff --git a/scripts/templates/plugin/client/index.js b/scripts/templates/plugin/client/index.js new file mode 100644 index 000000000..931cd722c --- /dev/null +++ b/scripts/templates/plugin/client/index.js @@ -0,0 +1,20 @@ + +/** + This is a client index example file and it should look like this: + + ``` + import LoveButton from './components/LoveButton'; + + export default { + slots: { + commentReactions: [LoveButton] + }, + reducer, + translations + }; + ``` + + To read more info on how to build client plugins. Please, go to: https://coralproject.github.io/talk/plugins-client.html + */ + +export default {}; diff --git a/scripts/templates/plugin/client/translations.yml b/scripts/templates/plugin/client/translations.yml new file mode 100644 index 000000000..d8407b801 --- /dev/null +++ b/scripts/templates/plugin/client/translations.yml @@ -0,0 +1,15 @@ +# +# This file is for translations and they should look like this: +# +# +# ``` +# en: +# coral-plugin-respect: +# respect: Respect +# respected: Respected +# es: +# coral-plugin-respect: +# respect: Respetar +# respected: Respetado +# ``` +# diff --git a/scripts/templates/plugin/index.js b/scripts/templates/plugin/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/scripts/templates/plugin/index.js @@ -0,0 +1 @@ +module.exports = {}; From 60608af8b2a98af5f94a66c6b956c420c6532a90 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 6 Jul 2017 11:40:35 -0300 Subject: [PATCH 02/17] Filter out the ones that have slots --- client/coral-framework/helpers/plugins.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/coral-framework/helpers/plugins.js b/client/coral-framework/helpers/plugins.js index fcd0e6db6..2e5934bc4 100644 --- a/client/coral-framework/helpers/plugins.js +++ b/client/coral-framework/helpers/plugins.js @@ -16,7 +16,7 @@ function getSlotComponents(slot) { // Filter out components that have been disabled in `plugin_config` return flatten(plugins - // Filter out components that have been disabled in `plugin_config` + // Filter out components that have slots and have been disabled in `plugin_config` .filter((o) => o.module.slots && (!pluginConfig || !pluginConfig[o.plugin] || !pluginConfig[o.plugin].disable_components)) .filter((o) => o.module.slots[slot]) @@ -78,8 +78,7 @@ export function getSlotsFragments(slots) { } const components = uniq(flattenDeep(slots.map((slot) => { return plugins - .filter((o) => o.module.slots) - .filter((o) => o.module.slots[slot]) + .filter((o) => o.module.slots ? o.module.slots[slot] : false) .map((o) => o.module.slots[slot]); }))); From 99425e89ca2be99a399ce911e41e35cbf8c6de12 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 6 Jul 2017 13:09:43 -0300 Subject: [PATCH 03/17] More questions --- bin/cli-plugins | 35 +++++++++++++++++-- .../templates/plugin-client/client/.babelrc | 14 ++++++++ .../plugin-client/client/.eslintrc.json | 23 ++++++++++++ scripts/templates/plugin-client/index.js | 1 + scripts/templates/plugin-server/index.js | 1 + .../client/components/MyPluginComponent.js | 15 ++++++++ scripts/templates/plugin/client/index.js | 10 ++++-- 7 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 scripts/templates/plugin-client/client/.babelrc create mode 100644 scripts/templates/plugin-client/client/.eslintrc.json create mode 100644 scripts/templates/plugin-client/index.js create mode 100644 scripts/templates/plugin-server/index.js create mode 100644 scripts/templates/plugin/client/components/MyPluginComponent.js diff --git a/bin/cli-plugins b/bin/cli-plugins index 6dc127697..aa2d8f234 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -286,7 +286,7 @@ async function createSeedPlugin() { { type: 'input', name: 'pluginName', - message: 'Plugin Name: i.e talk-plugin-permalink', + message: 'Plugin Name:', validate: (input) => { if (pluginNameExists(input)) { @@ -299,18 +299,47 @@ async function createSeedPlugin() { return 'Plugin Name is required.'; } + }, + { + type: 'confirm', + name: 'server', + message: 'Is this a server-side plugin?' + }, + { + type: 'confirm', + name: 'client', + message: 'Is this a client-side plugin?' + }, + { + type: 'confirm', + name: 'client', + message: 'Should we add it to the plugins.json?' } ]); + //============================================================================== // Creating plugin seed + //============================================================================== const seedTemplatePlugin = path.join(dir, 'scripts/templates/plugin'); const newPluginPath = path.join(pluginsDir, answers.pluginName); try { - fs.copySync(seedTemplatePlugin, newPluginPath); + fs.copySync(seedTemplatePlugin, newPluginPath, { + filter: (p) => { + if (!answers.server) { + return /templates\/plugin\/server/.test(p); + } - console.log('Success!'); + if (!answers.client) { + return /templates\/plugin\/client/.test(p); + } + + return true; + } + }); + + console.log(`✨ Yay! Talk Plugin Seed created! Find your plugin in the /plugins folder`); } catch (err) { console.error(err); } diff --git a/scripts/templates/plugin-client/client/.babelrc b/scripts/templates/plugin-client/client/.babelrc new file mode 100644 index 000000000..60be246eb --- /dev/null +++ b/scripts/templates/plugin-client/client/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "add-module-exports", + "transform-class-properties", + "transform-decorators-legacy", + "transform-object-assign", + "transform-object-rest-spread", + "transform-async-to-generator", + "transform-react-jsx" + ] +} \ No newline at end of file diff --git a/scripts/templates/plugin-client/client/.eslintrc.json b/scripts/templates/plugin-client/client/.eslintrc.json new file mode 100644 index 000000000..9fe56bd14 --- /dev/null +++ b/scripts/templates/plugin-client/client/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "rules": { + "react/jsx-uses-react": "error", + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] + } +} diff --git a/scripts/templates/plugin-client/index.js b/scripts/templates/plugin-client/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/scripts/templates/plugin-client/index.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/scripts/templates/plugin-server/index.js b/scripts/templates/plugin-server/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/scripts/templates/plugin-server/index.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.js b/scripts/templates/plugin/client/components/MyPluginComponent.js new file mode 100644 index 000000000..ff0fe6c3c --- /dev/null +++ b/scripts/templates/plugin/client/components/MyPluginComponent.js @@ -0,0 +1,15 @@ +import React from 'react'; +import {Icon} from 'plugin-api/beta/client/components/ui'; + +class MyPluginComponent extends React.Component { + render() { + return ( +
+ + Plugin Created by Talk CLI +
+ ); + } +} + +export default MyPluginComponent; diff --git a/scripts/templates/plugin/client/index.js b/scripts/templates/plugin/client/index.js index 931cd722c..acd0910be 100644 --- a/scripts/templates/plugin/client/index.js +++ b/scripts/templates/plugin/client/index.js @@ -1,6 +1,6 @@ /** - This is a client index example file and it should look like this: + This is a client index example file and it could look like this: ``` import LoveButton from './components/LoveButton'; @@ -17,4 +17,10 @@ To read more info on how to build client plugins. Please, go to: https://coralproject.github.io/talk/plugins-client.html */ -export default {}; +import MyPluginComponent from './components/MyPluginComponent'; + +export default { + slots: { + stream: [MyPluginComponent] + } +}; From a8e5ad451d8e50391a089312dcc63738677bc2b8 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 6 Jul 2017 15:08:39 -0300 Subject: [PATCH 04/17] Plugins CLI :D --- bin/cli-plugins | 78 +++++++++++++++++++++++++++++++++++++------------ package.json | 1 + yarn.lock | 22 ++++++++++++++ 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/bin/cli-plugins b/bin/cli-plugins index aa2d8f234..e5c3dd657 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -20,6 +20,7 @@ const path = require('path'); const spawn = require('cross-spawn'); const semver = require('semver'); const resolve = require('resolve'); +const stringify = require("json-stringify-pretty-compact"); const {plugins, itteratePlugins, isInternal} = require('../plugins'); function existsInNodeModules(name) { @@ -312,7 +313,7 @@ async function createSeedPlugin() { }, { type: 'confirm', - name: 'client', + name: 'addPluginsJson', message: 'Should we add it to the plugins.json?' } ]); @@ -321,28 +322,69 @@ async function createSeedPlugin() { // Creating plugin seed //============================================================================== - const seedTemplatePlugin = path.join(dir, 'scripts/templates/plugin'); + const seedPlugin = path.join(dir, 'scripts/templates/plugin'); const newPluginPath = path.join(pluginsDir, answers.pluginName); - - try { - fs.copySync(seedTemplatePlugin, newPluginPath, { - filter: (p) => { - if (!answers.server) { - return /templates\/plugin\/server/.test(p); - } - if (!answers.client) { - return /templates\/plugin\/client/.test(p); + if (fs.existsSync(seedPlugin)) { + + if (answers.server && answers.client) { + + // This is a server-side and client-side plugin!, let's copy the template + fs.copySync(seedPlugin, newPluginPath); + } else { + + fs.copySync(seedPlugin, newPluginPath, {filter: (p) => { + + // Allowing plugin folder and files with no subfolders + const rootRx = /plugin$|plugin\/[^/]*(\.).{2,3}/igm; + if (rootRx.test(p) && (fs.lstatSync(p).isDirectory() || fs.lstatSync(p).isFile())) { + return true; } - return true; - } - }); + // If it's a client-side plugin, copying client folder + if (answers.client) { + return /client/.test(p); + } + + // If it's a server-side plugin, copying server folder + if (answers.server) { + return /server/.test(p); + } + + }}); + } + + // Let's add this to the plugins.json + if (answers.addPluginsJson) { + const pluginsJson = path.join(dir, 'plugins.json'); + + fs.readJson(pluginsJson) + .then(j => { + + // This is a client-side plugin, let's push this. + if (answers.client) { + j.client.push(answers.pluginName); + + const output = stringify(j); + fs.writeFileSync(pluginsJson, output); + } + + // This is a server-side plugin, let's push this. + if (answers.server) { + j.server.push(answers.pluginName); + + const output = stringify(j); + fs.writeFileSync(pluginsJson, output); + } + }) + .catch(err => { + console.error(err); + }); + } + + console.log(`✨ Yay! Plugin created! Find your plugin: ${answers.pluginName} in the /plugins folder`); + } - console.log(`✨ Yay! Talk Plugin Seed created! Find your plugin in the /plugins folder`); - } catch (err) { - console.error(err); - } } //============================================================================== diff --git a/package.json b/package.json index 218381896..7c99b46a2 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "immutability-helper": "^2.2.0", "inquirer": "^3.0.6", "joi": "^10.4.1", + "json-stringify-pretty-compact": "^1.0.4", "jsonwebtoken": "^7.3.0", "jwt-decode": "^2.2.0", "kue": "^0.11.5", diff --git a/yarn.lock b/yarn.lock index 9de2c35fa..c536e2901 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3290,6 +3290,14 @@ fs-extra@^0.26.4: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + fs-promise@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-0.3.1.tgz#bf34050368f24d6dc9dfc6688ab5cead8f86842a" @@ -4614,6 +4622,10 @@ json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" +json-stringify-pretty-compact@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-1.0.4.tgz#d5161131be27fd9748391360597fcca250c6c5ce" + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -4632,6 +4644,12 @@ jsonfile@^2.1.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -8263,6 +8281,10 @@ uniqs@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" +universalify@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.0.tgz#9eb1c4651debcc670cc94f1a75762332bb967778" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" From aad2455654a15eafc5dcadf771162c1f16fc6e0a Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 6 Jul 2017 15:19:26 -0300 Subject: [PATCH 05/17] Linting --- bin/cli-plugins | 9 ++++----- package.json | 1 - .../plugin/client/components/MyPluginComponent.js | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/bin/cli-plugins b/bin/cli-plugins index e5c3dd657..54bf0f1ed 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -20,7 +20,6 @@ const path = require('path'); const spawn = require('cross-spawn'); const semver = require('semver'); const resolve = require('resolve'); -const stringify = require("json-stringify-pretty-compact"); const {plugins, itteratePlugins, isInternal} = require('../plugins'); function existsInNodeModules(name) { @@ -359,13 +358,13 @@ async function createSeedPlugin() { const pluginsJson = path.join(dir, 'plugins.json'); fs.readJson(pluginsJson) - .then(j => { + .then((j) => { // This is a client-side plugin, let's push this. if (answers.client) { j.client.push(answers.pluginName); - const output = stringify(j); + const output = JSON.stringify(j, null, 2); fs.writeFileSync(pluginsJson, output); } @@ -373,11 +372,11 @@ async function createSeedPlugin() { if (answers.server) { j.server.push(answers.pluginName); - const output = stringify(j); + const output = JSON.stringify(j, null, 2); fs.writeFileSync(pluginsJson, output); } }) - .catch(err => { + .catch((err) => { console.error(err); }); } diff --git a/package.json b/package.json index 7c99b46a2..218381896 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,6 @@ "immutability-helper": "^2.2.0", "inquirer": "^3.0.6", "joi": "^10.4.1", - "json-stringify-pretty-compact": "^1.0.4", "jsonwebtoken": "^7.3.0", "jwt-decode": "^2.2.0", "kue": "^0.11.5", diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.js b/scripts/templates/plugin/client/components/MyPluginComponent.js index ff0fe6c3c..42bfc09fb 100644 --- a/scripts/templates/plugin/client/components/MyPluginComponent.js +++ b/scripts/templates/plugin/client/components/MyPluginComponent.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Icon} from 'plugin-api/beta/client/components/ui'; +import {CoralLogo} from 'plugin-api/beta/client/components/ui'; class MyPluginComponent extends React.Component { render() { From d2b4c2bcac030777f671ab631d6ca792f945d5ab Mon Sep 17 00:00:00 2001 From: David Erwin Date: Fri, 7 Jul 2017 13:43:05 -0400 Subject: [PATCH 06/17] Add architecture docs --- docs/_data/sidebars/talk_sidebar.yml | 8 +++ docs/architecture-tags.md | 7 +++ docs/architecture.md | 75 ++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 docs/architecture-tags.md create mode 100644 docs/architecture.md diff --git a/docs/_data/sidebars/talk_sidebar.yml b/docs/_data/sidebars/talk_sidebar.yml index b44c9648f..dd311cbef 100644 --- a/docs/_data/sidebars/talk_sidebar.yml +++ b/docs/_data/sidebars/talk_sidebar.yml @@ -37,6 +37,14 @@ entries: url: /install-setup.html output: web + - title: Architecture + output: web + folderitems: + - title: Overview + url: /architecture.html + output: web + + - title: Plugins output: web folderitems: diff --git a/docs/architecture-tags.md b/docs/architecture-tags.md new file mode 100644 index 000000000..7b402b436 --- /dev/null +++ b/docs/architecture-tags.md @@ -0,0 +1,7 @@ +--- +title: Architecture Overview +keywords: architecture +sidebar: talk_sidebar +permalink: architecture-tags.html +summary: +--- diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 000000000..dbaee1b3e --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,75 @@ +--- +title: Architecture Overview +keywords: architecture +sidebar: talk_sidebar +permalink: architecture.html +summary: +--- + +## Talk's Plugin/Plugin API/Core Architecture + +Talk consists of three distinct layers of code: + +* Plugins +* Plugin API +* Core + +### Plugins + +Talk plugins deliver the features and functionality that can be changed or removed. Much of the default functionality is delivered by plugins allowing developers to change behavior along product lines that we've found to be important. + +### Plugin API + +Talk plugins interact exclusively with the Plugin API. Maintaining this layer of separation between plugins and core allows us to consciously design the api that we want it publish to plugin authors. We can then expose just the elements of core that make sense and maintain that contract as core changes. + +### Core + +Talk core consists of architecture and functionality that deliver stability, security, scalability, extendability, etc... In addition, the Core contains features and functionality that is essential to the operation of Talk as a product. + +Our goal is to continually extend our plugin infrastructure making the Core as pluggable as possible. Ultimately, a day may come where the Core of Talk is simply a framework for delivering a certain flavor of web applications. + +## Thinking about Plugins, the Plugin API and Core? + +The following is a template for a thought process that may help clarify your ideas against the backdrop of Talk's architecture. + +Think of a feature of capability. It could be something that's already in Talk or not. It could be something you want to build, or something you'd think would be a terrible idea. The important part here is to have something to interrogate. + +``` +wait(60000); +``` + +Now, ask these questions: + +### Is it a Plugin? + +Most work for Talk these days happens in the Plugin space. If the answers to any of these questions is Yes, then you're thinking of a Plugin. + +* Does Talk's exiting Plugin APIs support the thing you want to build? +* Is this something that only some users will want/need? +* Is this something that we want devs to iterate on widely? + +You should [build it as a plugin](plugins-quickstart.html). Feel free to explore here on your own or reach out to us. We love to advise on plugins, so please feel free to [file an issue](https://github.com/coralproject/talk/blob/master/CONTRIBUTING.md) and we will start a conversation. We will help you conceptualize, architect and promote your plugin if it is in line with our values. + +### Does it need updates to the Plugin API? + +If you answered yes above: + +* Do I need to extend the Plugin API to support my plugin? + +Often times all the functionality a plugin needs is in the Core, but the Plugin API doesn't expose it. In these cases, we seek to iteratively extend the Talk Plugin API. All Plugin API contributions from the community must begin by [filing an Issue](https://github.com/coralproject/talk/blob/master/CONTRIBUTING.md). + +Note: we are stabilizing the process by which new Plugin API bindings are created, agreed upon and ultimately made part of our Plugins Contract. If you are interested in this process, please reach out to us. + +### Does it need updates to the Plugin API _and_ Core? + +3) What, if any, changes need to be made to Core so that the API can be extended? + +Quite often the only things missing from Core are things like _events_, _slots_, _CSS classes_, etc... Adding these is a great way to become a Core Contributor and break new ground as a Plugin Developer. + +We seek to keep Core as lean as possible. + +### Is my idea really just Core? + +Amazing! We are always looking to extend the capabilities of Talk. We look forward to discussing what you've got to bring! + +Please see our [contributing guide](](https://github.com/coralproject/talk/blob/master/CONTRIBUTING.md)) for more information about contributing Core code. From c3ec772ea27072c40c646b471bf8eb422d28084a Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 7 Jul 2017 14:43:46 -0300 Subject: [PATCH 07/17] new cta for questions --- bin/cli-plugins | 4 ++-- .../templates/plugin-client/client/.babelrc | 14 ----------- .../plugin-client/client/.eslintrc.json | 23 ------------------- scripts/templates/plugin-client/index.js | 1 - scripts/templates/plugin-server/index.js | 1 - 5 files changed, 2 insertions(+), 41 deletions(-) delete mode 100644 scripts/templates/plugin-client/client/.babelrc delete mode 100644 scripts/templates/plugin-client/client/.eslintrc.json delete mode 100644 scripts/templates/plugin-client/index.js delete mode 100644 scripts/templates/plugin-server/index.js diff --git a/bin/cli-plugins b/bin/cli-plugins index 54bf0f1ed..e4b5cae51 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -303,12 +303,12 @@ async function createSeedPlugin() { { type: 'confirm', name: 'server', - message: 'Is this a server-side plugin?' + message: 'Is this plugin extending the server capabilities?' }, { type: 'confirm', name: 'client', - message: 'Is this a client-side plugin?' + message: 'Is this plugin extending the client capabilities?' }, { type: 'confirm', diff --git a/scripts/templates/plugin-client/client/.babelrc b/scripts/templates/plugin-client/client/.babelrc deleted file mode 100644 index 60be246eb..000000000 --- a/scripts/templates/plugin-client/client/.babelrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "presets": [ - "es2015" - ], - "plugins": [ - "add-module-exports", - "transform-class-properties", - "transform-decorators-legacy", - "transform-object-assign", - "transform-object-rest-spread", - "transform-async-to-generator", - "transform-react-jsx" - ] -} \ No newline at end of file diff --git a/scripts/templates/plugin-client/client/.eslintrc.json b/scripts/templates/plugin-client/client/.eslintrc.json deleted file mode 100644 index 9fe56bd14..000000000 --- a/scripts/templates/plugin-client/client/.eslintrc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "mocha": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaFeatures": { - "experimentalObjectRestSpread": true, - "jsx": true - } - }, - "parser": "babel-eslint", - "plugins": [ - "react" - ], - "rules": { - "react/jsx-uses-react": "error", - "react/jsx-uses-vars": "error", - "no-console": ["warn", { "allow": ["warn", "error"] }] - } -} diff --git a/scripts/templates/plugin-client/index.js b/scripts/templates/plugin-client/index.js deleted file mode 100644 index f053ebf79..000000000 --- a/scripts/templates/plugin-client/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/scripts/templates/plugin-server/index.js b/scripts/templates/plugin-server/index.js deleted file mode 100644 index f053ebf79..000000000 --- a/scripts/templates/plugin-server/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; From 52d7ba8965ef245374284b732e28e7955c5e0d3d Mon Sep 17 00:00:00 2001 From: David Erwin Date: Fri, 7 Jul 2017 16:59:18 -0400 Subject: [PATCH 08/17] Add Tags docs --- docs/_data/sidebars/talk_sidebar.yml | 3 ++ docs/architecture-tags.md | 64 +++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/docs/_data/sidebars/talk_sidebar.yml b/docs/_data/sidebars/talk_sidebar.yml index dd311cbef..ed307b88e 100644 --- a/docs/_data/sidebars/talk_sidebar.yml +++ b/docs/_data/sidebars/talk_sidebar.yml @@ -43,6 +43,9 @@ entries: - title: Overview url: /architecture.html output: web + - title: Tags + url: /architecture-tags.html + output: web - title: Plugins diff --git a/docs/architecture-tags.md b/docs/architecture-tags.md index 7b402b436..38205c7eb 100644 --- a/docs/architecture-tags.md +++ b/docs/architecture-tags.md @@ -1,7 +1,69 @@ --- -title: Architecture Overview +title: Tags keywords: architecture sidebar: talk_sidebar permalink: architecture-tags.html summary: --- + +Tags can be added to Users, Comments and Assets. + +## Tag Definitions + +When handling tags, the Talk Server references a set of definitions that describe how tags are handled. These definitions are keyed off the tag `name`, the simple string that is stored on items. + +The schema for Tag definitions [can be found here](https://github.com/coralproject/talk/blob/3545bf01cd91044fdb738d337a0ac94d9f71fbc3/models/schema/tag.js). + +Note that along with the `name`, tag definitions contains: + +* `permissions` information about who can see and set the tag, +* `models` which `ITEM_TYPES` this tag can be applied to, and + +Whenever a tag is 'handled' by the server, it references this definition to determine that tag's behavior. + +See [Plugin API Documentation](plugins-server.html#field-tags) for more information. + +### Creating a Tag Definition + +Tag Definitions must be created before tags can be used. This ensures that users cannot push arbitrary tags to hack the system. It also allows devs to specify the behavioral characteristics of the tag. + +Take the tag created by `coral-plugin-offtopic` as an example. + +``` +// coral-plugin-offtopic/index.js +module.exports = { + tags: [ + { + name: 'OFF_TOPIC', + permissions: { + public: true, + self: true, + roles: [] + }, + models: ['COMMENTS'], + created_at: new Date() + } + ] +}; +``` + +This plugin allows users to self-report that their comment is "off topic" at the time of creation, then display a badge on those comments. + +To accomplish this, the plugin creates the tag `OFF_TOPIC` with: + +* `public: true` - will be sent over the wire to the client side) +* `self: true` - can be added by the active user to themselves or assets they own +* `roles: []` - cannot be added by anyone based on their roles +* `models: ['COMMENTS']` - can only be added to COMMENTS (not to users/assets/etc...) + +And viola! This tag is something that can only be created by the logged in user on their own comments and is sent over the wire to the client so it can display the badge. + +## Tag Links + +When tags are stored on objects in the database, they are represented by [TagLinks](https://github.com/coralproject/talk/blob/master/models/schema/tag_link.js). + +A TagLinks says that `tag` was `assigned_by` a specific user at a specific time (`created_at`). + +Note that the `tag` field in the TagLinkSchema is the full TagSchema itself. This allows for another level of flexibility. Server code may generate Tags on the fly, complete with programmatically generated permissions and item behaviors. + +If a Tag definitions exists in the global/asset context then that definition will be used regardless of what is stored here. This allows high level controls on the behavior of tags. From 83d7e599c79f0765f074a2379feceb2b0b047ef8 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sun, 9 Jul 2017 12:09:07 -0300 Subject: [PATCH 09/17] pushing client template --- .../client/components/MyPluginComponent.css | 27 +++++++++++++++++++ .../client/components/MyPluginComponent.js | 16 ++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 scripts/templates/plugin/client/components/MyPluginComponent.css diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.css b/scripts/templates/plugin/client/components/MyPluginComponent.css new file mode 100644 index 000000000..187e68750 --- /dev/null +++ b/scripts/templates/plugin/client/components/MyPluginComponent.css @@ -0,0 +1,27 @@ +.myPluginContainer { + padding: 10px; + background: #f0f0f0; + border: 1px solid #d6d6d6; + margin: 10px 0; + text-align: center; + border-radius: 3px; +} + +.logo { + position: block; + animation: spin 2s infinite ease; + animation-delay: 1s; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.description { + color: #444444; +} diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.js b/scripts/templates/plugin/client/components/MyPluginComponent.js index 42bfc09fb..d586ab473 100644 --- a/scripts/templates/plugin/client/components/MyPluginComponent.js +++ b/scripts/templates/plugin/client/components/MyPluginComponent.js @@ -1,12 +1,22 @@ import React from 'react'; import {CoralLogo} from 'plugin-api/beta/client/components/ui'; +import styles from './MyPluginComponent.css'; class MyPluginComponent extends React.Component { render() { return ( -
- - Plugin Created by Talk CLI +
+ +
+

Plugin created by Talk CLI

+ + + To read more about client plugins check{' '} + + our docs and guides! + + +
); } From 1e3c1feadfe4336717162cfb1fcb4e800eba0971 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sun, 9 Jul 2017 12:09:54 -0300 Subject: [PATCH 10/17] cta --- scripts/templates/plugin/client/components/MyPluginComponent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.js b/scripts/templates/plugin/client/components/MyPluginComponent.js index d586ab473..89e274e1a 100644 --- a/scripts/templates/plugin/client/components/MyPluginComponent.js +++ b/scripts/templates/plugin/client/components/MyPluginComponent.js @@ -11,7 +11,7 @@ class MyPluginComponent extends React.Component {

Plugin created by Talk CLI

- To read more about client plugins check{' '} + To read more about plugins check{' '} our docs and guides! From a686bc75a7710c7dc1cd9b04c2d1e2d10a3b9e8c Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 10 Jul 2017 10:30:20 -0600 Subject: [PATCH 11/17] Some changes to server side stuff + tempalte location --- bin/cli-plugins | 10 +++++----- {scripts => bin}/templates/plugin/client/.babelrc | 0 .../templates/plugin/client/.eslintrc.json | 0 .../plugin/client/components/MyPluginComponent.css | 0 .../plugin/client/components/MyPluginComponent.js | 0 {scripts => bin}/templates/plugin/client/index.js | 0 .../templates/plugin/client/translations.yml | 0 {scripts => bin}/templates/plugin/index.js | 0 8 files changed, 5 insertions(+), 5 deletions(-) rename {scripts => bin}/templates/plugin/client/.babelrc (100%) rename {scripts => bin}/templates/plugin/client/.eslintrc.json (100%) rename {scripts => bin}/templates/plugin/client/components/MyPluginComponent.css (100%) rename {scripts => bin}/templates/plugin/client/components/MyPluginComponent.js (100%) rename {scripts => bin}/templates/plugin/client/index.js (100%) rename {scripts => bin}/templates/plugin/client/translations.yml (100%) rename {scripts => bin}/templates/plugin/index.js (100%) diff --git a/bin/cli-plugins b/bin/cli-plugins index e4b5cae51..942036d29 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -274,7 +274,7 @@ async function reconcilePluginDeps({skipLocal, skipRemote, dryRun, upgradeRemote } async function createSeedPlugin() { - const pluginsDir = path.join(dir, 'plugins'); + const pluginsDir = path.join(__dirname, 'plugins'); function pluginNameExists(pluginName) { const pluginNames = fs.readdirSync(pluginsDir); @@ -321,7 +321,7 @@ async function createSeedPlugin() { // Creating plugin seed //============================================================================== - const seedPlugin = path.join(dir, 'scripts/templates/plugin'); + const seedPlugin = path.join(__dirname, 'bin/templates/plugin'); const newPluginPath = path.join(pluginsDir, answers.pluginName); if (fs.existsSync(seedPlugin)) { @@ -363,7 +363,7 @@ async function createSeedPlugin() { // This is a client-side plugin, let's push this. if (answers.client) { j.client.push(answers.pluginName); - + const output = JSON.stringify(j, null, 2); fs.writeFileSync(pluginsJson, output); } @@ -381,8 +381,8 @@ async function createSeedPlugin() { }); } - console.log(`✨ Yay! Plugin created! Find your plugin: ${answers.pluginName} in the /plugins folder`); - } + console.log(`✨ Yay! Plugin created! Find your plugin: ${answers.pluginName} in the ./plugins folder`); + } } diff --git a/scripts/templates/plugin/client/.babelrc b/bin/templates/plugin/client/.babelrc similarity index 100% rename from scripts/templates/plugin/client/.babelrc rename to bin/templates/plugin/client/.babelrc diff --git a/scripts/templates/plugin/client/.eslintrc.json b/bin/templates/plugin/client/.eslintrc.json similarity index 100% rename from scripts/templates/plugin/client/.eslintrc.json rename to bin/templates/plugin/client/.eslintrc.json diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.css b/bin/templates/plugin/client/components/MyPluginComponent.css similarity index 100% rename from scripts/templates/plugin/client/components/MyPluginComponent.css rename to bin/templates/plugin/client/components/MyPluginComponent.css diff --git a/scripts/templates/plugin/client/components/MyPluginComponent.js b/bin/templates/plugin/client/components/MyPluginComponent.js similarity index 100% rename from scripts/templates/plugin/client/components/MyPluginComponent.js rename to bin/templates/plugin/client/components/MyPluginComponent.js diff --git a/scripts/templates/plugin/client/index.js b/bin/templates/plugin/client/index.js similarity index 100% rename from scripts/templates/plugin/client/index.js rename to bin/templates/plugin/client/index.js diff --git a/scripts/templates/plugin/client/translations.yml b/bin/templates/plugin/client/translations.yml similarity index 100% rename from scripts/templates/plugin/client/translations.yml rename to bin/templates/plugin/client/translations.yml diff --git a/scripts/templates/plugin/index.js b/bin/templates/plugin/index.js similarity index 100% rename from scripts/templates/plugin/index.js rename to bin/templates/plugin/index.js From 8b70dc688de2650ac507703b5e8a5ca7176e8df3 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 11 Jul 2017 21:03:27 +0700 Subject: [PATCH 12/17] Adapt CSS classnames for Embed --- .../src/components/Embed.js | 55 ++++++++++--------- client/coral-embed-stream/src/index.js | 2 +- views/embed/stream.ejs | 2 +- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index 145e8340a..a98dbf976 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -9,6 +9,7 @@ import Count from 'coral-plugin-comment-count/CommentCount'; import ProfileContainer from 'coral-settings/containers/ProfileContainer'; import ConfigureStreamContainer from 'coral-configure/containers/ConfigureStreamContainer'; +import cn from 'classnames'; export default class Embed extends React.Component { changeTab = (tab) => { @@ -37,34 +38,36 @@ export default class Embed extends React.Component { const {activeTab, viewAllComments, commentId} = this.props; const {asset: {totalCommentCount}} = this.props.root; const {user} = this.props.auth; + const hasHighlightedComment = !!commentId; return ( -
-
- - - {t('framework.my_profile')} - {t('framework.configure_stream')} - - {commentId && - } - - - - - - - - - - -
+
+ + + {t('framework.my_profile')} + + {t('framework.configure_stream')} + + + {commentId && + } + + + + + + + + + +
); } diff --git a/client/coral-embed-stream/src/index.js b/client/coral-embed-stream/src/index.js index f5be3922d..9020a8457 100644 --- a/client/coral-embed-stream/src/index.js +++ b/client/coral-embed-stream/src/index.js @@ -48,5 +48,5 @@ render( - , document.querySelector('#coralStream') + , document.querySelector('#talk-embed-stream-container') ); diff --git a/views/embed/stream.ejs b/views/embed/stream.ejs index 03897d85f..99ca2072a 100644 --- a/views/embed/stream.ejs +++ b/views/embed/stream.ejs @@ -15,7 +15,7 @@ -
+
From 40f4419c9de896213a3574536f4606abe9ebb00d Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 11 Jul 2017 21:04:19 +0700 Subject: [PATCH 13/17] Add flagged unflagged CSS classnames --- client/coral-embed-stream/src/components/Embed.js | 4 ++-- client/coral-plugin-flags/components/FlagButton.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index a98dbf976..98137624f 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -42,7 +42,7 @@ export default class Embed extends React.Component { return (
- + {t('framework.my_profile')} @@ -54,7 +54,7 @@ export default class Embed extends React.Component { cStyle="darkGrey" style={{float: 'right'}} onClick={viewAllComments} - className={'talk-embed-stream-show-all-comments-button'} + className={'talk-stream-show-all-comments-button'} > {t('framework.show_all_comments')} } diff --git a/client/coral-plugin-flags/components/FlagButton.js b/client/coral-plugin-flags/components/FlagButton.js index 25fcf21a9..33499e83d 100644 --- a/client/coral-plugin-flags/components/FlagButton.js +++ b/client/coral-plugin-flags/components/FlagButton.js @@ -148,7 +148,7 @@ export default class FlagButton extends Component {