MOCO Browser Extension (#2)
* spike * initial draft * updated styling * skeleton * added bubble script to webpack * added linter settings * installs * first implementation * Update webpack config - write bundle to `/build` - add support for SASS - improve options view as a proof o concept for styling * Update es-lint rules to mach mocoapp * Upgrade npm packages * Mount Bubble only for configured services * Update react and babel * Move module resolution config to webpack * Syncrhonize apiClient with chrome storage * Load projects and initialize form with last project and task * Enhance service * Improve handling of changeset with defaults * Create activity * Show error page on missing configuration * Refactor so that changeset can be used as activity params * Show form errors * Fetch and show booked hours for service * Allow to book hours with colon, error handling, spinner * WIP: Shadow DOM * Remove shadow dom * Render App in iframe * Refactor App component to load projects and create activity * Bugsnag integration * Add title to form and timer hint to hours input field * Configure positioning of bubble * Get rid of shared browser instance * Show Calendar and animate buble * Update webpack config * Prevent double animation of bubble * Fix eslint * Add margin to iframe body * Submit form when pressing enter on textarea * Open select on Enter * Use local environment for development * Show upgrade error if version invalid * Add asana service * Add jira and wunderlist services, add better support for query strings * Match urls with hash * Show popup in browser action * Pump version, add version to zip file * Add youtrack service * WIP: always show browserAction * Refactor * Update design * Finalize release 1.0.3 * Fix styles * Add support for Firefox browser * Extract common webpack config * Fix eslint * Close modal with ESC key * Use TimeInputParser to parse hours input * Improve webpack config * Show modal instead of popup when clicking on browser action * Pre-select last booked activities on service * Remove badge from booked hours * Show error and success feedback on options page * Remove updateBrowserActionForTab * Animate Bubble on unmount * Fix select date * Refactor * Fix key shortcut * Show schedule in calendar * Upload source maps to bugsnag * Upload sourcemaps to bugsnag * Define command shortcuts * Fix race condition where both Bubble and content wanted to mount Popup The content script is now the only place, where the Popup is mounted * Replace hash in filename by version * No new line in textarea and updated shortcuts for chrome * Change shortcut to Ctrl+Shift+K * Fix cors issue in new chrome 73 * Style improvements * Only report errors from own sources * Prevent sending messages to browser tabs * Fix scrollbars in iframe * Add error page for unknown error * Add stop propagation to Bubble click event * Update error pages * Remove timeout in tabHandler. The messaging error occurs only when the browser extension is reloaded/updated without refreshing the browser tab. * Refactor messaging * Show spinner in popup * Extract message handler to own module * Update styles and texts of error pages * Ensure focus is on document when opening popup * Find projects by identifier and value, do not highlight selected option in select component * Update docs * Spread match properties on service; improve remote service configuration for jira and wunderlist * Add webpack plugin to remove source mapping url * Bugsnag do not collect user ip * Upload source maps before removing source mapping url in bundles * Add support for regex url patterns, update asana config. * Fix animation Set default transform property via css * Improve config for asana * Change to fad-in/out animation
This commit is contained in:
127
src/js/utils/messageHandlers.js
Normal file
127
src/js/utils/messageHandlers.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import ApiClient from "api/Client"
|
||||
import {
|
||||
ERROR_UNAUTHORIZED,
|
||||
ERROR_UPGRADE_REQUIRED,
|
||||
ERROR_UNKNOWN,
|
||||
groupedProjectOptions,
|
||||
weekStartsOn
|
||||
} from "utils"
|
||||
import { get, forEach, reject, isNil } from "lodash/fp"
|
||||
import { startOfWeek, endOfWeek } from "date-fns"
|
||||
import { createMatcher } from "utils/urlMatcher"
|
||||
import remoteServices from "remoteServices"
|
||||
import { queryTabs, isBrowserTab, getSettings } from "utils/browser"
|
||||
|
||||
const getStartOfWeek = () => startOfWeek(new Date(), { weekStartsOn })
|
||||
const getEndOfWeek = () => endOfWeek(new Date(), { weekStartsOn })
|
||||
const matcher = createMatcher(remoteServices)
|
||||
|
||||
export function tabUpdated(tab, { messenger, settings }) {
|
||||
messenger.connectTab(tab)
|
||||
|
||||
const service = matcher(tab.url)
|
||||
if (service?.match?.id) {
|
||||
messenger.postMessage(tab, { type: "requestService" })
|
||||
|
||||
messenger.once("newService", ({ payload: { service } }) => {
|
||||
const apiClient = new ApiClient(settings)
|
||||
apiClient
|
||||
.bookedHours(service)
|
||||
.then(({ data }) => {
|
||||
messenger.postMessage(tab, {
|
||||
type: "showBubble",
|
||||
payload: {
|
||||
bookedHours: parseFloat(data[0]?.hours) || 0,
|
||||
service
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
messenger.postMessage(tab, {
|
||||
type: "showBubble",
|
||||
payload: {
|
||||
bookedHours: 0,
|
||||
service
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
messenger.postMessage(tab, { type: "hideBubble" })
|
||||
}
|
||||
}
|
||||
|
||||
export function settingsChanged(settings, { messenger }) {
|
||||
queryTabs({ currentWindow: true })
|
||||
.then(reject(isBrowserTab))
|
||||
.then(
|
||||
forEach(tab => {
|
||||
messenger.postMessage(tab, { type: "closePopup" })
|
||||
tabUpdated(tab, { settings, messenger })
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export function togglePopup(tab, { messenger }) {
|
||||
return function({ isOpen, service } = {}) {
|
||||
if (isNil(isOpen)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
messenger.postMessage(tab, { type: "closePopup" })
|
||||
} else {
|
||||
openPopup(tab, { service, messenger })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openPopup(tab, { service, messenger }) {
|
||||
messenger.postMessage(tab, { type: "openPopup", payload: { loading: true } })
|
||||
|
||||
const fromDate = getStartOfWeek()
|
||||
const toDate = getEndOfWeek()
|
||||
getSettings()
|
||||
.then(settings => new ApiClient(settings))
|
||||
.then(apiClient =>
|
||||
Promise.all([
|
||||
apiClient.login(service),
|
||||
apiClient.projects(),
|
||||
apiClient.activities(fromDate, toDate),
|
||||
apiClient.schedules(fromDate, toDate)
|
||||
])
|
||||
)
|
||||
.then(responses => {
|
||||
const action = {
|
||||
type: "openPopup",
|
||||
payload: {
|
||||
service,
|
||||
lastProjectId: get("[0].data.last_project_id", responses),
|
||||
lastTaskId: get("[0].data.last_task_id", responses),
|
||||
roundTimeEntries: get("[0].data.round_time_entries", responses),
|
||||
projects: groupedProjectOptions(get("[1].data.projects", responses)),
|
||||
activities: get("[2].data", responses),
|
||||
schedules: get("[3].data", responses),
|
||||
fromDate,
|
||||
toDate,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
messenger.postMessage(tab, action)
|
||||
})
|
||||
.catch(error => {
|
||||
let errorType, errorMessage
|
||||
if (error.response?.status === 401) {
|
||||
errorType = ERROR_UNAUTHORIZED
|
||||
} else if (error.response?.status === 426) {
|
||||
errorType = ERROR_UPGRADE_REQUIRED
|
||||
} else {
|
||||
errorType = ERROR_UNKNOWN
|
||||
errorMessage = error.message
|
||||
}
|
||||
messenger.postMessage(tab, {
|
||||
type: "openPopup",
|
||||
payload: { errorType, errorMessage }
|
||||
})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user