├── .gitignore
├── .htaccess
├── LICENSE
├── README.md
├── _redirects
├── config
├── env.js
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── paths.js
├── polyfills.js
├── webpack.config.dev.js
├── webpack.config.prod.js
└── webpackDevServer.config.js
├── package.json
├── public
├── index.html
├── manifest.json
└── static
│ ├── livechat.png
│ └── octopus.png
├── readme-assets
├── auth-provider.png
├── config.png
├── create-page.png
├── domain.png
├── edit-menu.png
├── edit-page.png
├── index.png
├── new-page.png
├── rules.png
└── system-diagram.png
├── scripts
├── build.js
├── start.js
└── test.js
├── src
├── App.css
├── App.js
├── App.test.js
├── components
│ ├── markdown
│ │ ├── Markdown.js
│ │ ├── hljs-github.css
│ │ └── index.js
│ ├── menu-search
│ │ ├── MenuSearch.css
│ │ ├── MenuSearch.js
│ │ └── index.js
│ ├── page
│ │ ├── Page.css
│ │ ├── Page.js
│ │ └── index.js
│ ├── people-online
│ │ ├── PeopleOnline.js
│ │ └── index.js
│ └── person
│ │ ├── Person.js
│ │ └── index.js
├── config
│ ├── config.template.js
│ └── index.js
├── containers
│ └── page
│ │ ├── PageContainer.js
│ │ └── index.js
├── css
│ ├── buttons.css
│ ├── markdown.css
│ ├── reset.css
│ └── tooltips.css
├── index.js
├── markdown-plugins
│ ├── diagram
│ │ ├── diagram.css
│ │ └── diagram.js
│ ├── flowchart
│ │ └── flowchart.js
│ ├── google-storage-images
│ │ └── google-storage-images.js
│ ├── heading-anchors
│ │ ├── heading-anchors.css
│ │ └── heading-anchors.js
│ └── react-router-links
│ │ └── react-router-links.js
├── registerServiceWorker.js
├── templates
│ ├── company-structure.js
│ ├── diagrams-help.js
│ ├── index-page.js
│ ├── index.js
│ ├── menu.js
│ ├── new-page.js
│ └── product-roadmap.js
└── utils
│ ├── Firebase.js
│ ├── OnlineTracker.js
│ ├── Utils.js
│ └── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # config
4 | /config/config.php
5 |
6 | # dependencies
7 | /node_modules
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 | /build
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | # PHP Storm files
27 | .idea
28 |
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | Options FollowSymLinks MultiViews
3 | RewriteEngine on
4 | RewriteCond %{REQUEST_FILENAME} !-d
5 | RewriteCond %{REQUEST_FILENAME} !-f
6 | RewriteRule . index.html [L]
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 LiveChat
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Octopus
2 |
3 | [](https://github.com/prettier/prettier)
4 |
5 | **🐙 Octopus** is a server-less, easy-to-setup internal wiki page with built-in software diagrams support. It uses **Markdown** for writing content and enhances it with [Graphviz](http://graphviz.org) and [flowchart.js](http://flowchart.js.org/) diagrams for easy software documentation.
6 |
7 | Here's a default wiki page:
8 |
9 |
10 |
11 |
12 |
13 | ### Technology
14 |
15 | Octopus is a [JAMstack](https://jamstack.org/) app that uses [Google Firebase](https://firebase.google.com/) as its backend. You do not need a web server (such as Apache) or a database (like MySQL) to have it up and running. You can deploy the app to a CDN for free using [Netlify](https://www.netlify.com/).
16 |
17 | #### With Octopus, you can:
18 | * require users to be signed in to read or edit the wiki (supported providers: Google, GitHub, Email/Password, Twitter and Phone),
19 | * create access rules for reading and editing (restrict particular users or auth domains),
20 | * host wiki page under a custom domain.
21 |
22 | #### Features
23 | * create new wiki pages with Markdown language,
24 | * edit menu (using Markdown) to easily link to wiki pages,
25 | * include [Graphviz](http://www.graphviz.org/Gallery.php) and [flowchart.js](http://flowchart.js.org/) diagrams inside your Markdown content,
26 | * see who is currently reading your wiki articles,
27 | * adjust your Wiki front-end with React ([create-react-app](https://github.com/facebookincubator/create-react-app)).
28 |
29 |
30 | #### Example system diagram
31 |
32 |
33 |
34 |
35 | #### Page editing with Markdown
36 |
37 |
38 |
39 |
40 | ## Installation
41 | 1. Clone this repository to your computer.
42 | 2. Copy config template file (`src/config/config.template.js`) to `src/config/config.js`.
43 |
44 | ```
45 | cp src/config/config.template.js src/config/config.js
46 | ```
47 |
48 | > Note: you can safely commit `src/config/config.js` file to a repository. This file does not store sensitive credentials - all config variables will be publicly available in the `.js` file anyway.
49 |
50 | 3. Create a new Firebase project here: https://firebase.google.com/
51 | 4. Pick "Add Firebase to your web app" and copy the config to `src/config/config.js` created in step 2.
52 |
53 |
54 |
55 |
56 |
57 |
58 | 5. In Firebase Console, go to **Authentication** > **Sign-in method**, choose a provider and enable it. Octopus has been tested with Google and GitHub providers.
59 |
60 |
61 |
62 |
63 |
64 | 6. Still in **Authentication** > **Sign-in method** section, add the domain that will host your app to **Authorized Domains** list.
65 |
66 |
67 |
68 |
69 |
70 | 7. Build the app:
71 | ```
72 | npm install
73 | npm run build
74 | ```
75 |
76 | 8. Deploy the `build/` directory to your webserver.
77 |
78 | ## Server-less deployment
79 | You can skip hosting the app on your webserver (step 8 from installation guide above). All you need is to deploy the app to a cloud-based CDN provider.
80 |
81 | We recommend using [Netlify](https://www.netlify.com/).
82 |
83 | It will automatically deploy your forked Octopus GitHub repo to production after each commit. It will also prepare a ready-to-use URL that all your users can access immediately. Later on, you can set up a custom domain to make it look more professional.
84 |
85 | Note: when deploying Octopus via Netlify, fill in the following details in the setup wizard:
86 |
87 | > Build command: `npm run build`
88 | > Publish directory: `build`
89 |
90 | ## Security
91 | By default, any user can view and edit your wiki page. Probably this is not what you expect!
92 |
93 | To make your content accessible only to your company, go to **Firebase Console** > **Database** > **Rules** and restrict who can read and edit your wiki page.
94 |
95 | Here's an example rule if you use Google sign-in provider and your company email address ends with **@livechatinc.com**:
96 |
97 |
98 |
99 |
100 |
101 |
102 | ```
103 | {
104 | "rules": {
105 | ".read": "auth.token.email.endsWith('@livechatinc.com')",
106 | ".write": "auth.token.email.endsWith('@livechatinc.com')"
107 | }
108 | }
109 | ```
110 |
111 | You can read more about possible security rules in [Realtime Database Rules](https://firebase.google.com/docs/database/security/) documentation.
112 |
113 | ## Using Octopus
114 | Octopus is designed to be very easy to use.
115 |
116 | To create a new page, just enter the URL you wish to create, for example: `https:///test/new-page`. If such page has not been created yet, you will see the following screen:
117 |
118 |
119 |
120 |
121 |
122 |
123 | When you click "Create this page", new page will be created and filled in with default content, ready to edit:
124 |
125 |
126 |
127 |
128 |
129 |
130 | Once the page is ready, you can easily include it in the menu:
131 |
132 |
133 |
134 |
135 |
136 |
137 | That's it. Send all your teammates link to Octopus and they're ready to contribute!
138 |
139 |
140 |
141 | ## Project background
142 | Why did we build Octopus?
143 |
144 | We've struggled with finding an easy-to-use software for documenting internal systems at [LiveChat](https://www.livechatinc.com/).
145 |
146 | We wanted it to be easy to contribute for **non-technical people** and include easily **editable software diagrams**. We couldn't find a satisfying product, so we've built one.
147 |
148 | ## Built with
149 | * React via [create-react-app](https://github.com/facebookincubator/create-react-app).
150 | * [viz.js](https://github.com/mdaines/viz.js/)
151 | * [flowchart.js](https://github.com/adrai/flowchart.js)
152 | * [Firebase](https://firebase.google.com/)
153 |
154 | ## Changelog
155 | * 15.09.2017 - "Open as .png" option
156 | * 13.09.2017 - Initial release
157 |
158 | ## Authors
159 | [Bartosz Olchówka](https://twitter.com/bolchowka/) / CTO @ [LiveChat](https://www.livechatinc.com/)
160 |
161 | ## License
162 | This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details
163 |
--------------------------------------------------------------------------------
/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
2 |
--------------------------------------------------------------------------------
/config/env.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 |
7 | // Make sure that including paths.js after env.js will read .env variables.
8 | delete require.cache[require.resolve('./paths')];
9 |
10 | const NODE_ENV = process.env.NODE_ENV;
11 | if (!NODE_ENV) {
12 | throw new Error(
13 | 'The NODE_ENV environment variable is required but was not specified.'
14 | );
15 | }
16 |
17 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
18 | var dotenvFiles = [
19 | `${paths.dotenv}.${NODE_ENV}.local`,
20 | `${paths.dotenv}.${NODE_ENV}`,
21 | // Don't include `.env.local` for `test` environment
22 | // since normally you expect tests to produce the same
23 | // results for everyone
24 | NODE_ENV !== 'test' && `${paths.dotenv}.local`,
25 | paths.dotenv,
26 | ].filter(Boolean);
27 |
28 | // Load environment variables from .env* files. Suppress warnings using silent
29 | // if this file is missing. dotenv will never modify any environment variables
30 | // that have already been set.
31 | // https://github.com/motdotla/dotenv
32 | dotenvFiles.forEach(dotenvFile => {
33 | if (fs.existsSync(dotenvFile)) {
34 | require('dotenv').config({
35 | path: dotenvFile,
36 | });
37 | }
38 | });
39 |
40 | // We support resolving modules according to `NODE_PATH`.
41 | // This lets you use absolute paths in imports inside large monorepos:
42 | // https://github.com/facebookincubator/create-react-app/issues/253.
43 | // It works similar to `NODE_PATH` in Node itself:
44 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
45 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
46 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
47 | // https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
48 | // We also resolve them to make sure all tools using them work consistently.
49 | const appDirectory = fs.realpathSync(process.cwd());
50 | process.env.NODE_PATH = (process.env.NODE_PATH || '')
51 | .split(path.delimiter)
52 | .filter(folder => folder && !path.isAbsolute(folder))
53 | .map(folder => path.resolve(appDirectory, folder))
54 | .join(path.delimiter);
55 |
56 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
57 | // injected into the application via DefinePlugin in Webpack configuration.
58 | const REACT_APP = /^REACT_APP_/i;
59 |
60 | function getClientEnvironment(publicUrl) {
61 | const raw = Object.keys(process.env)
62 | .filter(key => REACT_APP.test(key))
63 | .reduce(
64 | (env, key) => {
65 | env[key] = process.env[key];
66 | return env;
67 | },
68 | {
69 | // Useful for determining whether we’re running in production mode.
70 | // Most importantly, it switches React into the correct mode.
71 | NODE_ENV: process.env.NODE_ENV || 'development',
72 | // Useful for resolving the correct path to static assets in `public`.
73 | // For example,
.
74 | // This should only be used as an escape hatch. Normally you would put
75 | // images into the `src` and `import` them in code to get their paths.
76 | PUBLIC_URL: publicUrl,
77 | }
78 | );
79 | // Stringify all values so we can feed into Webpack DefinePlugin
80 | const stringified = {
81 | 'process.env': Object.keys(raw).reduce(
82 | (env, key) => {
83 | env[key] = JSON.stringify(raw[key]);
84 | return env;
85 | },
86 | {}
87 | ),
88 | };
89 |
90 | return { raw, stringified };
91 | }
92 |
93 | module.exports = getClientEnvironment;
94 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`;
20 | } else {
21 | return path;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right