refactor(workflows): migrate to the new DI architecture
Bug: twpowertools:226
Change-Id: I8700cfd66883a667fc6ae0dffe9deb96f8d8cc80
diff --git a/src/common/architecture/dependenciesProvider/DependenciesProvider.ts b/src/common/architecture/dependenciesProvider/DependenciesProvider.ts
index 8bbe0b8..02e25ce 100644
--- a/src/common/architecture/dependenciesProvider/DependenciesProvider.ts
+++ b/src/common/architecture/dependenciesProvider/DependenciesProvider.ts
@@ -2,7 +2,6 @@
import AutoRefresh from '../../../features/autoRefresh/core/autoRefresh';
import OptionsProviderAdapter from '../../../infrastructure/services/options/OptionsProvider.adapter';
import WorkflowsImport from '../../../features/workflows/core/communityConsole/import';
-import Workflows from '../../../features/workflows/core/communityConsole/workflows';
import StartupDataStorageAdapter from '../../../infrastructure/services/communityConsole/StartupDataStorage.adapter';
import ReportDialogColorThemeFix from '../../../features/ccDarkTheme/core/logic/reportDialog';
@@ -12,7 +11,6 @@
export const ReportDialogColorThemeFixDependency =
'report-dialog-color-theme-fix';
export const StartupDataStorageDependency = 'startupDataStorage';
-export const WorkflowsDependency = 'workflows';
export const WorkflowsImportDependency = 'workflowsImport';
export const DependenciesToClass = {
[AutoRefreshDependency]: AutoRefresh,
@@ -20,7 +18,6 @@
[OptionsProviderDependency]: OptionsProviderAdapter,
[ReportDialogColorThemeFixDependency]: ReportDialogColorThemeFix,
[StartupDataStorageDependency]: StartupDataStorageAdapter,
- [WorkflowsDependency]: Workflows,
[WorkflowsImportDependency]: WorkflowsImport,
};
diff --git a/src/entryPoints/communityConsole/contentScripts/main.ts b/src/entryPoints/communityConsole/contentScripts/main.ts
index bb7fe6a..9c70743 100644
--- a/src/entryPoints/communityConsole/contentScripts/main.ts
+++ b/src/entryPoints/communityConsole/contentScripts/main.ts
@@ -4,6 +4,7 @@
import DependenciesProviderSingleton, {
AutoRefreshDependency,
OptionsProviderDependency,
+ WorkflowsImportDependency,
} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
import { Context } from '../../../common/architecture/entrypoint/Context';
import {
@@ -30,6 +31,10 @@
import CCInfiniteScrollSetUpHandler from '../../../features/infiniteScroll/nodeWatcherHandlers/ccInfiniteScrollSetUp.handler';
import CCInfiniteScrollLoadMoreBarHandler from '../../../features/infiniteScroll/nodeWatcherHandlers/ccInfiniteScrollLoadMoreBar.handler';
import CCInfiniteScrollLoadMoreBtnHandler from '../../../features/infiniteScroll/nodeWatcherHandlers/ccInfiniteScrollLoadMoreBtn.handler';
+import WorkflowsThreadListActionBarHandler from '../../../features/workflows/presentation/nodeWatcherHandlers/threadListActionBar.handler';
+import WorkflowsImportCRTagsHandler from '../../../features/workflows/presentation/nodeWatcherHandlers/crTags.handler';
+import Workflows from '../../../features/workflows/core/communityConsole/workflows';
+import WorkflowsImportStylesheetScript from '../../../features/workflows/presentation/scripts/importStylesheet';
const scriptRunner = createScriptRunner();
scriptRunner.run();
@@ -40,6 +45,9 @@
const optionsProvider = dependenciesProvider.getDependency(
OptionsProviderDependency,
);
+ const workflowsImport = dependenciesProvider.getDependency(
+ WorkflowsImportDependency,
+ );
const ccInfiniteScroll = new CCInfiniteScroll();
@@ -88,11 +96,20 @@
'ccInfiniteScrollLoadMoreBtn',
new CCInfiniteScrollLoadMoreBtnHandler(ccInfiniteScroll),
],
+ [
+ 'workflowsImportCRTags',
+ new WorkflowsImportCRTagsHandler(workflowsImport),
+ ],
+ [
+ 'workflowsThreadListActionBar',
+ new WorkflowsThreadListActionBarHandler(new Workflows()),
+ ],
]),
),
// Individual feature scripts
new AutoRefreshStylesScript(),
+ new WorkflowsImportStylesheetScript(),
// Non-DI scripts (legacy, should be migrated to use a DI approach)
...new Features().getScripts(context),
diff --git a/src/entryPoints/communityConsole/contentScripts/start.ts b/src/entryPoints/communityConsole/contentScripts/start.ts
index c408b9f..73d2230 100644
--- a/src/entryPoints/communityConsole/contentScripts/start.ts
+++ b/src/entryPoints/communityConsole/contentScripts/start.ts
@@ -5,6 +5,7 @@
AutoRefreshDependency,
OptionsProviderDependency,
StartupDataStorageDependency,
+ WorkflowsImportDependency,
} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
import { Context } from '../../../common/architecture/entrypoint/Context';
import {
@@ -22,6 +23,7 @@
import { SortedScriptsProviderAdapter } from '../../../infrastructure/presentation/scripts/SortedScriptsProvider.adapter';
import StandaloneScripts from '../../../scripts/Scripts';
import LoadDraftsSetupScript from '../../../features/loadDrafts/presentation/scripts/setup.script';
+import WorkflowsImportSetUpScript from '../../../features/workflows/presentation/scripts/importSetUp.script';
const scriptRunner = createScriptRunner();
scriptRunner.run();
@@ -35,6 +37,9 @@
const startupDataStorage = dependenciesProvider.getDependency(
StartupDataStorageDependency,
);
+ const workflowsImport = dependenciesProvider.getDependency(
+ WorkflowsImportDependency,
+ );
const context: Context = {
page: ScriptPage.CommunityConsole,
@@ -51,6 +56,7 @@
new CCDarkThemeInjectForcedDarkTheme(),
new InteropThreadPageSetupScript(),
new LoadDraftsSetupScript(optionsProvider, startupDataStorage),
+ new WorkflowsImportSetUpScript(workflowsImport),
// Non-DI scripts (legacy, should be migrated to use a DI approach)
...new Features().getScripts(context),
diff --git a/src/features/Features.ts b/src/features/Features.ts
index 7f2a061..b79d4fa 100644
--- a/src/features/Features.ts
+++ b/src/features/Features.ts
@@ -1,14 +1,12 @@
import Feature from '../common/architecture/features/Feature';
import ScriptFilterListProvider from '../common/architecture/scripts/ScriptFilterListProvider';
import ExtraInfoFeature from './extraInfo/extraInfo.feature';
-import WorkflowsFeature from './workflows/workflows.feature';
export type ConcreteFeatureClass = { new (): Feature };
export default class Features extends ScriptFilterListProvider {
private features: ConcreteFeatureClass[] = [
ExtraInfoFeature,
- WorkflowsFeature,
];
private initializedFeatures: Feature[];
diff --git a/src/features/workflows/core/communityConsole/import.js b/src/features/workflows/core/communityConsole/import.js
index 09ffc0a..a527151 100644
--- a/src/features/workflows/core/communityConsole/import.js
+++ b/src/features/workflows/core/communityConsole/import.js
@@ -6,13 +6,19 @@
const kListCannedResponsesResponse = 'TWPT_ListCannedResponsesResponse';
-const kImportParam = 'TWPTImportToWorkflow';
+export const kImportParam = 'TWPTImportToWorkflow';
const kSelectedIdParam = 'TWPTSelectedId';
// Class which is used to inject a "select" button in the CRs list when loading
// the canned response list for this purpose from the workflows manager.
export default class WorkflowsImport {
constructor() {
+ this.isSetUp = false;
+ }
+
+ setUp() {
+ if (this.isSetUp) return;
+
// Only set this class up if the Community Console was opened with the
// purpose of importing CRs to the workflow manager.
const searchParams = new URLSearchParams(document.location.search);
@@ -27,34 +33,18 @@
duplicateNames: new Set(),
};
- this.setUpHandler();
- this.addCustomStyles();
+ this._setUpHandler();
}
- setUpHandler() {
- window.addEventListener(kListCannedResponsesResponse, e => {
- if (e.detail.id < this.lastCRsList.id) return;
-
- // Look if there are duplicate names
- const crs = e.detail.body?.['1'] ?? [];
- const names = crs.map(cr => cr?.['7']).slice().sort();
- let duplicateNames = new Set();
- for (let i = 1; i < names.length; i++)
- if (names[i - 1] == names[i]) duplicateNames.add(names[i]);
-
- this.lastCRsList = {
- body: e.detail.body,
- id: e.detail.id,
- duplicateNames,
- };
+ addButtonIfApplicable(tags) {
+ this.setUp();
+ if (!this.isSetUp) return;
+ isOptionEnabled('workflows').then(isEnabled => {
+ if (isEnabled) this._addButton(tags);
});
}
- addCustomStyles() {
- injectStylesheet(chrome.runtime.getURL('css/workflow_import.css'));
- }
-
- addButton(tags) {
+ _addButton(tags) {
const cr = recursiveParentElement(tags, 'EC-CANNED-RESPONSE-ROW');
if (!cr) return;
@@ -101,10 +91,22 @@
});
}
- addButtonIfApplicable(tags) {
- if (!this.isSetUp) return;
- isOptionEnabled('workflows').then(isEnabled => {
- if (isEnabled) this.addButton(tags);
+ _setUpHandler() {
+ window.addEventListener(kListCannedResponsesResponse, e => {
+ if (e.detail.id < this.lastCRsList.id) return;
+
+ // Look if there are duplicate names
+ const crs = e.detail.body?.['1'] ?? [];
+ const names = crs.map(cr => cr?.['7']).slice().sort();
+ let duplicateNames = new Set();
+ for (let i = 1; i < names.length; i++)
+ if (names[i - 1] == names[i]) duplicateNames.add(names[i]);
+
+ this.lastCRsList = {
+ body: e.detail.body,
+ id: e.detail.id,
+ duplicateNames,
+ };
});
}
}
diff --git a/src/features/workflows/core/communityConsole/workflows.js b/src/features/workflows/core/communityConsole/workflows.js
index 1110923..9162795 100644
--- a/src/features/workflows/core/communityConsole/workflows.js
+++ b/src/features/workflows/core/communityConsole/workflows.js
@@ -6,8 +6,13 @@
export default class Workflows {
constructor() {
+ this.isSetUp = false;
this.menu = null;
this.workflows = null;
+ }
+
+ setUp() {
+ if (this.isSetUp) return;
// Always keep the workflows list updated
WorkflowsStorage.watch(workflows => {
@@ -21,6 +26,8 @@
message: 'openWorkflowsManager',
});
});
+
+ this.isSetup = true;
}
_emitWorkflowsUpdateEvent() {
@@ -34,6 +41,8 @@
}
addThreadListBtnIfEnabled(readToggle) {
+ this.setUp();
+
isOptionEnabled('workflows').then(isEnabled => {
if (isEnabled) {
this.menu = document.createElement('twpt-workflows-inject');
diff --git a/src/features/workflows/nodeWatcherHandlers/crTags.handler.ts b/src/features/workflows/nodeWatcherHandlers/crTags.handler.ts
deleted file mode 100644
index 040c5ed..0000000
--- a/src/features/workflows/nodeWatcherHandlers/crTags.handler.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import CssSelectorNodeWatcherScriptHandler from '../../../common/architecture/scripts/nodeWatcher/handlers/CssSelectorNodeWatcherScriptHandler';
-import { NodeMutation } from '../../../presentation/nodeWatcher/NodeWatcherHandler';
-import { WorkflowsNodeWatcherDependencies } from '../scripts/nodeWatcher.script';
-
-/**
- * Injects the button to import a canned response next to each CR.
- */
-export default class WorkflowsImportCRTagsHandler extends CssSelectorNodeWatcherScriptHandler<WorkflowsNodeWatcherDependencies> {
- cssSelector = 'ec-canned-response-row .tags';
-
- onMutatedNode(mutation: NodeMutation) {
- this.options.workflowsImport.addButtonIfApplicable(mutation.node);
- }
-}
diff --git a/src/features/workflows/nodeWatcherHandlers/threadListActionBar.handler.ts b/src/features/workflows/nodeWatcherHandlers/threadListActionBar.handler.ts
deleted file mode 100644
index ab23f11..0000000
--- a/src/features/workflows/nodeWatcherHandlers/threadListActionBar.handler.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { NodeWatcherScriptHandler } from '../../../common/architecture/scripts/nodeWatcher/handlers/NodeWatcherScriptHandler';
-import { NodeMutation } from '../../../presentation/nodeWatcher/NodeWatcherHandler';
-import { WorkflowsNodeWatcherDependencies } from '../scripts/nodeWatcher.script';
-
-/**
- * Injects the workflows menu in the thread list.
- */
-export default class WorkflowsThreadListActionBarHandler extends NodeWatcherScriptHandler<WorkflowsNodeWatcherDependencies> {
- initialDiscoverySelector =
- ':is(ec-bulk-actions material-button[debugid="mark-read-button"],' +
- 'ec-bulk-actions material-button[debugid="mark-unread-button"])';
-
- nodeFilter(mutation: NodeMutation) {
- return this.options.workflows.shouldAddThreadListBtn(mutation.node);
- }
-
- onMutatedNode(mutation: NodeMutation) {
- this.options.workflows.addThreadListBtnIfEnabled(mutation.node);
- }
-}
diff --git a/src/features/workflows/presentation/nodeWatcherHandlers/crTags.handler.ts b/src/features/workflows/presentation/nodeWatcherHandlers/crTags.handler.ts
new file mode 100644
index 0000000..f4001c9
--- /dev/null
+++ b/src/features/workflows/presentation/nodeWatcherHandlers/crTags.handler.ts
@@ -0,0 +1,18 @@
+import CssSelectorNodeWatcherHandler from '../../../../infrastructure/presentation/nodeWatcher/handlers/CssSelectorHandler.adapter';
+import { NodeMutation } from '../../../../presentation/nodeWatcher/NodeWatcherHandler';
+import WorkflowsImport from '../../core/communityConsole/import';
+
+/**
+ * Injects the button to import a canned response next to each CR.
+ */
+export default class WorkflowsImportCRTagsHandler extends CssSelectorNodeWatcherHandler {
+ cssSelector = 'ec-canned-response-row .tags';
+
+ constructor(private workflowsImport: WorkflowsImport) {
+ super();
+ }
+
+ onMutatedNode(mutation: NodeMutation) {
+ this.workflowsImport.addButtonIfApplicable(mutation.node);
+ }
+}
diff --git a/src/features/workflows/presentation/nodeWatcherHandlers/threadListActionBar.handler.ts b/src/features/workflows/presentation/nodeWatcherHandlers/threadListActionBar.handler.ts
new file mode 100644
index 0000000..d100b9d
--- /dev/null
+++ b/src/features/workflows/presentation/nodeWatcherHandlers/threadListActionBar.handler.ts
@@ -0,0 +1,26 @@
+import {
+ NodeMutation,
+ NodeWatcherHandler,
+} from '../../../../presentation/nodeWatcher/NodeWatcherHandler';
+import Workflows from '../../core/communityConsole/workflows';
+
+/**
+ * Injects the workflows menu in the thread list.
+ */
+export default class WorkflowsThreadListActionBarHandler
+ implements NodeWatcherHandler
+{
+ initialDiscoverySelector =
+ ':is(ec-bulk-actions material-button[debugid="mark-read-button"],' +
+ 'ec-bulk-actions material-button[debugid="mark-unread-button"])';
+
+ constructor(private workflows: Workflows) {}
+
+ nodeFilter(mutation: NodeMutation) {
+ return this.workflows.shouldAddThreadListBtn(mutation.node);
+ }
+
+ onMutatedNode(mutation: NodeMutation) {
+ this.workflows.addThreadListBtnIfEnabled(mutation.node);
+ }
+}
diff --git a/src/features/workflows/presentation/scripts/importSetUp.script.ts b/src/features/workflows/presentation/scripts/importSetUp.script.ts
new file mode 100644
index 0000000..73edf50
--- /dev/null
+++ b/src/features/workflows/presentation/scripts/importSetUp.script.ts
@@ -0,0 +1,17 @@
+import Script from '../../../../common/architecture/scripts/Script';
+import WorkflowsImport from '../../core/communityConsole/import';
+
+export default class WorkflowsImportSetUpScript extends Script {
+ priority = 102;
+ page: never;
+ environment: never;
+ runPhase: never;
+
+ constructor(private workflowsImport: WorkflowsImport) {
+ super();
+ }
+
+ execute() {
+ this.workflowsImport.setUp();
+ }
+}
diff --git a/src/features/workflows/presentation/scripts/importStylesheet.ts b/src/features/workflows/presentation/scripts/importStylesheet.ts
new file mode 100644
index 0000000..1b0a443
--- /dev/null
+++ b/src/features/workflows/presentation/scripts/importStylesheet.ts
@@ -0,0 +1,16 @@
+import Script from '../../../../common/architecture/scripts/Script';
+import { injectStylesheet } from '../../../../common/contentScriptsUtils';
+import { kImportParam } from '../../core/communityConsole/import';
+
+export default class WorkflowsImportStylesheetScript extends Script {
+ page: never;
+ environment: never;
+ runPhase: never;
+
+ execute() {
+ const searchParams = new URLSearchParams(document.location.search);
+ if (searchParams.has(kImportParam)) {
+ injectStylesheet(chrome.runtime.getURL('css/workflow_import.css'));
+ }
+ }
+}
diff --git a/src/features/workflows/templates/workflows.html.ejs b/src/features/workflows/presentation/templates/workflows.html.ejs
similarity index 100%
rename from src/features/workflows/templates/workflows.html.ejs
rename to src/features/workflows/presentation/templates/workflows.html.ejs
diff --git a/src/features/workflows/scripts/dependenciesSetUpAtMain.script.ts b/src/features/workflows/scripts/dependenciesSetUpAtMain.script.ts
deleted file mode 100644
index 37ec85f..0000000
--- a/src/features/workflows/scripts/dependenciesSetUpAtMain.script.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import {
- Dependency,
- WorkflowsDependency,
-} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
-import {
- ScriptEnvironment,
- ScriptPage,
- ScriptRunPhase,
-} from '../../../common/architecture/scripts/Script';
-import SetUpDependenciesScript from '../../../common/architecture/scripts/setUpDependencies/SetUpDependenciesScript';
-
-export default class WorkflowsDependenciesSetUpAtMainScript extends SetUpDependenciesScript {
- public page = ScriptPage.CommunityConsole;
- public environment = ScriptEnvironment.ContentScript;
- public runPhase = ScriptRunPhase.Main;
- public dependencies: Dependency[] = [WorkflowsDependency];
-}
diff --git a/src/features/workflows/scripts/dependenciesSetUpAtStart.script.ts b/src/features/workflows/scripts/dependenciesSetUpAtStart.script.ts
deleted file mode 100644
index 0b52082..0000000
--- a/src/features/workflows/scripts/dependenciesSetUpAtStart.script.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import {
- Dependency,
- WorkflowsImportDependency,
-} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
-import {
- ScriptEnvironment,
- ScriptPage,
- ScriptRunPhase,
-} from '../../../common/architecture/scripts/Script';
-import SetUpDependenciesScript from '../../../common/architecture/scripts/setUpDependencies/SetUpDependenciesScript';
-
-export default class WorkflowsDependenciesSetUpAtStartScript extends SetUpDependenciesScript {
- public priority = 102;
- public page = ScriptPage.CommunityConsole;
- public environment = ScriptEnvironment.ContentScript;
- public runPhase = ScriptRunPhase.Start;
- public dependencies: Dependency[] = [WorkflowsImportDependency];
-}
diff --git a/src/features/workflows/scripts/nodeWatcher.script.ts b/src/features/workflows/scripts/nodeWatcher.script.ts
deleted file mode 100644
index 36c5a75..0000000
--- a/src/features/workflows/scripts/nodeWatcher.script.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import DependenciesProviderSingleton, {
- WorkflowsDependency,
- WorkflowsImportDependency,
-} from '../../../common/architecture/dependenciesProvider/DependenciesProvider';
-import {
- ScriptEnvironment,
- ScriptPage,
- ScriptRunPhase,
-} from '../../../common/architecture/scripts/Script';
-import LegacyNodeWatcherScript from '../../../common/architecture/scripts/nodeWatcher/LegacyNodeWatcherScript';
-import WorkflowsImport from '../core/communityConsole/import';
-import Workflows from '../core/communityConsole/workflows';
-import WorkflowsImportCRTagsHandler from '../nodeWatcherHandlers/crTags.handler';
-import WorkflowsThreadListActionBarHandler from '../nodeWatcherHandlers/threadListActionBar.handler';
-
-export interface WorkflowsNodeWatcherDependencies {
- workflows: Workflows;
- workflowsImport: WorkflowsImport;
-}
-
-export default class WorkflowsNodeWatcherScript extends LegacyNodeWatcherScript<WorkflowsNodeWatcherDependencies> {
- public page = ScriptPage.CommunityConsole;
- public environment = ScriptEnvironment.ContentScript;
- public runPhase = ScriptRunPhase.Main;
- public handlers = new Map([
- ['workflowsImportCRTags', WorkflowsImportCRTagsHandler],
- ['workflowsThreadListActionBar', WorkflowsThreadListActionBarHandler],
- ]);
-
- protected optionsFactory(): WorkflowsNodeWatcherDependencies {
- const dependenciesProvider = DependenciesProviderSingleton.getInstance();
- return {
- workflows: dependenciesProvider.getDependency(WorkflowsDependency),
- workflowsImport: dependenciesProvider.getDependency(
- WorkflowsImportDependency,
- ),
- };
- }
-}
diff --git a/src/features/workflows/workflows.feature.ts b/src/features/workflows/workflows.feature.ts
deleted file mode 100644
index 9033ecb..0000000
--- a/src/features/workflows/workflows.feature.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import Feature from '../../common/architecture/features/Feature';
-import { ConcreteScript } from '../../common/architecture/scripts/Script';
-import { OptionCodename } from '../../common/options/optionsPrototype';
-import WorkflowsDependenciesSetUpAtMainScript from './scripts/dependenciesSetUpAtMain.script';
-import WorkflowsDependenciesSetUpAtStartScript from './scripts/dependenciesSetUpAtStart.script';
-import WorkflowsNodeWatcherScript from './scripts/nodeWatcher.script';
-
-export default class WorkflowsFeature extends Feature {
- public readonly scripts: ConcreteScript[] = [
- WorkflowsDependenciesSetUpAtStartScript,
- WorkflowsDependenciesSetUpAtMainScript,
- WorkflowsNodeWatcherScript,
- ];
-
- readonly codename = 'workflows';
- readonly relatedOptions: OptionCodename[] = ['workflows'];
-}
diff --git a/webpack.config.js b/webpack.config.js
index c3e835d..1eb49ba 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -144,7 +144,8 @@
}),
new HtmlWebpackPlugin({
filename: 'workflows.html',
- template: 'src/features/workflows/templates/workflows.html.ejs',
+ template:
+ 'src/features/workflows/presentation/templates/workflows.html.ejs',
chunks: ['workflowManager'],
}),
new webpack.DefinePlugin({