Refactor
This commit is contained in:
@@ -11,6 +11,11 @@
|
|||||||
.moco-bx-options {
|
.moco-bx-options {
|
||||||
padding: 0rem 2rem 2rem;
|
padding: 0rem 2rem 2rem;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $blue;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
}
|
}
|
||||||
@@ -45,9 +50,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__host-overrides {
|
&__host-overrides {
|
||||||
padding-bottom: 1rem;
|
margin-bottom: 1.5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ class App extends Component {
|
|||||||
chrome.runtime.onMessage.removeListener(this.handleSetFormErrors)
|
chrome.runtime.onMessage.removeListener(this.handleSetFormErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = event => {
|
handleChange = (event) => {
|
||||||
const { projects } = this.props
|
const { projects } = this.props
|
||||||
const {
|
const {
|
||||||
target: { name, value },
|
target: { name, value },
|
||||||
@@ -133,11 +133,11 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSelectDate = date => {
|
handleSelectDate = (date) => {
|
||||||
this.changeset.date = formatDate(date)
|
this.changeset.date = formatDate(date)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleStopTimer = timedActivity => {
|
handleStopTimer = (timedActivity) => {
|
||||||
const { service } = this.props
|
const { service } = this.props
|
||||||
|
|
||||||
chrome.runtime.sendMessage({
|
chrome.runtime.sendMessage({
|
||||||
@@ -146,7 +146,7 @@ class App extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = event => {
|
handleSubmit = (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const { service } = this.props
|
const { service } = this.props
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ class App extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown = event => {
|
handleKeyDown = (event) => {
|
||||||
if (event.keyCode === 27) {
|
if (event.keyCode === 27) {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
chrome.runtime.sendMessage({ type: "closePopup" })
|
chrome.runtime.sendMessage({ type: "closePopup" })
|
||||||
@@ -204,7 +204,7 @@ class App extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Spring native from={{ opacity: 0 }} to={{ opacity: 1 }} config={config.stiff}>
|
<Spring native from={{ opacity: 0 }} to={{ opacity: 1 }} config={config.stiff}>
|
||||||
{props => (
|
{(props) => (
|
||||||
<animated.div className="moco-bx-app-container" style={props}>
|
<animated.div className="moco-bx-app-container" style={props}>
|
||||||
<Header subdomain={subdomain} />
|
<Header subdomain={subdomain} />
|
||||||
<Observer>
|
<Observer>
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { observable } from "mobx"
|
|||||||
import { observer } from "mobx-react"
|
import { observer } from "mobx-react"
|
||||||
import { isChrome, getSettings, setStorage } from "utils/browser"
|
import { isChrome, getSettings, setStorage } from "utils/browser"
|
||||||
import ApiClient from "api/Client"
|
import ApiClient from "api/Client"
|
||||||
import remoteServices from "../remoteServices"
|
import { pipe, toPairs, fromPairs, map } from "lodash/fp"
|
||||||
import { pipe, toPairs, fromPairs, prop, map, sortedUniqBy, filter } from "lodash/fp"
|
|
||||||
|
|
||||||
function upperCaseFirstLetter(input) {
|
function upperCaseFirstLetter(input) {
|
||||||
return input[0].toUpperCase() + input.slice(1)
|
return input[0].toUpperCase() + input.slice(1)
|
||||||
@@ -14,15 +13,6 @@ function removePathFromUrl(url) {
|
|||||||
return url.replace(/(\.[a-z]+)\/.*$/, "$1")
|
return url.replace(/(\.[a-z]+)\/.*$/, "$1")
|
||||||
}
|
}
|
||||||
|
|
||||||
const overridableRemoveServices = pipe(
|
|
||||||
filter(prop("allowHostOverride")),
|
|
||||||
map((remoteService) => ({
|
|
||||||
name: remoteService.name,
|
|
||||||
host: remoteService.host,
|
|
||||||
})),
|
|
||||||
sortedUniqBy("name"),
|
|
||||||
)(remoteServices)
|
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class Options extends Component {
|
class Options extends Component {
|
||||||
@observable subdomain = ""
|
@observable subdomain = ""
|
||||||
@@ -33,10 +23,10 @@ class Options extends Component {
|
|||||||
@observable showHostOverrideOptions = false
|
@observable showHostOverrideOptions = false
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
getSettings(false).then((storeData) => {
|
getSettings(false).then((settings) => {
|
||||||
this.subdomain = storeData.subdomain || ""
|
this.subdomain = settings.subdomain || ""
|
||||||
this.apiKey = storeData.apiKey || ""
|
this.apiKey = settings.apiKey || ""
|
||||||
this.hostOverrides = storeData.hostOverrides
|
this.hostOverrides = settings.hostOverrides
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,27 +122,42 @@ class Options extends Component {
|
|||||||
{!this.showHostOverrideOptions && (
|
{!this.showHostOverrideOptions && (
|
||||||
<div className="moco-bx-options__host-overrides">
|
<div className="moco-bx-options__host-overrides">
|
||||||
<a href="#" className="moco-bx-btn__secondary" onClick={this.toggleHostOverrideOptions}>
|
<a href="#" className="moco-bx-btn__secondary" onClick={this.toggleHostOverrideOptions}>
|
||||||
URLs für Dienste anpassen?
|
Service-URLs überschreiben?
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{this.showHostOverrideOptions && (
|
{this.showHostOverrideOptions && (
|
||||||
<div style={{ marginBottom: "1rem" }}>
|
<div style={{ marginBottom: "1.5rem" }}>
|
||||||
<h3>URLs für Dienste</h3>
|
<h3 style={{ marginBottom: 0 }}>Service-URLs</h3>
|
||||||
{overridableRemoveServices.map((remoteService) => (
|
<small>
|
||||||
<div className="form-group" key={remoteService.name} style={{ margin: "0.5rem 0" }}>
|
Doppelpunkt für Platzhalter verwenden, z.B.{" "}
|
||||||
|
<span style={{ backgroundColor: "rgba(100, 100, 100, 0.1)" }}>:org</span>. Siehe{" "}
|
||||||
|
<a
|
||||||
|
href="https://github.com/hundertzehn/mocoapp-browser-extension#remote-service-configuration"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Online-Doku
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</small>
|
||||||
|
<br />
|
||||||
|
{pipe(
|
||||||
|
Object.entries,
|
||||||
|
Array.from,
|
||||||
|
)(this.hostOverrides).map(([name, host]) => (
|
||||||
|
<div className="form-group" key={name} style={{ margin: "0.5rem 0" }}>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<span
|
<span
|
||||||
className="input-group-addon input-group-addon--left"
|
className="input-group-addon input-group-addon--left"
|
||||||
style={{ display: "inline-block", width: "70px", textAlign: "left" }}
|
style={{ display: "inline-block", width: "70px", textAlign: "left" }}
|
||||||
>
|
>
|
||||||
{upperCaseFirstLetter(remoteService.name)}
|
{upperCaseFirstLetter(name)}
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name={remoteService.name}
|
name={name}
|
||||||
value={this.hostOverrides[remoteService.name] || ""}
|
value={host}
|
||||||
placeholder={remoteService.host}
|
|
||||||
onKeyDown={this.handleInputKeyDown}
|
onKeyDown={this.handleInputKeyDown}
|
||||||
onChange={this.handleChangeHostOverrides}
|
onChange={this.handleChangeHostOverrides}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import "mobx-react-lite/batchingForReactDom"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import ReactDOM from "react-dom"
|
import ReactDOM from "react-dom"
|
||||||
import Options from "./components/Options"
|
import Options from "./components/Options"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import "mobx-react-lite/batchingForReactDom"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import ReactDOM from "react-dom"
|
import ReactDOM from "react-dom"
|
||||||
import App from "./components/App"
|
import App from "./components/App"
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export default {
|
|||||||
name: "asana",
|
name: "asana",
|
||||||
host: "https://app.asana.com",
|
host: "https://app.asana.com",
|
||||||
urlPatterns: [
|
urlPatterns: [
|
||||||
[/^__HOST__\/0\/([^/]+)\/(\d+)/, ["domainUserId", "id"]],
|
[/^:host:\/0\/([^/]+)\/(\d+)/, ["domainUserId", "id"]],
|
||||||
[/^__HOST__\/0\/search\/([^/]+)\/(\d+)/, ["domainUserId", "id"]],
|
[/^:host:\/0\/search\/([^/]+)\/(\d+)/, ["domainUserId", "id"]],
|
||||||
],
|
],
|
||||||
description: (document) =>
|
description: (document) =>
|
||||||
document.querySelector(".ItemRow--highlighted textarea")?.textContent?.trim() ||
|
document.querySelector(".ItemRow--highlighted textarea")?.textContent?.trim() ||
|
||||||
@@ -23,32 +23,32 @@ export default {
|
|||||||
"github-pr": {
|
"github-pr": {
|
||||||
name: "github",
|
name: "github",
|
||||||
host: "https://github.com",
|
host: "https://github.com",
|
||||||
urlPatterns: ["__HOST__/:org/:repo/pull/:id(/:tab)"],
|
urlPatterns: [":host:/:org/:repo/pull/:id(/:tab)"],
|
||||||
id: (document, service, { org, repo, id }) => [service.key, org, repo, id].join("."),
|
id: (document, service, { org, repo, id }) => [service.key, org, repo, id].join("."),
|
||||||
description: (document) => document.querySelector(".js-issue-title")?.textContent?.trim(),
|
description: (document) => document.querySelector(".js-issue-title")?.textContent?.trim(),
|
||||||
projectId: projectIdentifierBySelector(".js-issue-title"),
|
projectId: projectIdentifierBySelector(".js-issue-title"),
|
||||||
allowHostOverride: true,
|
allowHostOverride: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
"github-issue": {
|
"github-issue": {
|
||||||
name: "github",
|
name: "github",
|
||||||
host: "https://github.com",
|
host: "https://github.com",
|
||||||
urlPatterns: ["__HOST__/:org/:repo/issues/:id"],
|
urlPatterns: [":host:/:org/:repo/issues/:id"],
|
||||||
id: (document, service, { org, repo, id }) => [service.key, org, repo, id].join("."),
|
id: (document, service, { org, repo, id }) => [service.key, org, repo, id].join("."),
|
||||||
description: (document, service, { org, repo, id }) =>
|
description: (document, service, { org, repo, id }) =>
|
||||||
document.querySelector(".js-issue-title")?.textContent?.trim(),
|
document.querySelector(".js-issue-title")?.textContent?.trim(),
|
||||||
projectId: projectIdentifierBySelector(".js-issue-title"),
|
projectId: projectIdentifierBySelector(".js-issue-title"),
|
||||||
allowHostOverride: true,
|
allowHostOverride: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
jira: {
|
jira: {
|
||||||
name: "jira",
|
name: "jira",
|
||||||
host: "https://:org.atlassian.net",
|
host: "https://:org.atlassian.net",
|
||||||
urlPatterns: [
|
urlPatterns: [
|
||||||
"__HOST__/secure/RapidBoard.jspa",
|
":host:/secure/RapidBoard.jspa",
|
||||||
"__HOST__/browse/:id",
|
":host:/browse/:id",
|
||||||
"__HOST__/jira/software/projects/:projectId/boards/:board",
|
":host:/jira/software/projects/:projectId/boards/:board",
|
||||||
"__HOST__/jira/software/projects/:projectId/boards/:board/backlog",
|
":host:/jira/software/projects/:projectId/boards/:board/backlog",
|
||||||
],
|
],
|
||||||
queryParams: {
|
queryParams: {
|
||||||
id: "selectedIssue",
|
id: "selectedIssue",
|
||||||
@@ -69,7 +69,7 @@ export default {
|
|||||||
meistertask: {
|
meistertask: {
|
||||||
name: "meistertask",
|
name: "meistertask",
|
||||||
host: "https://www.meistertask.com",
|
host: "https://www.meistertask.com",
|
||||||
urlPatterns: ["/app/task/:id/:slug"],
|
urlPatterns: [":host:/app/task/:id/:slug"],
|
||||||
description: (document) => {
|
description: (document) => {
|
||||||
const json = document.getElementById("mt-toggl-data")?.dataset?.togglJson || "{}"
|
const json = document.getElementById("mt-toggl-data")?.dataset?.togglJson || "{}"
|
||||||
const data = JSON.parse(json)
|
const data = JSON.parse(json)
|
||||||
@@ -87,7 +87,7 @@ export default {
|
|||||||
trello: {
|
trello: {
|
||||||
name: "trello",
|
name: "trello",
|
||||||
host: "https://trello.com",
|
host: "https://trello.com",
|
||||||
urlPatterns: ["__HOST__/c/:id/:title"],
|
urlPatterns: [":host:/c/:id/:title"],
|
||||||
description: (document, service, { title }) =>
|
description: (document, service, { title }) =>
|
||||||
document.querySelector(".js-title-helper")?.textContent?.trim() || title,
|
document.querySelector(".js-title-helper")?.textContent?.trim() || title,
|
||||||
projectId: (document) =>
|
projectId: (document) =>
|
||||||
@@ -99,7 +99,7 @@ export default {
|
|||||||
youtrack: {
|
youtrack: {
|
||||||
name: "youtrack",
|
name: "youtrack",
|
||||||
host: "https://:org.myjetbrains.com",
|
host: "https://:org.myjetbrains.com",
|
||||||
urlPatterns: ["__HOST__/youtrack/issue/:id"],
|
urlPatterns: [":host:/youtrack/issue/:id"],
|
||||||
description: (document) => document.querySelector("yt-issue-body h1")?.textContent?.trim(),
|
description: (document) => document.querySelector("yt-issue-body h1")?.textContent?.trim(),
|
||||||
projectId: projectIdentifierBySelector("yt-issue-body h1"),
|
projectId: projectIdentifierBySelector("yt-issue-body h1"),
|
||||||
allowHostOverride: true,
|
allowHostOverride: true,
|
||||||
@@ -109,8 +109,8 @@ export default {
|
|||||||
name: "wrike",
|
name: "wrike",
|
||||||
host: "https://www.wrike.com",
|
host: "https://www.wrike.com",
|
||||||
urlPatterns: [
|
urlPatterns: [
|
||||||
"__HOST__/workspace.htm#path=mywork",
|
":host:/workspace.htm#path=mywork",
|
||||||
"__HOST__/workspace.htm#path=folder",
|
":host:/workspace.htm#path=folder",
|
||||||
"https\\://app-eu.wrike.com/workspace.htm#path=mywork",
|
"https\\://app-eu.wrike.com/workspace.htm#path=mywork",
|
||||||
"https\\://app-eu.wrike.com/workspace.htm#path=folder",
|
"https\\://app-eu.wrike.com/workspace.htm#path=folder",
|
||||||
],
|
],
|
||||||
@@ -125,7 +125,7 @@ export default {
|
|||||||
wunderlist: {
|
wunderlist: {
|
||||||
name: "wunderlist",
|
name: "wunderlist",
|
||||||
host: "https://www.wunderlist.com",
|
host: "https://www.wunderlist.com",
|
||||||
urlPatterns: ["__HOST__/(webapp)#/tasks/:id(/*)"],
|
urlPatterns: [":host:/(webapp)#/tasks/:id(/*)"],
|
||||||
description: (document) =>
|
description: (document) =>
|
||||||
document
|
document
|
||||||
.querySelector(".taskItem.selected .taskItem-titleWrapper-title")
|
.querySelector(".taskItem.selected .taskItem-titleWrapper-title")
|
||||||
@@ -138,8 +138,8 @@ export default {
|
|||||||
name: "gitlab",
|
name: "gitlab",
|
||||||
host: "https://gitlab.com",
|
host: "https://gitlab.com",
|
||||||
urlPatterns: [
|
urlPatterns: [
|
||||||
"__HOST__/:org/:group/:projectId/-/merge_requests/:id",
|
":host:/:org/:group/:projectId/-/merge_requests/:id",
|
||||||
"__HOST__/:org/:projectId/-/merge_requests/:id",
|
":host:/:org/:projectId/-/merge_requests/:id",
|
||||||
],
|
],
|
||||||
description: (document, service, { id }) => {
|
description: (document, service, { id }) => {
|
||||||
const title = document.querySelector("h2.title")?.textContent?.trim()
|
const title = document.querySelector("h2.title")?.textContent?.trim()
|
||||||
@@ -152,8 +152,8 @@ export default {
|
|||||||
name: "gitlab",
|
name: "gitlab",
|
||||||
host: "https://gitlab.com",
|
host: "https://gitlab.com",
|
||||||
urlPatterns: [
|
urlPatterns: [
|
||||||
"__HOST__/:org/:group/:projectId/-/issues/:id",
|
":host:/:org/:group/:projectId/-/issues/:id",
|
||||||
"__HOST__/:org/:projectId/-/issues/:id",
|
":host:/:org/:projectId/-/issues/:id",
|
||||||
],
|
],
|
||||||
description: (document, service, { id }) => {
|
description: (document, service, { id }) => {
|
||||||
const title = document.querySelector("h2.title")?.textContent?.trim()
|
const title = document.querySelector("h2.title")?.textContent?.trim()
|
||||||
|
|||||||
@@ -1,36 +1,46 @@
|
|||||||
import { head } from "lodash/fp"
|
import { head, pick, reduce, filter, prop, pipe } from "lodash/fp"
|
||||||
|
import remoteServices from "../remoteServices"
|
||||||
|
|
||||||
|
const DEFAULT_SUBDOMAIN = "unset"
|
||||||
|
|
||||||
export const isChrome = () => typeof browser === "undefined" && chrome
|
export const isChrome = () => typeof browser === "undefined" && chrome
|
||||||
export const isFirefox = () => typeof browser !== "undefined" && chrome
|
export const isFirefox = () => typeof browser !== "undefined" && chrome
|
||||||
|
|
||||||
const DEFAULT_SUBDOMAIN = "unset"
|
export const defaultHostOverrides = pipe(
|
||||||
const DEFAULT_HOST_OVERRIDES = {
|
filter(prop("allowHostOverride")),
|
||||||
github: "https://github.com",
|
reduce((acc, remoteService) => {
|
||||||
gitlab: "https://gitlab.com",
|
acc[remoteService.name] = remoteService.host
|
||||||
jira: "https://:org.atlassian.net",
|
return acc
|
||||||
youtrack: "https://:org.myjetbrains.com",
|
}, {}),
|
||||||
}
|
)(remoteServices)
|
||||||
|
|
||||||
|
// We pick only the keys defined in `defaultHostOverrides`, so that
|
||||||
|
// deleted host overrides get cleared from the settings
|
||||||
|
const getHostOverrides = (settings) => ({
|
||||||
|
...defaultHostOverrides,
|
||||||
|
...pick(Object.keys(defaultHostOverrides), settings.hostOverrides || {}),
|
||||||
|
})
|
||||||
|
|
||||||
export const getSettings = (withDefaultSubdomain = true) => {
|
export const getSettings = (withDefaultSubdomain = true) => {
|
||||||
const keys = ["subdomain", "apiKey", "settingTimeTrackingHHMM", "hostOverrides"]
|
const keys = ["subdomain", "apiKey", "settingTimeTrackingHHMM", "hostOverrides"]
|
||||||
const { version } = chrome.runtime.getManifest()
|
const { version } = chrome.runtime.getManifest()
|
||||||
if (isChrome()) {
|
if (isChrome()) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.storage.sync.get(keys, (data) => {
|
chrome.storage.sync.get(keys, (settings) => {
|
||||||
if (withDefaultSubdomain) {
|
if (withDefaultSubdomain) {
|
||||||
data.subdomain = data.subdomain || DEFAULT_SUBDOMAIN
|
settings.subdomain = settings.subdomain || DEFAULT_SUBDOMAIN
|
||||||
}
|
}
|
||||||
data.hostOverrides = { ...DEFAULT_HOST_OVERRIDES, ...(data.hostOverrides || {}) }
|
settings.hostOverrides = getHostOverrides(settings)
|
||||||
resolve({ ...data, version })
|
resolve({ ...settings, version })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return browser.storage.sync.get(keys).then((data) => {
|
return browser.storage.sync.get(keys).then((settings) => {
|
||||||
if (withDefaultSubdomain) {
|
if (withDefaultSubdomain) {
|
||||||
data.subdomain = data.subdomain || DEFAULT_SUBDOMAIN
|
settings.subdomain = settings.subdomain || DEFAULT_SUBDOMAIN
|
||||||
}
|
}
|
||||||
data.hostOverrides = { ...DEFAULT_HOST_OVERRIDES, ...(data.hostOverrides || {}) }
|
settings.hostOverrides = getHostOverrides(settings)
|
||||||
return { ...data, version }
|
return { ...settings, version }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,41 +17,30 @@ import {
|
|||||||
import { startOfWeek, endOfWeek } from "date-fns"
|
import { startOfWeek, endOfWeek } from "date-fns"
|
||||||
import { format } from "date-fns"
|
import { format } from "date-fns"
|
||||||
|
|
||||||
const nilToArray = input => input || []
|
const nilToArray = (input) => input || []
|
||||||
|
|
||||||
export const ERROR_UNAUTHORIZED = "unauthorized"
|
export const ERROR_UNAUTHORIZED = "unauthorized"
|
||||||
export const ERROR_UPGRADE_REQUIRED = "upgrade-required"
|
export const ERROR_UPGRADE_REQUIRED = "upgrade-required"
|
||||||
export const ERROR_UNKNOWN = "unknown"
|
export const ERROR_UNKNOWN = "unknown"
|
||||||
|
|
||||||
export const noop = () => null
|
export const noop = () => null
|
||||||
export const asArray = input => (Array.isArray(input) ? input : [input])
|
export const asArray = (input) => (Array.isArray(input) ? input : [input])
|
||||||
|
|
||||||
export const findProjectBy = prop => val => projects => {
|
export const findProjectBy = (prop) => (val) => (projects) => {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return compose(
|
return compose(find(pathEq(prop, val)), flatMap(get("options")))(projects)
|
||||||
find(pathEq(prop, val)),
|
|
||||||
flatMap(get("options")),
|
|
||||||
)(projects)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const findProjectByIdentifier = findProjectBy("identifier")
|
export const findProjectByIdentifier = findProjectBy("identifier")
|
||||||
export const findProjectByValue = findProjectBy("value")
|
export const findProjectByValue = findProjectBy("value")
|
||||||
|
|
||||||
export const findTask = id =>
|
export const findTask = (id) => compose(find(pathEq("value", Number(id))), get("tasks"))
|
||||||
compose(
|
|
||||||
find(pathEq("value", Number(id))),
|
|
||||||
get("tasks"),
|
|
||||||
)
|
|
||||||
|
|
||||||
export const defaultTask = tasks =>
|
export const defaultTask = (tasks) =>
|
||||||
compose(
|
compose(defaultTo(head(tasks)), find(pathEq("isDefault", true)), nilToArray)(tasks)
|
||||||
defaultTo(head(tasks)),
|
|
||||||
find(pathEq("isDefault", true)),
|
|
||||||
nilToArray,
|
|
||||||
)(tasks)
|
|
||||||
|
|
||||||
function taskOptions(tasks) {
|
function taskOptions(tasks) {
|
||||||
return tasks.map(({ id, name, billable, default: isDefault }) => ({
|
return tasks.map(({ id, name, billable, default: isDefault }) => ({
|
||||||
@@ -63,7 +52,7 @@ function taskOptions(tasks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function projectOptions(projects) {
|
export function projectOptions(projects) {
|
||||||
return projects.map(project => ({
|
return projects.map((project) => ({
|
||||||
value: project.id,
|
value: project.id,
|
||||||
label: project.intern ? `(${project.name})` : project.name,
|
label: project.intern ? `(${project.name})` : project.name,
|
||||||
identifier: project.identifier,
|
identifier: project.identifier,
|
||||||
@@ -82,17 +71,9 @@ export const groupedProjectOptions = compose(
|
|||||||
nilToArray,
|
nilToArray,
|
||||||
)
|
)
|
||||||
|
|
||||||
export const serializeProps = attrs =>
|
export const serializeProps = (attrs) => compose(mapValues(JSON.stringify), pick(attrs))
|
||||||
compose(
|
|
||||||
mapValues(JSON.stringify),
|
|
||||||
pick(attrs),
|
|
||||||
)
|
|
||||||
|
|
||||||
export const parseProps = attrs =>
|
export const parseProps = (attrs) => compose(mapValues(JSON.parse), pick(attrs))
|
||||||
compose(
|
|
||||||
mapValues(JSON.parse),
|
|
||||||
pick(attrs),
|
|
||||||
)
|
|
||||||
|
|
||||||
export const trace = curry((tag, value) => {
|
export const trace = curry((tag, value) => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@@ -101,13 +82,13 @@ export const trace = curry((tag, value) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const weekStartsOn = 1
|
export const weekStartsOn = 1
|
||||||
export const formatDate = date => format(date, "yyyy-MM-dd")
|
export const formatDate = (date) => format(date, "yyyy-MM-dd")
|
||||||
export const getStartOfWeek = () => startOfWeek(new Date(), { weekStartsOn })
|
export const getStartOfWeek = () => startOfWeek(new Date(), { weekStartsOn })
|
||||||
export const getEndOfWeek = () => endOfWeek(new Date(), { weekStartsOn })
|
export const getEndOfWeek = () => endOfWeek(new Date(), { weekStartsOn })
|
||||||
|
|
||||||
export const extensionSettingsUrl = () => `chrome://extensions/?id=${chrome.runtime.id}`
|
export const extensionSettingsUrl = () => `chrome://extensions/?id=${chrome.runtime.id}`
|
||||||
|
|
||||||
export const extractAndSetTag = changeset => {
|
export const extractAndSetTag = (changeset) => {
|
||||||
let { description } = changeset
|
let { description } = changeset
|
||||||
const match = description.match(/^#(\S+)/)
|
const match = description.match(/^#(\S+)/)
|
||||||
if (!match) {
|
if (!match) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import UrlPattern from "url-pattern"
|
import UrlPattern from "url-pattern"
|
||||||
import { isFunction, isUndefined, compose, toPairs, map, pipe, isNil, convert } from "lodash/fp"
|
import { isFunction, isUndefined, compose, toPairs, map, pipe, isNil, reduce } from "lodash/fp"
|
||||||
import { asArray } from "./index"
|
import { asArray } from "./index"
|
||||||
import queryString from "query-string"
|
import queryString from "query-string"
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ function parseUrl(url) {
|
|||||||
|
|
||||||
function extractQueryParams(queryParams, query) {
|
function extractQueryParams(queryParams, query) {
|
||||||
return toPairs(queryParams).reduce((acc, [key, params]) => {
|
return toPairs(queryParams).reduce((acc, [key, params]) => {
|
||||||
const param = asArray(params).find(param => !isNil(query[param]))
|
const param = asArray(params).find((param) => !isNil(query[param]))
|
||||||
if (param) {
|
if (param) {
|
||||||
acc[key] = query[param]
|
acc[key] = query[param]
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ function extractQueryParams(queryParams, query) {
|
|||||||
}, {})
|
}, {})
|
||||||
}
|
}
|
||||||
|
|
||||||
const createEvaluator = args => fnOrValue => {
|
const createEvaluator = (args) => (fnOrValue) => {
|
||||||
if (isUndefined(fnOrValue)) {
|
if (isUndefined(fnOrValue)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -40,20 +40,15 @@ const createEvaluator = args => fnOrValue => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const prepareHostForRegExp = (host) => {
|
const prepareHostForRegExp = (host) => {
|
||||||
if (isUndefined(host)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return host.replace(":", "\\:")
|
return host.replace(":", "\\:")
|
||||||
}
|
}
|
||||||
|
|
||||||
const replaceHostInPattern = (host, pattern) => {
|
const replaceHostInPattern = (host, pattern) => {
|
||||||
if(typeof pattern === "string") {
|
if (typeof pattern === "string") {
|
||||||
return pattern.replace("__HOST__", prepareHostForRegExp(host))
|
return pattern.replace(":host:", prepareHostForRegExp(host))
|
||||||
} else if(pattern instanceof RegExp) {
|
} else if (pattern instanceof RegExp) {
|
||||||
return new RegExp(pattern.source.replace("__HOST__", prepareHostForRegExp(host)))
|
return new RegExp(pattern.source.replace(":host:", prepareHostForRegExp(host)))
|
||||||
} else {
|
} else {
|
||||||
console.error("Invalid type for pattern %v, no host replacement performed", pattern)
|
|
||||||
return pattern
|
return pattern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,11 +57,9 @@ const parseServices = compose(
|
|||||||
map(([key, config]) => ({
|
map(([key, config]) => ({
|
||||||
...config,
|
...config,
|
||||||
key,
|
key,
|
||||||
patterns: config.urlPatterns.map(pattern => {
|
patterns: config.urlPatterns.map((pattern) => {
|
||||||
if (Array.isArray(pattern)) {
|
if (Array.isArray(pattern)) {
|
||||||
return new UrlPattern(
|
return new UrlPattern(...pattern.map((p) => replaceHostInPattern(config.host, p)))
|
||||||
...pattern.map((p, index) => (index === 0 ? replaceHostInPattern(config.host, p) : p)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return new UrlPattern(replaceHostInPattern(config.host, pattern))
|
return new UrlPattern(replaceHostInPattern(config.host, pattern))
|
||||||
}),
|
}),
|
||||||
@@ -74,7 +67,7 @@ const parseServices = compose(
|
|||||||
toPairs,
|
toPairs,
|
||||||
)
|
)
|
||||||
|
|
||||||
export const createEnhancer = document => service => {
|
export const createEnhancer = (document) => (service) => {
|
||||||
if (!service) {
|
if (!service) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -93,38 +86,34 @@ export const createEnhancer = document => service => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const applyHostOverrides = (remoteServices, hostOverrides) => {
|
const applyHostOverrides = (remoteServices, hostOverrides) =>
|
||||||
let appliedRemoteServices = Object.assign(remoteServices)
|
pipe(
|
||||||
if (isUndefined(hostOverrides)) {
|
toPairs,
|
||||||
console.error("No overrides found.")
|
reduce((acc, [key, remoteService]) => {
|
||||||
return remoteServices
|
acc[key] = {
|
||||||
}
|
...remoteService,
|
||||||
|
key,
|
||||||
Object.keys(remoteServices).forEach((key) => {
|
host: hostOverrides[remoteService.name] || remoteService.host,
|
||||||
const remoteService = remoteServices[key]
|
}
|
||||||
appliedRemoteServices[key] = {
|
return acc
|
||||||
...remoteService,
|
}, {}),
|
||||||
key,
|
)(remoteServices)
|
||||||
host: (hostOverrides && hostOverrides[remoteService.name]) || remoteService.host,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return appliedRemoteServices
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createMatcher = (remoteServices, hostOverrides) => {
|
export const createMatcher = (remoteServices, hostOverrides) => {
|
||||||
const services = parseServices(applyHostOverrides(remoteServices, hostOverrides))
|
const services = parseServices(applyHostOverrides(remoteServices, hostOverrides))
|
||||||
|
|
||||||
return tabUrl => {
|
return (tabUrl) => {
|
||||||
const { origin, pathname, hash, query } = parseUrl(tabUrl)
|
const { origin, pathname, hash, query } = parseUrl(tabUrl)
|
||||||
const url = `${origin}${pathname}${hash}`
|
const url = `${origin}${pathname}${hash}`
|
||||||
const service = services.find(service => service.patterns.some(pattern => pattern.match(url)))
|
const service = services.find((service) => {
|
||||||
|
return service.patterns.some((pattern) => pattern.match(url))
|
||||||
|
})
|
||||||
|
|
||||||
if (!service) {
|
if (!service) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const pattern = service.patterns.find(pattern => pattern.match(url))
|
const pattern = service.patterns.find((pattern) => pattern.match(url))
|
||||||
let match = pattern.match(url)
|
let match = pattern.match(url)
|
||||||
if (service.queryParams) {
|
if (service.queryParams) {
|
||||||
const extractedQueryParams = extractQueryParams(service.queryParams, query)
|
const extractedQueryParams = extractQueryParams(service.queryParams, query)
|
||||||
@@ -140,11 +129,8 @@ export const createMatcher = (remoteServices, hostOverrides) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createServiceFinder = (remoteServices, hostOverrides) => document => {
|
export const createServiceFinder = (remoteServices, hostOverrides) => (document) => {
|
||||||
const matcher = createMatcher(remoteServices, hostOverrides)
|
const matcher = createMatcher(remoteServices, hostOverrides)
|
||||||
const enhancer = createEnhancer(document)
|
const enhancer = createEnhancer(document)
|
||||||
return pipe(
|
return pipe(matcher, enhancer)
|
||||||
matcher,
|
|
||||||
enhancer,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user