Browser extension fixes (#8)

* Set full url on service

* Link logo to `/activities` in modal

* Update changelog

* Honor the selected task and set the correct billability
This commit is contained in:
Manuel Bouza
2019-03-30 06:59:18 +01:00
committed by Tobias Miesel
parent 0f5172a820
commit 02a0bec738
10 changed files with 87 additions and 52 deletions

View File

@@ -32,7 +32,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Change the default value of subdomain to `unset` to have a well-formed URL. - Change the default value of subdomain to `unset` to have a well-formed URL.
## [1.1.0] - 2019-03-28 ## [1.1.0] - 2019-03-30
### Added ### Added
- Read project identifier from Asana project title - Read project identifier from Asana project title
- Add support for meistertask.com - Add support for meistertask.com
### Fixed
- Link logo in modal to MOCO activities page
- Set full url on service, including query params

View File

@@ -16,6 +16,7 @@
"test:watch": "node_modules/.bin/jest --watch" "test:watch": "node_modules/.bin/jest --watch"
}, },
"dependencies": { "dependencies": {
"@babel/polyfill": "^7.4.0",
"@bugsnag/js": "^5.2.0", "@bugsnag/js": "^5.2.0",
"@bugsnag/plugin-react": "^5.2.0", "@bugsnag/plugin-react": "^5.2.0",
"axios": "^0.18.0", "axios": "^0.18.0",

View File

@@ -1,3 +1,4 @@
import "@babel/polyfill"
import ApiClient from "api/Client" import ApiClient from "api/Client"
import { import {
isChrome, isChrome,

View File

@@ -36,6 +36,7 @@ class App extends Component {
projectId: PropTypes.string, projectId: PropTypes.string,
taskId: PropTypes.string taskId: PropTypes.string
}), }),
subdomain: PropTypes.string,
activities: PropTypes.array, activities: PropTypes.array,
schedules: PropTypes.array, schedules: PropTypes.array,
projects: PropTypes.array, projects: PropTypes.array,
@@ -62,12 +63,14 @@ class App extends Component {
const { service, projects, lastProjectId, lastTaskId } = this.props const { service, projects, lastProjectId, lastTaskId } = this.props
const project = const project =
findProjectByValue(this.changeset.assignment_id)(projects) ||
findProjectByIdentifier(service?.projectId)(projects) || findProjectByIdentifier(service?.projectId)(projects) ||
findProjectByValue(Number(lastProjectId))(projects) || findProjectByValue(Number(lastProjectId))(projects) ||
head(projects) head(projects)
const task = const task =
findTask(service?.taskId || lastTaskId)(project) || head(project?.tasks) findTask(this.changeset.task_id || service?.taskId || lastTaskId)(project) ||
head(project?.tasks)
const defaults = { const defaults = {
remote_service: service?.name, remote_service: service?.name,
@@ -108,7 +111,7 @@ class App extends Component {
if (name === "assignment_id") { if (name === "assignment_id") {
const project = findProjectByValue(value)(projects) const project = findProjectByValue(value)(projects)
this.changeset.task_id = head(project?.tasks).value || null this.changeset.task_id = head(project?.tasks)?.value
} }
}; };
@@ -145,6 +148,7 @@ class App extends Component {
render() { render() {
const { const {
loading, loading,
subdomain,
projects, projects,
activities, activities,
schedules, schedules,
@@ -179,7 +183,7 @@ class App extends Component {
> >
{props => ( {props => (
<animated.div className="moco-bx-app-container" style={props}> <animated.div className="moco-bx-app-container" style={props}>
<Header /> <Header subdomain={subdomain} />
<Observer> <Observer>
{() => ( {() => (
<> <>

View File

@@ -52,6 +52,7 @@ class Popup extends Component {
const serializedProps = serializeProps([ const serializedProps = serializeProps([
"loading", "loading",
"service", "service",
"subdomain",
"lastProjectId", "lastProjectId",
"lastTaskId", "lastTaskId",
"roundTimeEntries", "roundTimeEntries",

View File

@@ -1,13 +1,20 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types'
import logoUrl from "images/logo.png" import logoUrl from "images/logo.png"
const Header = () => ( const Header = ({ subdomain }) => (
<div className="moco-bx-logo__container"> <div className="moco-bx-logo__container">
<a href={`https://${subdomain}.mocoapp.com/activities`} target="_blank" rel="noopener noreferrer">
<img <img
className="moco-bx-logo" className="moco-bx-logo"
src={chrome.extension.getURL(logoUrl)} src={chrome.extension.getURL(logoUrl)}
/> />
</a>
</div> </div>
) )
Header.propTypes = {
subdomain: PropTypes.string
}
export default Header export default Header

View File

@@ -9,6 +9,7 @@ import "../css/popup.scss"
const parsedProps = parseProps([ const parsedProps = parseProps([
"loading", "loading",
"service", "service",
"subdomain",
"projects", "projects",
"activities", "activities",
"schedules", "schedules",

View File

@@ -76,26 +76,25 @@ export function togglePopup(tab, { messenger }) {
} }
} }
function openPopup(tab, { service, messenger }) { async function openPopup(tab, { service, messenger }) {
messenger.postMessage(tab, { type: "openPopup", payload: { loading: true } }) messenger.postMessage(tab, { type: "openPopup", payload: { loading: true } })
const fromDate = getStartOfWeek() const fromDate = getStartOfWeek()
const toDate = getEndOfWeek() const toDate = getEndOfWeek()
getSettings() const settings = await getSettings()
.then(settings => new ApiClient(settings)) const apiClient = new ApiClient(settings)
.then(apiClient => try {
Promise.all([ const responses = await Promise.all([
apiClient.login(service), apiClient.login(service),
apiClient.projects(), apiClient.projects(),
apiClient.activities(fromDate, toDate), apiClient.activities(fromDate, toDate),
apiClient.schedules(fromDate, toDate) apiClient.schedules(fromDate, toDate)
]) ])
)
.then(responses => {
const action = { const action = {
type: "openPopup", type: "openPopup",
payload: { payload: {
service, service,
subdomain: settings.subdomain,
lastProjectId: get("[0].data.last_project_id", responses), lastProjectId: get("[0].data.last_project_id", responses),
lastTaskId: get("[0].data.last_task_id", responses), lastTaskId: get("[0].data.last_task_id", responses),
roundTimeEntries: get("[0].data.round_time_entries", responses), roundTimeEntries: get("[0].data.round_time_entries", responses),
@@ -108,8 +107,7 @@ function openPopup(tab, { service, messenger }) {
} }
} }
messenger.postMessage(tab, action) messenger.postMessage(tab, action)
}) } catch (error) {
.catch(error => {
let errorType, errorMessage let errorType, errorMessage
if (error.response?.status === 401) { if (error.response?.status === 401) {
errorType = ERROR_UNAUTHORIZED errorType = ERROR_UNAUTHORIZED
@@ -123,5 +121,5 @@ function openPopup(tab, { service, messenger }) {
type: "openPopup", type: "openPopup",
payload: { errorType, errorMessage } payload: { errorType, errorMessage }
}) })
}) }
} }

View File

@@ -88,7 +88,7 @@ export const createMatcher = remoteServices => {
return { return {
...match, ...match,
...service, ...service,
url, url: tabUrl,
match match
} }
} }

View File

@@ -607,6 +607,14 @@
"@babel/helper-regex" "^7.0.0" "@babel/helper-regex" "^7.0.0"
regexpu-core "^4.1.3" regexpu-core "^4.1.3"
"@babel/polyfill@^7.4.0":
version "7.4.0"
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.4.0.tgz#90f9d68ae34ac42ab4b4aa03151848f536960218"
integrity sha512-bVsjsrtsDflIHp5I6caaAa2V25Kzn50HKPL6g3X0P0ni1ks+58cPB8Mz6AOKVuRPgaVdq/OwEUc/1vKqX+Mo4A==
dependencies:
core-js "^2.6.5"
regenerator-runtime "^0.13.2"
"@babel/preset-env@^7.2.2": "@babel/preset-env@^7.2.2":
version "7.3.1" version "7.3.1"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db"
@@ -2021,6 +2029,11 @@ copyfiles@^2.1.0:
through2 "^2.0.1" through2 "^2.0.1"
yargs "^11.0.0" yargs "^11.0.0"
core-js@^2.6.5:
version "2.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
core-util-is@1.0.2, core-util-is@~1.0.0: core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -6160,6 +6173,11 @@ regenerator-runtime@^0.12.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-runtime@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
regenerator-transform@^0.13.3: regenerator-transform@^0.13.3:
version "0.13.3" version "0.13.3"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb"