├── .editorconfig ├── .eslintrc ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── TODO.md ├── docs └── deployment.md ├── package.json ├── packages ├── insights-api │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── app.hooks.ts │ │ ├── app.ts │ │ ├── authentication.ts │ │ ├── channels.ts │ │ ├── config.ts │ │ ├── declarations.d.ts │ │ ├── index.ts │ │ ├── insights │ │ │ ├── adapter │ │ │ │ ├── index.ts │ │ │ │ └── sql │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── postgres.ts │ │ │ │ │ └── sqlite.ts │ │ │ ├── definitions.d.ts │ │ │ ├── results │ │ │ │ └── index.ts │ │ │ └── structure │ │ │ │ ├── generators │ │ │ │ ├── index.ts │ │ │ │ └── postgres.ts │ │ │ │ └── index.ts │ │ ├── logger.ts │ │ ├── middleware │ │ │ └── index.ts │ │ ├── models │ │ │ ├── connections.model.ts │ │ │ ├── favourites.model.ts │ │ │ ├── subsets.model.ts │ │ │ ├── urls.model.ts │ │ │ ├── users.model.ts │ │ │ └── views.model.ts │ │ ├── services │ │ │ ├── connection-test │ │ │ │ ├── connection-test.class.ts │ │ │ │ ├── connection-test.hooks.ts │ │ │ │ └── connection-test.service.ts │ │ │ ├── connections │ │ │ │ ├── connections.class.ts │ │ │ │ ├── connections.hooks.ts │ │ │ │ └── connections.service.ts │ │ │ ├── favourites │ │ │ │ ├── favourites.class.ts │ │ │ │ ├── favourites.hooks.ts │ │ │ │ └── favourites.service.ts │ │ │ ├── index.ts │ │ │ ├── results │ │ │ │ ├── results.class.ts │ │ │ │ ├── results.hooks.ts │ │ │ │ └── results.service.ts │ │ │ ├── structure │ │ │ │ ├── structure.class.ts │ │ │ │ ├── structure.hooks.ts │ │ │ │ └── structure.service.ts │ │ │ ├── subsets │ │ │ │ ├── subsets.class.ts │ │ │ │ ├── subsets.hooks.ts │ │ │ │ └── subsets.service.ts │ │ │ ├── urls │ │ │ │ ├── urls.class.ts │ │ │ │ ├── urls.hooks.ts │ │ │ │ └── urls.service.ts │ │ │ ├── users │ │ │ │ ├── users.class.ts │ │ │ │ ├── users.hooks.ts │ │ │ │ └── users.service.ts │ │ │ └── views │ │ │ │ ├── views.class.ts │ │ │ │ ├── views.hooks.ts │ │ │ │ └── views.service.ts │ │ └── utils │ │ │ ├── find-config-folder.ts │ │ │ ├── random-string.ts │ │ │ └── set-config-folder.ts │ ├── test │ │ ├── app.test.ts │ │ ├── authentication.test.ts │ │ └── services │ │ │ ├── connection-test.test.ts │ │ │ ├── connections.test.ts │ │ │ ├── favourites.test.ts │ │ │ ├── results.test.ts │ │ │ ├── structure.test.ts │ │ │ ├── subsets.test.ts │ │ │ ├── urls.test.ts │ │ │ ├── users.test.ts │ │ │ └── views.test.ts │ ├── tsconfig.json │ └── yarn.lock ├── insights-charts │ ├── .babelrc │ ├── package.json │ ├── src │ │ ├── graph │ │ │ ├── basic-tooltip.js │ │ │ ├── data-ui.js │ │ │ └── recharts.js │ │ └── index.js │ └── yarn.lock ├── insights-desktop │ ├── bin │ │ └── insights-desktop │ ├── main.js │ ├── package.json │ └── src │ │ └── insights-desktop.js ├── insights-web │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── config-overrides.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── insights.svg │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── logo64.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── index.js │ │ ├── index.scss │ │ ├── lib │ │ │ ├── client.js │ │ │ ├── explorer │ │ │ │ ├── get-meta.js │ │ │ │ ├── get-sorted-meta.js │ │ │ │ ├── state-to-url.js │ │ │ │ └── url-to-state.js │ │ │ ├── popups │ │ │ │ ├── delete.js │ │ │ │ └── prompt.js │ │ │ ├── selectors │ │ │ │ └── location.js │ │ │ ├── tags │ │ │ │ ├── spinner.js │ │ │ │ └── submit-button.js │ │ │ └── utils │ │ │ │ ├── delay.js │ │ │ │ ├── highlight-text.js │ │ │ │ ├── move-caret-to-end.js │ │ │ │ ├── range.js │ │ │ │ └── script.js │ │ ├── react-app-env.d.ts │ │ ├── scenes │ │ │ ├── _layout │ │ │ │ ├── index.js │ │ │ │ ├── logic.js │ │ │ │ ├── styles.scss │ │ │ │ └── styles │ │ │ │ │ └── spinner.scss │ │ │ ├── auth.js │ │ │ ├── explorer │ │ │ │ ├── connection │ │ │ │ │ ├── database │ │ │ │ │ │ ├── form │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── intro.js │ │ │ │ │ │ │ └── timezones.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── menu │ │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── logic.js │ │ │ │ │ ├── styles.scss │ │ │ │ │ └── subset │ │ │ │ │ │ ├── form │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── logic.js │ │ │ │ │ │ └── models │ │ │ │ │ │ │ ├── edit-field │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ │ ├── field-row │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── json │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ │ ├── logic.js │ │ │ │ │ │ │ ├── model-row │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ │ └── styles.scss │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── menu │ │ │ │ │ │ └── index.js │ │ │ │ ├── dashboard │ │ │ │ │ ├── breadcrumbs │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── model.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── model-map │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── styles.scss │ │ │ │ │ ├── tutorial │ │ │ │ │ │ └── index.js │ │ │ │ │ └── views │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── styles.scss │ │ │ │ ├── filter │ │ │ │ │ ├── column-filters.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── one-filter.js │ │ │ │ │ └── styles.scss │ │ │ │ ├── graph │ │ │ │ │ ├── compare-with.js │ │ │ │ │ ├── controls-right.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── styles.scss │ │ │ │ │ └── time-group-select.js │ │ │ │ ├── index.js │ │ │ │ ├── logic.js │ │ │ │ ├── pagination │ │ │ │ │ └── index.js │ │ │ │ ├── saga.js │ │ │ │ ├── sidebar │ │ │ │ │ ├── index.js │ │ │ │ │ ├── models │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── logic.js │ │ │ │ │ ├── selected-model │ │ │ │ │ │ ├── aggregate │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ ├── filter-button │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── pin │ │ │ │ │ │ │ └── index.js │ │ │ │ │ └── styles.scss │ │ │ │ ├── styles.scss │ │ │ │ ├── table │ │ │ │ │ ├── column-settings.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── styles.scss │ │ │ │ │ ├── table-cell.js │ │ │ │ │ ├── table-header.js │ │ │ │ │ └── table-settings.js │ │ │ │ ├── tags │ │ │ │ │ └── full-path │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── styles.scss │ │ │ │ └── time-filter │ │ │ │ │ └── index.js │ │ │ ├── header │ │ │ │ ├── copy-query │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ ├── logic.js │ │ │ │ ├── saga.js │ │ │ │ ├── share │ │ │ │ │ └── index.js │ │ │ │ ├── styles.scss │ │ │ │ ├── user │ │ │ │ │ └── index.js │ │ │ │ └── views │ │ │ │ │ ├── index.js │ │ │ │ │ ├── logic.js │ │ │ │ │ └── styles.scss │ │ │ ├── index.js │ │ │ ├── login │ │ │ │ ├── index.js │ │ │ │ ├── logic.js │ │ │ │ ├── saga.js │ │ │ │ └── styles.scss │ │ │ ├── routes.js │ │ │ ├── settings │ │ │ │ ├── index.js │ │ │ │ └── styles.scss │ │ │ ├── urls │ │ │ │ └── index.js │ │ │ └── users │ │ │ │ ├── index.js │ │ │ │ ├── logic.js │ │ │ │ └── styles.scss │ │ └── serviceWorker.ts │ ├── tsconfig.json │ └── yarn.lock └── insights │ ├── app │ ├── create-secret.js │ ├── create-superuser.js │ ├── init.js │ ├── lib │ │ ├── create-folder.js │ │ ├── find-config-folder.js │ │ └── random-string.js │ ├── start.js │ └── templates │ │ ├── default.json │ │ ├── development.json │ │ └── production.json │ ├── bin │ ├── insights │ ├── insights-createsecret │ ├── insights-createsuperuser │ ├── insights-init │ └── insights-start │ ├── package.json │ └── yarn.lock ├── scripts └── sync-versions.js ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "extends": ["standard", "standard-react"], 8 | "parser": "babel-eslint", 9 | "rules": { 10 | "indent": [ 11 | "error", 12 | 2 13 | ], 14 | "linebreak-style": [ 15 | "error", 16 | "unix" 17 | ], 18 | "quotes": [ 19 | "error", 20 | "single" 21 | ], 22 | "react/jsx-uses-react": 2, 23 | "react/jsx-uses-vars": 2, 24 | "react/jsx-indent-props": 0, 25 | "react/prop-types": 0, 26 | "react/react-in-jsx-scope": 2, 27 | "arrow-parens": 0, 28 | "no-debugger": "off" 29 | }, 30 | "plugins": [ 31 | "react" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: mariusandra 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ## Package builds 3 | 4 | packages/insights-charts/lib/ 5 | packages/insights-charts/es/ 6 | packages/insights-web/build/ 7 | packages/insights/web-build/ 8 | 9 | .insights/ 10 | 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directory 34 | # Commenting this out is preferred by some people, see 35 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 36 | node_modules 37 | 38 | # Users Environment Variables 39 | .lock-wscript 40 | 41 | # IDEs and editors (shamelessly copied from @angular/cli's .gitignore) 42 | /.idea 43 | .project 44 | .classpath 45 | .c9/ 46 | *.launch 47 | .settings/ 48 | *.sublime-workspace 49 | 50 | # IDE - VSCode 51 | .vscode/* 52 | !.vscode/settings.json 53 | !.vscode/tasks.json 54 | !.vscode/launch.json 55 | !.vscode/extensions.json 56 | 57 | ### Linux ### 58 | *~ 59 | 60 | # temporary files which can be created if a process still has a handle open of a deleted file 61 | .fuse_hidden* 62 | 63 | # KDE directory preferences 64 | .directory 65 | 66 | # Linux trash folder which might appear on any partition or disk 67 | .Trash-* 68 | 69 | # .nfs files are created when an open file is removed but is still being accessed 70 | .nfs* 71 | 72 | ### OSX ### 73 | *.DS_Store 74 | .AppleDouble 75 | .LSOverride 76 | 77 | # Icon must end with two \r 78 | Icon 79 | 80 | 81 | # Thumbnails 82 | ._* 83 | 84 | # Files that might appear in the root of a volume 85 | .DocumentRevisions-V100 86 | .fseventsd 87 | .Spotlight-V100 88 | .TemporaryItems 89 | .Trashes 90 | .VolumeIcon.icns 91 | .com.apple.timemachine.donotpresent 92 | 93 | # Directories potentially created on remote AFP share 94 | .AppleDB 95 | .AppleDesktop 96 | Network Trash Folder 97 | Temporary Items 98 | .apdisk 99 | 100 | ### Windows ### 101 | # Windows thumbnail cache files 102 | Thumbs.db 103 | ehthumbs.db 104 | ehthumbs_vista.db 105 | 106 | # Folder config file 107 | Desktop.ini 108 | 109 | # Recycle Bin used on file shares 110 | $RECYCLE.BIN/ 111 | 112 | # Windows Installer files 113 | *.cab 114 | *.msi 115 | *.msm 116 | *.msp 117 | 118 | # Windows shortcuts 119 | *.lnk 120 | 121 | # Others 122 | data/ 123 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | data/ 31 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceRoot}/server/index.js", 12 | "cwd": "${workspaceRoot}", 13 | "env": { 14 | "NODE_ENV": "development" 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Feathers 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Insights 2 | 3 | Insights is a tool to visually explore a PostgreSQL database, with an emphasis on generating graphs that show business performance over time. 4 | 5 | Think of Google Data Studio or Google Looker, but totally free, self-hosted and without the "Google" part. 6 | 7 | See a [**live demo**](https://demo.insights.sh/) for Widgets Inc, a fictional e-commerce site. 8 | 9 | ![Insights Explorer](https://user-images.githubusercontent.com/53387/74577340-e68a6000-4f8e-11ea-95bf-4682f545cc8f.png) 10 | 11 | ## Important Disclaimer and Security Notice! 12 | 13 | Please be aware that is an extremely early BETA release of Insights, which has not gone through any kind of security audit. 14 | 15 | Use on a live server at your own risk! 16 | 17 | ## Installing 18 | 19 | To install, make sure you have Node 10+ installed and then run: 20 | 21 | ``` 22 | npm install -g insights 23 | insights init 24 | insights start 25 | ``` 26 | 27 | This creates a folder `.insights` which contains all the config and runtime data. 28 | 29 | ## Implemented Features 30 | 31 | * Self Hosted, installed via NPM 32 | * PostgreSQL connection support 33 | * Auto-detect your database schema, including all foreign keys! 34 | * Connect to multiple databases 35 | * Edit the schema and add custom SQL fields right there in the interface! 36 | * Create subsets of your data (e.g. share only a few fields with marketing) 37 | * Data explorer 38 | * Filters on the data 39 | * Time-based graphs 40 | * Split the graph by some column (e.g. new users by country name) 41 | * Keyboard navigation in the sidebar 42 | * Saved views 43 | * Pinned fields 44 | 45 | 46 | ## Coming Soon 47 | 48 | * Embed React or