Skip to content

Commit

Permalink
chore(standard-actions): add Tab model
Browse files Browse the repository at this point in the history
  • Loading branch information
lutangar committed Jul 2, 2019
1 parent d661daa commit 4e4c12e
Show file tree
Hide file tree
Showing 22 changed files with 133 additions and 130 deletions.
7 changes: 3 additions & 4 deletions src/app/actions/browser.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { TabAction } from '.';
import Tab from 'app/lmem/Tab';

export interface BrowserActionClickedAction extends TabAction {
type: 'BROWSER/BROWSER_ACTION_CLICKED';
payload: {
tab: number;
tab: Tab;
};
}

export const browserActionClicked = (
tab: number
): BrowserActionClickedAction => ({
export const browserActionClicked = (tab: Tab): BrowserActionClickedAction => ({
type: 'BROWSER/BROWSER_ACTION_CLICKED',
payload: { tab },
meta: { tab, sendToTab: true, tracked: false }
Expand Down
13 changes: 7 additions & 6 deletions src/app/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { InstalledAction } from './install';
import {
RefreshMatchingContextsAction,
RefreshMatchingContextsFailedAction,
ReceivedMatchingContextsAction
} from './kraftBackend';
import {
Expand All @@ -27,6 +28,7 @@ import {
ReadNoticeAction
} from './notices';
import { Action } from 'redux';
import Tab from 'app/lmem/Tab';

export interface StandardAction extends Action {
payload?: any;
Expand All @@ -44,21 +46,19 @@ export interface ErrorAction extends BaseAction {
}

export interface TabMeta extends ActionMeta {
tab: number;
url?: string;
tab: Tab;
}

export type TabAction = BaseAction & {
export interface TabAction extends BaseAction {
meta: TabMeta;
};
}

export type TabErrorAction = TabAction & ErrorAction;

export interface ActionMeta {
tab?: number;
sendToBackground?: boolean;
sendToTab?: boolean;
tracked?: false;
tracked?: boolean;
}

export type AppAction =
Expand All @@ -69,6 +69,7 @@ export type AppAction =
| TabRemovedAction
| InstalledAction
| RefreshMatchingContextsAction
| RefreshMatchingContextsFailedAction
| ReceivedMatchingContextsAction
| MatchContextAction
| MatchContextFailureAction
Expand Down
3 changes: 2 additions & 1 deletion src/app/actions/notices.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StatefulNotice } from 'app/lmem/notice';
import { BaseAction, ErrorAction, TabAction, TabMeta } from '.';
import Tab from 'app/lmem/Tab';

export interface NoticesFoundAction extends TabAction {
type: 'NOTICES_FOUND';
Expand All @@ -10,7 +11,7 @@ export interface NoticesFoundAction extends TabAction {

export const noticesFound = (
notices: StatefulNotice[],
tab: number
tab: Tab
): NoticesFoundAction => ({
type: 'NOTICES_FOUND',
payload: {
Expand Down
43 changes: 14 additions & 29 deletions src/app/actions/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,27 @@ import {
import { InstallationDetails } from 'app/lmem/installation';
import { MatchingContext } from 'app/lmem/matchingContext';
import { BaseAction, TabAction, TabErrorAction } from '.';
import Tab from 'app/lmem/Tab';

export interface InitAction extends TabAction {
type: 'INIT';
payload: {
tab: number;
installationDetails: InstallationDetails;
};
payload: InstallationDetails;
}

export const init = (
tab: number,
installationDetails: InstallationDetails
installationDetails: InstallationDetails,
tab: Tab
): InitAction => ({
type: 'INIT',
payload: {
tab,
installationDetails
},
payload: installationDetails,
meta: { tab, sendToTab: true }
});

export interface MatchContextAction extends TabAction {
type: 'LMEM/MATCH_CONTEXT';
payload: { url: string; tab: number };
}
export const matchContext = (url: string, tab: number): MatchContextAction => ({
export const matchContext = (tab: Tab): MatchContextAction => ({
type: 'LMEM/MATCH_CONTEXT',
payload: { url, tab },
meta: { tab, tracked: false }
});

Expand All @@ -43,45 +36,37 @@ export interface MatchContextFailureAction extends TabErrorAction {
}
export const matchContextFailure = (
error: Error,
url: string,
tab: number
tab: Tab
): MatchContextFailureAction => ({
type: 'LMEM/MATCH_CONTEXT_FAILURE',
payload: error,
meta: { url, tab, tracked: false },
meta: { tab, tracked: false },
error: true
});

export interface ContextTriggeredAction extends TabAction {
type: 'LMEM/CONTEXT_TRIGGERED';
payload: {
url: string;
tab: number;
triggeredContexts: MatchingContext[];
};
payload: MatchingContext[];
}
export const contextTriggered = (
tab: number,
url: string,
triggeredContexts: MatchingContext[]
triggeredContexts: MatchingContext[],
tab: Tab
): ContextTriggeredAction => ({
type: 'LMEM/CONTEXT_TRIGGERED',
payload: { tab, url, triggeredContexts },
payload: triggeredContexts,
meta: { tab }
});

export interface ContextTriggerFailureAction extends TabErrorAction {
type: 'LMEM/CONTEXT_TRIGGER_FAILURE';
meta: { url: string; tab: number };
}
export const contextTriggerFailure = (
error: Error,
tab: number,
url: string
tab: Tab
): ContextTriggerFailureAction => ({
type: 'LMEM/CONTEXT_TRIGGER_FAILURE',
payload: error,
meta: { url, tab },
meta: { tab },
error: true
});

Expand Down
17 changes: 9 additions & 8 deletions src/app/actions/tabsLifecycle.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import { TabAction } from '.';
import Tab from 'app/lmem/Tab';

export interface TabCreatedAction extends TabAction {
type: 'BROWSER/TAB_CREATED';
payload: { tab: number; url: string };
payload: { tab: Tab };
}
export const tabCreated = (tab: number, url: string): TabCreatedAction => ({
export const tabCreated = (tab: Tab): TabCreatedAction => ({
type: 'BROWSER/TAB_CREATED',
payload: { tab, url },
payload: { tab },
meta: { tab, tracked: false }
});

export interface TabUpdatedAction extends TabAction {
type: 'BROWSER/TAB_UPDATED';
payload: { tab: number; url: string };
payload: { tab: Tab };
}
export const tabUpdated = (tab: number, url: string): TabUpdatedAction => ({
export const tabUpdated = (tab: Tab): TabUpdatedAction => ({
type: 'BROWSER/TAB_UPDATED',
payload: { tab, url },
payload: { tab },
meta: { tab, tracked: false }
});

export interface TabRemovedAction extends TabAction {
type: 'BROWSER/TAB_REMOVED';
payload: { tab: number };
payload: { tab: Tab };
}
export const tabRemoved = (tab: number): TabRemovedAction => ({
export const tabRemoved = (tab: Tab): TabRemovedAction => ({
type: 'BROWSER/TAB_REMOVED',
payload: { tab },
meta: { tab, tracked: false }
Expand Down
13 changes: 6 additions & 7 deletions src/app/background/reducers/tabs.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import {
TAB_CREATED,
TAB_UPDATED,
TAB_REMOVED
TAB_REMOVED,
TAB_UPDATED
} from '../../constants/browser/tabs';
import { AppAction } from 'app/actions';
import * as R from 'ramda';
import Tab from 'app/lmem/Tab';

export interface TabsState {
[tab: string]: string;
[tabId: string]: Tab;
}

export const initialState: TabsState = {};

export default function(state = initialState, action: AppAction) {
switch (action.type) {
case TAB_CREATED:
return { ...state, [action.payload.tab]: action.payload.url };

case TAB_UPDATED:
return { ...state, [action.payload.tab]: action.payload.url };
return { ...state, [action.payload.tab.id]: action.payload.tab };

case TAB_REMOVED:
return R.dissoc<TabsState>(action.payload.tab.toString(), state);
return R.dissoc<TabsState>(action.payload.tab.id.toString(), state);

default:
return state;
Expand Down
8 changes: 4 additions & 4 deletions src/app/background/sagas/badge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import { badgeResetFailed, badgeUpdateFailed } from '../../actions/badge';
export const updateBadgeSaga = (badgeTheme: BadgeTheme) =>
function*({
payload: notices,
meta: { tab: tabId }
meta: { tab }
}: NoticesUpdatedAction): IterableIterator<any> {
try {
const noticesToDisplay = yield select(getNoticesToDisplay(notices));
yield call(updateBadge, noticesToDisplay, badgeTheme, tabId);
yield call(updateBadge, noticesToDisplay, badgeTheme, tab.id);
} catch (e) {
badgeUpdateFailed(e);
}
};

export function* resetBadgeSaga({
meta: { tab: tabId }
meta: { tab }
}: TabAction): IterableIterator<any> {
try {
resetBadge(tabId);
resetBadge(tab.id);
} catch (e) {
badgeResetFailed(e);
}
Expand Down
31 changes: 14 additions & 17 deletions src/app/background/sagas/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,40 +50,37 @@ import * as R from 'ramda';
import { MatchingContext } from '../../lmem/matchingContext';
import { StatefulNotice, Notice, warnIfNoticeInvalid } from '../../lmem/notice';
import sendToTab from '../services/sendToTab';
import { AppAction } from '../../actions/';
import { fetchNotices } from '../../../api/fetchNotice';

export const tabSaga = (executeContentScript: ExecuteContentScript) =>
function*({ payload: { tab, url } }: TabCreatedAction | TabUpdatedAction) {
yield call(executeContentScript, tab, url);
yield put(matchContext(url, tab));
function*({ payload: { tab } }: TabCreatedAction | TabUpdatedAction) {
yield call(executeContentScript, tab);
yield put(matchContext(tab));
};

export function* matchContextSaga({
payload: { url },
meta: { tab }
}: MatchContextAction) {
export function* matchContextSaga({ meta: { tab } }: MatchContextAction) {
try {
const triggeredContexts = yield select(state =>
findTriggeredContexts(state)(url)
findTriggeredContexts(state)(tab.url)
);

if (triggeredContexts.length >= 1) {
yield put(contextTriggered(tab, url, triggeredContexts));
yield put(contextTriggered(triggeredContexts, tab));
} else {
throw new Error('No contexts triggered');
}
} catch (e) {
yield put(matchContextFailure(e, url, tab));
yield put(matchContextFailure(e, tab));
}
}

export const contextTriggeredSaga = function*({
payload: { tab, url: trigger, triggeredContexts }
payload: triggeredContexts,
meta: { tab }
}: ContextTriggeredAction) {
try {
const initialContent = yield select(getInitialContent);
yield put(init(tab, initialContent.installationDetails));
yield put(init(initialContent.installationDetails, tab));

const toFetch = R.compose<MatchingContext[], string[], string[]>(
R.uniq,
Expand All @@ -97,14 +94,14 @@ export const contextTriggeredSaga = function*({
getNoticesToDisplay(validNotices)
);
yield all(
noticesToShow.map(notice => put(noticeDisplayed(notice, trigger)))
noticesToShow.map(notice => put(noticeDisplayed(notice, tab.url)))
);

const ignoredNotices: StatefulNotice[] = yield select(
getIgnoredNotices(validNotices)
);
yield all(
ignoredNotices.map(notice => put(noticeIgnored(notice, trigger)))
ignoredNotices.map(notice => put(noticeIgnored(notice, tab.url)))
);

if (noticesToShow.length > 0) {
Expand All @@ -114,15 +111,15 @@ export const contextTriggeredSaga = function*({
// throw new Error('Context was triggered but they were no notices left to display.');
}
} catch (e) {
yield put(contextTriggerFailure(e, tab, trigger));
yield put(contextTriggerFailure(e, tab));
}
};

export function* publishToTabSaga(action: TabAction) {
const {
meta: { tab }
} = action;
const response = yield call(sendToTab, tab, action);
const response = yield call(sendToTab, tab.id, action);

console.log(`Tab "${tab}" respond`, response);
}
Expand Down
6 changes: 4 additions & 2 deletions src/app/background/services/createBrowserActionChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { browserActionClicked } from 'app/actions/browser';
export const createBrowserActionChannel = () => {
return eventChannel(emit => {
const handleClick = (tab: chrome.tabs.Tab) => {
if (tab.id) {
emit(browserActionClicked(tab.id));
if (tab.id && tab.url) {
emit(browserActionClicked({ id: tab.id, url: tab.url }));
} else {
console.error('Tab had no id or URL.');
}
};

Expand Down
11 changes: 6 additions & 5 deletions src/app/background/services/executeTabScript.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
export type ExecuteContentScript = (tab: number, url: string) => Promise<any[]>;
import Tab from 'app/lmem/Tab';

export type ExecuteContentScript = (tab: Tab) => Promise<any[]>;

export const executeTabScript = (code: string): ExecuteContentScript => (
tab: number,
url: string
tab: Tab
): Promise<any[]> =>
new Promise(resolve => {
if (url.startsWith('http')) {
if (tab.url.startsWith('http')) {
chrome.tabs.executeScript(
tab,
tab.id,
{
code,
runAt: 'document_end'
Expand Down
Loading

0 comments on commit 4e4c12e

Please sign in to comment.