diff --git a/gatsby-browser.js b/gatsby-browser.js
index bab70167e..a17bd4221 100644
--- a/gatsby-browser.js
+++ b/gatsby-browser.js
@@ -4,9 +4,9 @@
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/
-// You can delete this file if you're not using it
-import wrapWithProvider from './wrap-with-provider'
-export const wrapRootElement = wrapWithProvider
+import 'prismjs/themes/prism-okaidia.css'
+import { wrapElement, initKea } from './kea'
-// gatsby-browser.js
-require('prismjs/themes/prism-okaidia.css')
+initKea(false)
+
+export const wrapRootElement = wrapElement
diff --git a/gatsby-node.js b/gatsby-node.js
index d45f00da9..3df2a4f1a 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -8,3 +8,17 @@
exports.createPages = require('./gatsby/createPages')
exports.onCreateNode = require('./gatsby/onCreateNode')
+
+// Implement the Gatsby API “onCreatePage”. This is
+// called after every page is created.
+exports.onCreatePage = async ({ page, actions }) => {
+ const { createPage } = actions
+ // Only update the `/app` page.
+ if (page.path.match(/^\/plugins/)) {
+ // page.matchPath is a special key that's used for matching pages
+ // with corresponding routes only on the client.
+ page.matchPath = '/plugins/*'
+ // Update the page.
+ createPage(page)
+ }
+}
diff --git a/gatsby-ssr.js b/gatsby-ssr.js
index 78fa62926..76262ee3a 100644
--- a/gatsby-ssr.js
+++ b/gatsby-ssr.js
@@ -5,5 +5,9 @@
*/
// You can delete this file if you're not using it
-import wrapWithProvider from './wrap-with-provider'
-export const wrapRootElement = wrapWithProvider
+import { wrapElement, initKea } from './kea'
+
+export const wrapPageElement = ({ element, props }) => {
+ initKea(true, props.location)
+ return wrapElement({ element })
+}
diff --git a/kea.js b/kea.js
new file mode 100644
index 000000000..3061d40b3
--- /dev/null
+++ b/kea.js
@@ -0,0 +1,13 @@
+import React from 'react'
+import { Provider } from 'react-redux'
+import { getContext, resetContext } from 'kea'
+import { loadersPlugin } from 'kea-loaders'
+import { routerPlugin } from 'kea-router'
+
+export function initKea(isServer = false, location = '') {
+ resetContext({
+ plugins: [loadersPlugin, routerPlugin(isServer ? { location } : {})],
+ })
+}
+
+export const wrapElement = ({ element }) => {element}
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 000000000..043fb614f
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,4 @@
+[[redirects]]
+ from = "/plugins/*"
+ to = "/plugins"
+ status = 200
\ No newline at end of file
diff --git a/package.json b/package.json
index 158243b8e..88d265611 100644
--- a/package.json
+++ b/package.json
@@ -47,8 +47,9 @@
"gatsby-transformer-remark": "^2.8.7",
"gatsby-transformer-sharp": "^2.2.14",
"katex": "^0.12.0",
- "kea": "^2.2.0",
+ "kea": "^2.2.2",
"kea-loaders": "^0.3.0",
+ "kea-router": "^0.5.1",
"node-sass": "^4.14.1",
"prismjs": "^1.21.0",
"query-string": "^6.13.1",
@@ -61,6 +62,7 @@
"react-modal": "^3.11.2",
"react-redux": "^7.2.1",
"react-responsive": "^6.1.2",
+ "redux": "^4.0.5",
"reselect": "^4.0.0",
"typescript": "^4.0.2"
},
diff --git a/src/components/PluginLibrary/PluginModal.tsx b/src/components/PluginLibrary/PluginModal.tsx
index 226354c21..3ccaae33d 100644
--- a/src/components/PluginLibrary/PluginModal.tsx
+++ b/src/components/PluginLibrary/PluginModal.tsx
@@ -8,13 +8,13 @@ import { useActions, useValues } from 'kea'
import { pluginLibraryLogic } from '../../logic/pluginLibraryLogic'
export const PluginModal = () => {
- const { activePlugin, modalOpen, pluginLoading } = useValues(pluginLibraryLogic)
- const { setModalOpen } = useActions(pluginLibraryLogic)
+ const { activePlugin, activePluginName, pluginLoading } = useValues(pluginLibraryLogic)
+ const { openLibrary } = useActions(pluginLibraryLogic)
return (
setModalOpen(false)}
+ isOpen={!!activePluginName}
+ onRequestClose={openLibrary}
className="pluginModalContent"
overlayClassName="modalOverlay"
ariaHideApp={false}
@@ -32,7 +32,7 @@ export const PluginModal = () => {
Learn More
-
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 3db8f301d..959d9ac8b 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,3 +1,5 @@
+import { LibraryPluginType } from 'types'
+
export const unsafeHash = (str: string) => {
var a = 1,
c = 0,
@@ -12,3 +14,10 @@ export const unsafeHash = (str: string) => {
}
return String(a)
}
+
+export const getPluginImageSrc = (plugin: LibraryPluginType) =>
+ plugin.imageLink
+ ? plugin.imageLink
+ : plugin.url.includes('github')
+ ? `https://raw.githubusercontent.com/${plugin.url.split('hub.com/')[1]}/main/logo.png`
+ : null
diff --git a/src/logic/pluginLibraryLogic.js b/src/logic/pluginLibraryLogic.js
index b52ce0fe3..9a13c13f0 100644
--- a/src/logic/pluginLibraryLogic.js
+++ b/src/logic/pluginLibraryLogic.js
@@ -1,38 +1,53 @@
import { kea } from 'kea'
+import { pluginInstallationMd } from '../pages-content/plugin-installation'
+import { getPluginImageSrc } from '../lib/utils'
+
+const toPathName = (pluginName) => pluginName.toLowerCase().replaceAll(' ', '-')
export const pluginLibraryLogic = kea({
actions: {
setFilter: (filter) => ({ filter }),
- setModalOpen: (open) => ({ open }),
setActivePlugin: (activePlugin) => ({ activePlugin }),
- setPluginLoading: (pluginLoading) => ({ pluginLoading }),
+ openLibrary: true,
+ openPlugin: (pluginName) => ({ pluginName }),
+ openPluginPath: (pathname) => ({ pathname }),
},
- reducers: {
+ reducers: () => ({
filter: [
'all',
{
setFilter: (_, { filter }) => filter,
},
],
- modalOpen: [
- false,
- {
- setModalOpen: (_, { open }) => open,
- },
- ],
activePlugin: [
{},
{
setActivePlugin: (_, { activePlugin }) => activePlugin,
},
],
+ activePluginName: [
+ '',
+ {
+ openPlugin: (_, { pluginName }) => pluginName,
+ openLibrary: () => '',
+ },
+ ],
+ pluginPathname: [
+ '',
+ {
+ openPluginPath: (_, { pathname }) => pathname,
+ openPlugin: (_, { pluginName }) => toPathName(pluginName),
+ openLibrary: () => '',
+ },
+ ],
pluginLoading: [
false,
{
- setPluginLoading: (_, { pluginLoading }) => pluginLoading,
+ openPlugin: () => true,
+ setActivePlugin: () => false,
},
],
- },
+ }),
loaders: () => ({
plugins: [
[],
@@ -52,6 +67,11 @@ export const pluginLibraryLogic = kea({
(plugins, filter) =>
plugins.filter((p) => p.displayOnWebsiteLib && (filter === 'all' || filter === p.type)),
],
+ pluginMatch: [
+ (s) => [s.pluginPathname, s.filteredPlugins],
+ (pluginPathname, filteredPlugins) =>
+ filteredPlugins.find((plugin) => toPathName(plugin.name) === pluginPathname),
+ ],
},
events: ({ actions }) => ({
afterMount: () => {
@@ -61,4 +81,54 @@ export const pluginLibraryLogic = kea({
}
},
}),
+ listeners: ({ values, actions }) => ({
+ openPlugin: async ({ pluginName }) => {
+ const { setActivePlugin } = actions
+ let plugin = values.filteredPlugins.filter((plugin) => plugin.name === pluginName)[0]
+ let markdown = `# ${plugin.name} \n ${plugin.description} \n ${pluginInstallationMd}`
+ if (plugin.url.includes('github.com/')) {
+ try {
+ const response = await window.fetch(
+ `https://raw.githubusercontent.com/${plugin.url.split('github.com/')[1]}/main/README.md`
+ )
+ if (response.status === 200) {
+ markdown = await response.text()
+ }
+ } catch (e) {
+ // can't load the readme, revert to default text
+ }
+ }
+ if (!markdown.includes('Installation')) {
+ markdown += pluginInstallationMd
+ }
+ plugin['markdown'] = markdown.split(/!\[.*\]\(.*\)/).join('')
+ plugin['imageSrc'] = getPluginImageSrc(plugin)
+ setActivePlugin(plugin)
+ },
+ loadPluginsSuccess: () => {
+ const { openPluginPath } = actions
+ openPluginPath(window.location.pathname.split('/plugins/')[1])
+ },
+ openPluginPath: () => {
+ const { pluginMatch, pluginsLoading } = values
+ if (pluginsLoading) {
+ return
+ }
+ if (pluginMatch) {
+ actions.openPlugin(pluginMatch.name)
+ } else {
+ actions.openLibrary()
+ }
+ },
+ }),
+ actionToUrl: () => ({
+ openLibrary: () => '/plugins/',
+ openPlugin: ({ pluginName }) => `/plugins/${toPathName(pluginName)}`,
+ openPluginPath: ({ pathname }) => `/plugins/${pathname}`,
+ }),
+ urlToAction: ({ actions }) => ({
+ '/plugins': () => actions.openLibrary(),
+ '/plugins/': () => actions.openLibrary(),
+ '/plugins/:pathname': ({ pathname }) => actions.openPluginPath(pathname),
+ }),
})
diff --git a/src/pages/plugins.js b/src/pages/plugins.js
index 67ba303ee..4f16a191d 100644
--- a/src/pages/plugins.js
+++ b/src/pages/plugins.js
@@ -7,43 +7,14 @@ import { useActions, useValues } from 'kea'
import { pluginLibraryLogic } from '../logic/pluginLibraryLogic'
import { Spin } from 'antd'
import { PluginModal } from '../components/PluginLibrary/PluginModal'
-import { pluginInstallationMd } from '../pages-content/plugin-installation'
+import { getPluginImageSrc } from '../lib/utils'
import './styles/plugin-library.scss'
const { TabPane } = Tabs
export const PluginLibraryPage = () => {
const { filteredPlugins, filter } = useValues(pluginLibraryLogic)
- const { setFilter, setModalOpen, setActivePlugin, setPluginLoading } = useActions(pluginLibraryLogic)
-
- const handlePluginClick = async (e, plugin) => {
- setPluginLoading(true)
- setModalOpen(true)
- let markdown = `# ${plugin.name} \n ${plugin.description} \n ${pluginInstallationMd}`
- if (plugin.url.includes('github')) {
- e.stopPropagation()
- const response = await window.fetch(
- `https://raw.githubusercontent.com/${plugin.url.split('hub.com/')[1]}/main/README.md`
- )
- if (response.status === 200) {
- markdown = await response.text()
- }
- }
- if (!markdown.includes('Installation')) {
- markdown += pluginInstallationMd
- }
- plugin['markdown'] = markdown.split(/!\[.*\]\(.*\)/).join('')
- plugin['imageSrc'] = getPluginImageSrc(plugin)
- setActivePlugin(plugin)
- setPluginLoading(false)
- }
-
- const getPluginImageSrc = (plugin) =>
- plugin.imageLink
- ? plugin.imageLink
- : plugin.url.includes('github')
- ? `https://raw.githubusercontent.com/${plugin.url.split('hub.com/')[1]}/main/logo.png`
- : null
+ const { setFilter, openPlugin } = useActions(pluginLibraryLogic)
return (
@@ -72,9 +43,7 @@ export const PluginLibraryPage = () => {
link={plugin.url}
imageSrc={getPluginImageSrc(plugin)}
isCommunityPlugin={plugin.maintainer === 'community'}
- onClick={(e) => {
- handlePluginClick(e, { ...plugin })
- }}
+ onClick={() => openPlugin(plugin.name)}
/>
))
) : (
diff --git a/src/types.ts b/src/types.ts
index 64d6ff79c..b0f8d3ca4 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -12,3 +12,12 @@ export interface FeatureComparisonData {
mixpanel: boolean
heap: boolean
}
+
+export interface LibraryPluginType {
+ id: number
+ name: string
+ description?: string
+ url: string
+ imageLink: string
+ maintainer?: string
+}
diff --git a/wrap-with-provider.js b/wrap-with-provider.js
deleted file mode 100644
index 89d44aa30..000000000
--- a/wrap-with-provider.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-import { Provider } from 'react-redux'
-import { getContext, resetContext } from 'kea'
-import { loadersPlugin } from 'kea-loaders'
-
-resetContext({
- plugins: [loadersPlugin],
-})
-
-// eslint-disable-next-line react/display-name,react/prop-types
-export default ({ element }) => {element}
diff --git a/yarn.lock b/yarn.lock
index 731ece09c..64d28eca6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10617,10 +10617,17 @@ kea-loaders@^0.3.0:
resolved "https://registry.yarnpkg.com/kea-loaders/-/kea-loaders-0.3.0.tgz#876a838cd65da4547d2611d8e180e7d867e2a657"
integrity sha512-aXrUjQf/GdJVDQqLtTWoY4gF1F+dTXv5U1LfCLffPhgrWRYHGTnaBV/K6pWxy1Qh+vMbepy80Nx9hFiK1owtHw==
-kea@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/kea/-/kea-2.2.0.tgz#1ba4a174a53880cca8002a67cf62b19b30d09702"
- integrity sha512-IzgTC6SC89wTLfiBMPlduG4r4YanxONYK4werz8RMZxPvcYw4XEEK8xQJguwVYtLCEGm4x5YiLCubGqGfRcbEw==
+kea-router@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/kea-router/-/kea-router-0.5.1.tgz#de6490628e16dd67702ee329e1912721b709efa2"
+ integrity sha512-qKAnT5TQxSWtkTifoZgRK+iQBtHCgKl11NoBldUmfunDo5eUtiYSK8rt7O123+fIZzXyg6PLQvJCRsSHf3Z3eA==
+ dependencies:
+ url-pattern "^1.0.3"
+
+kea@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/kea/-/kea-2.2.2.tgz#2a58ca5089b95fcc463224e6d08d95f05fac7af7"
+ integrity sha512-9qtmm/J0kz+wSrST1ljsxuoKoIpAhynkV0Rht8OQkAHvX7KEtABNVVdX/r6AgK1BOsjACF4t6tcMnYXG51GEZQ==
keyv@3.0.0:
version "3.0.0"
@@ -17688,6 +17695,11 @@ url-parse@^1.1.8, url-parse@^1.4.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
+url-pattern@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/url-pattern/-/url-pattern-1.0.3.tgz#0409292471b24f23c50d65a47931793d2b5acfc1"
+ integrity sha1-BAkpJHGyTyPFDWWkeTF5PStaz8E=
+
url-to-options@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"