mirror of
https://github.com/BillyOutlast/posthog.com.git
synced 2026-02-04 03:11:21 +01:00
Refactor Plugin Library Logic (#884)
* Refactor Plugin Library Logic * add kea router * update types * add dynamic routing * upgrade kea * kea SSR with location for router * fix random undefined bug * wip changes * use selector * fix build fail * add netlify config * fix back button * don't redirect to root if still loading plugins * refactor actions and logic Co-authored-by: Marius Andra <marius.andra@gmail.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
13
kea.js
Normal file
13
kea.js
Normal file
@@ -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 }) => <Provider store={getContext().store}>{element}</Provider>
|
||||
4
netlify.toml
Normal file
4
netlify.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[[redirects]]
|
||||
from = "/plugins/*"
|
||||
to = "/plugins"
|
||||
status = 200
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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 (
|
||||
<Modal
|
||||
isOpen={modalOpen}
|
||||
onRequestClose={() => setModalOpen(false)}
|
||||
isOpen={!!activePluginName}
|
||||
onRequestClose={openLibrary}
|
||||
className="pluginModalContent"
|
||||
overlayClassName="modalOverlay"
|
||||
ariaHideApp={false}
|
||||
@@ -32,7 +32,7 @@ export const PluginModal = () => {
|
||||
Learn More <ExportOutlined />
|
||||
</a>
|
||||
</div>
|
||||
<Button icon="close" onClick={() => setModalOpen(false)} className="modalClose" />
|
||||
<Button icon="close" onClick={openLibrary} className="modalClose" />
|
||||
</>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -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 (
|
||||
<Layout>
|
||||
@@ -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)}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 }) => <Provider store={getContext().store}>{element}</Provider>
|
||||
20
yarn.lock
20
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"
|
||||
|
||||
Reference in New Issue
Block a user