Enhance service
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import DomainCheck from "./services/DomainCheck"
|
||||
import config from "./config"
|
||||
import { parseServices, createMatcher } from 'utils/urlMatcher'
|
||||
import remoteServices from "./remoteServices"
|
||||
|
||||
const domainCheck = new DomainCheck(config)
|
||||
const services = parseServices(remoteServices)
|
||||
const matcher = createMatcher(services)
|
||||
const { version } = chrome.runtime.getManifest()
|
||||
|
||||
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||
@@ -10,14 +11,14 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||
return
|
||||
}
|
||||
|
||||
const service = domainCheck.match(tab.url)
|
||||
const service = matcher(tab.url)
|
||||
|
||||
if (service) {
|
||||
chrome.storage.sync.get(
|
||||
["subdomain", "apiKey"],
|
||||
({ subdomain, apiKey }) => {
|
||||
const settings = { subdomain, apiKey, version }
|
||||
const payload = { service, settings }
|
||||
const payload = { serviceKey: service.key, settings }
|
||||
chrome.tabs.sendMessage(tabId, { type: "mountBubble", payload }, () => {
|
||||
console.log("bubble mounted")
|
||||
})
|
||||
|
||||
@@ -12,6 +12,14 @@ import { findLastProject, findLastTask, groupedProjectOptions } from "utils"
|
||||
@observer
|
||||
class Bubble extends Component {
|
||||
static propTypes = {
|
||||
service: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
description: PropTypes.string,
|
||||
projectId: PropTypes.string,
|
||||
taskId: PropTypes.string
|
||||
}).isRequired,
|
||||
settings: PropTypes.shape({
|
||||
subdomain: PropTypes.string,
|
||||
apiKey: PropTypes.string,
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
export default {
|
||||
services: [
|
||||
{
|
||||
name: "github",
|
||||
urlPattern: "https://github.com/:org/:repo/pull/:id(/:tab)",
|
||||
description: (document, { org, repo, id }) =>
|
||||
`${org}/${repo}/${id} - ${document
|
||||
.querySelector(".gh-header-title")
|
||||
.textContent.trim()}`
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
import { createElement } from "react"
|
||||
import ReactDOM from "react-dom"
|
||||
import Bubble from "./components/Bubble"
|
||||
import services from "remoteServices"
|
||||
import { createEnhancer } from "utils/urlMatcher"
|
||||
import "../css/main.scss"
|
||||
|
||||
const serviceEnhancer = createEnhancer(window.document)(services)
|
||||
|
||||
chrome.runtime.onMessage.addListener(({ type, payload }) => {
|
||||
switch (type) {
|
||||
case "mountBubble": {
|
||||
@@ -15,20 +19,24 @@ chrome.runtime.onMessage.addListener(({ type, payload }) => {
|
||||
}
|
||||
})
|
||||
|
||||
const mountBubble = ({ service, settings }) => {
|
||||
if (document.getElementById("moco-bx-bubble")) {
|
||||
return
|
||||
const mountBubble = ({ serviceKey, settings }) => {
|
||||
if (!document.getElementById("moco-bx-container")) {
|
||||
const domContainer = document.createElement("div")
|
||||
domContainer.setAttribute("id", "moco-bx-container")
|
||||
document.body.appendChild(domContainer)
|
||||
}
|
||||
|
||||
const domContainer = document.createElement("div")
|
||||
domContainer.setAttribute("id", "moco-bx-container")
|
||||
document.body.appendChild(domContainer)
|
||||
if (!document.getElementById("moco-bx-bubble")) {
|
||||
const domBubble = document.createElement("div")
|
||||
domBubble.setAttribute("id", "moco-bx-bubble")
|
||||
document.body.appendChild(domBubble)
|
||||
}
|
||||
|
||||
const domBubble = document.createElement("div")
|
||||
domBubble.setAttribute("id", "moco-bx-bubble")
|
||||
document.body.appendChild(domBubble)
|
||||
|
||||
ReactDOM.render(createElement(Bubble, { service, settings }), domBubble)
|
||||
const service = serviceEnhancer(serviceKey, window.location.href)
|
||||
ReactDOM.render(
|
||||
createElement(Bubble, { service, settings }),
|
||||
document.getElementById("moco-bx-bubble")
|
||||
)
|
||||
}
|
||||
|
||||
const unmountBubble = () => {
|
||||
|
||||
30
src/js/remoteServices.js
Normal file
30
src/js/remoteServices.js
Normal file
@@ -0,0 +1,30 @@
|
||||
export default {
|
||||
"github-pr": {
|
||||
name: "github",
|
||||
urlPattern: "https://github.com/:org/:repo/pull/:id(/:tab)",
|
||||
id: (document, service, { org, repo, id }) =>
|
||||
[org, repo, service.key, id].join("."),
|
||||
description: (document, service, { org, repo, id }) =>
|
||||
`${org}/${repo}/${id} - ${document
|
||||
.querySelector(".js-issue-title")
|
||||
?.textContent?.trim()}`,
|
||||
projectId: document => {
|
||||
const match = document
|
||||
.querySelector(".js-issue-title")
|
||||
?.textContent.trim()
|
||||
?.match(/^\[(\d+)\]/)
|
||||
return match && match[1]
|
||||
}
|
||||
},
|
||||
|
||||
"github-issue": {
|
||||
name: "github",
|
||||
urlPattern: "https://github.com/:org/:repo/issues/:id",
|
||||
id: (document, service, { org, repo, id }) =>
|
||||
[org, repo, "issue", id].join("."),
|
||||
description: (document, service, { org, repo, id }) =>
|
||||
`${org}/${repo}/${id} - ${document
|
||||
.querySelector(".gh-header-title")
|
||||
.textContent.trim()}`
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import Route from "route-parser"
|
||||
|
||||
class DomainCheck {
|
||||
#services;
|
||||
|
||||
constructor(config) {
|
||||
this.#services = config.services.map(service => ({
|
||||
...service,
|
||||
route: new Route(service.urlPattern),
|
||||
}))
|
||||
}
|
||||
|
||||
#findService = url =>
|
||||
this.#services.find(service => service.route.match(url));
|
||||
|
||||
match(url) {
|
||||
const service = this.#findService(url)
|
||||
|
||||
if (!service) {
|
||||
return false
|
||||
}
|
||||
|
||||
return {
|
||||
...service,
|
||||
match: service.route.match(url),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DomainCheck
|
||||
@@ -14,13 +14,13 @@ const nilToArray = input => input || []
|
||||
|
||||
export const findLastProject = id =>
|
||||
compose(
|
||||
find(pathEq("value", id)),
|
||||
find(pathEq("value", Number(id))),
|
||||
flatMap(get("options"))
|
||||
)
|
||||
|
||||
export const findLastTask = id =>
|
||||
compose(
|
||||
find(pathEq("value", id)),
|
||||
find(pathEq("value", Number(id))),
|
||||
get("tasks")
|
||||
)
|
||||
|
||||
45
src/js/utils/urlMatcher.js
Normal file
45
src/js/utils/urlMatcher.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import Route from "route-parser"
|
||||
import { isFunction, isUndefined, compose, toPairs, map } from "lodash/fp"
|
||||
|
||||
const createEvaluator = args => fnOrValue => {
|
||||
if (isUndefined(fnOrValue)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isFunction(fnOrValue)) {
|
||||
return fnOrValue(...args)
|
||||
}
|
||||
|
||||
return fnOrValue
|
||||
}
|
||||
|
||||
export const parseServices = compose(
|
||||
map(([key, config]) => ({
|
||||
...config,
|
||||
key,
|
||||
route: new Route(config.urlPattern)
|
||||
})),
|
||||
toPairs
|
||||
)
|
||||
|
||||
export const createEnhancer = document => services => (key, url) => {
|
||||
const service = services[key]
|
||||
service.key = key
|
||||
const route = new Route(service.urlPattern)
|
||||
const match = route.match(url)
|
||||
const args = [document, service, match]
|
||||
const evaluate = createEvaluator(args)
|
||||
|
||||
return {
|
||||
...service,
|
||||
key,
|
||||
url,
|
||||
id: evaluate(service.id),
|
||||
description: evaluate(service.description),
|
||||
projectId: evaluate(service.projectId),
|
||||
taskId: evaluate(service.taskId),
|
||||
}
|
||||
}
|
||||
|
||||
export const createMatcher = services => url =>
|
||||
services.find(service => service.route.match(url))
|
||||
Reference in New Issue
Block a user