diff --git a/index.html b/index.html
index 89bfd069ca..aa8f97d657 100644
--- a/index.html
+++ b/index.html
@@ -108,6 +108,7 @@
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.MyItems());
+ openmct.install(openmct.plugins.ActivityStates());
openmct.install(
openmct.plugins.PlanLayout({
creatable: true
diff --git a/src/plugins/activityStates/activityStatesInterceptor.js b/src/plugins/activityStates/activityStatesInterceptor.js
new file mode 100644
index 0000000000..8106e8deef
--- /dev/null
+++ b/src/plugins/activityStates/activityStatesInterceptor.js
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2023, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+import { ACTIVITYSTATES_KEY, ACTIVITYSTATES_TYPE } from './createActivityStatesIdentifier.js';
+
+function activityStatesInterceptor(openmct, identifierObject, name) {
+ const activityStatesModel = {
+ identifier: identifierObject,
+ name,
+ type: ACTIVITYSTATES_TYPE,
+ activities: {},
+ location: null
+ };
+
+ return {
+ appliesTo: (identifier) => {
+ return identifier.key === ACTIVITYSTATES_KEY;
+ },
+ invoke: (identifier, object) => {
+ if (!object || openmct.objects.isMissing(object)) {
+ openmct.objects.save(activityStatesModel);
+
+ return activityStatesModel;
+ }
+
+ return object;
+ },
+ priority: openmct.priority.HIGH
+ };
+}
+
+export default activityStatesInterceptor;
diff --git a/src/plugins/activityStates/createActivityStatesIdentifier.js b/src/plugins/activityStates/createActivityStatesIdentifier.js
new file mode 100644
index 0000000000..fd281acbaf
--- /dev/null
+++ b/src/plugins/activityStates/createActivityStatesIdentifier.js
@@ -0,0 +1,9 @@
+export const ACTIVITYSTATES_KEY = 'activity-states';
+export const ACTIVITYSTATES_TYPE = 'activity-states';
+
+export function createActivityStatesIdentifier(namespace = '') {
+ return {
+ key: ACTIVITYSTATES_KEY,
+ namespace
+ };
+}
diff --git a/src/plugins/activityStates/plugin.js b/src/plugins/activityStates/plugin.js
new file mode 100644
index 0000000000..f90262eb87
--- /dev/null
+++ b/src/plugins/activityStates/plugin.js
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2023, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+import activityStatesInterceptor from './activityStatesInterceptor.js';
+import { createActivityStatesIdentifier } from './createActivityStatesIdentifier.js';
+
+const ACTIVITYSTATES_DEFAULT_NAME = 'Activity States';
+
+export default function ActivityStatesPlugin(
+ name = ACTIVITYSTATES_DEFAULT_NAME,
+ namespace = '',
+ priority = undefined
+) {
+ return function install(openmct) {
+ const identifier = createActivityStatesIdentifier(namespace);
+
+ if (priority === undefined) {
+ priority = openmct.priority.LOW;
+ }
+
+ openmct.objects.addGetInterceptor(activityStatesInterceptor(openmct, identifier, name));
+ };
+}
diff --git a/src/plugins/activityStates/pluginSpec.js b/src/plugins/activityStates/pluginSpec.js
new file mode 100644
index 0000000000..0b481fbdb4
--- /dev/null
+++ b/src/plugins/activityStates/pluginSpec.js
@@ -0,0 +1,89 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2023, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+import { createOpenMct, resetApplicationState } from 'utils/testing';
+
+import {
+ ACTIVITYSTATES_KEY,
+ createActivityStatesIdentifier
+} from './createActivityStatesIdentifier.js';
+
+const MISSING_NAME = `Missing: ${ACTIVITYSTATES_KEY}`;
+const DEFAULT_NAME = 'Activity States';
+const activityStatesIdentifier = createActivityStatesIdentifier();
+
+describe('the plugin', () => {
+ let openmct;
+ let missingObj = {
+ identifier: activityStatesIdentifier,
+ type: 'unknown',
+ name: MISSING_NAME
+ };
+
+ describe('with no arguments passed in', () => {
+ beforeEach((done) => {
+ openmct = createOpenMct();
+ openmct.install(openmct.plugins.ActivityStates());
+
+ openmct.on('start', done);
+ openmct.startHeadless();
+ });
+
+ afterEach(() => {
+ return resetApplicationState(openmct);
+ });
+
+ it('when installed, adds "Activity States"', async () => {
+ const activityStatesObject = await openmct.objects.get(activityStatesIdentifier);
+ expect(activityStatesObject.name).toBe(DEFAULT_NAME);
+ expect(activityStatesObject).toBeDefined();
+ });
+
+ describe('adds an interceptor that returns a "Activity States" model for', () => {
+ let activityStatesObject;
+ let mockNotFoundProvider;
+ let activeProvider;
+
+ beforeEach(async () => {
+ mockNotFoundProvider = {
+ get: () => Promise.reject(new Error('Not found')),
+ create: () => Promise.resolve(missingObj),
+ update: () => Promise.resolve(missingObj)
+ };
+
+ activeProvider = mockNotFoundProvider;
+ spyOn(openmct.objects, 'getProvider').and.returnValue(activeProvider);
+ activityStatesObject = await openmct.objects.get(activityStatesIdentifier);
+ });
+
+ it('missing objects', () => {
+ let idsMatch = openmct.objects.areIdsEqual(
+ activityStatesObject.identifier,
+ activityStatesIdentifier
+ );
+
+ expect(activityStatesObject).toBeDefined();
+ expect(idsMatch).toBeTrue();
+ });
+ });
+ });
+});
diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js
index 1583fdfc39..f26ccd5372 100644
--- a/src/plugins/plugins.js
+++ b/src/plugins/plugins.js
@@ -27,6 +27,7 @@ import ExampleUser from '../../example/exampleUser/plugin.js';
import ExampleFaultSource from '../../example/faultManagement/exampleFaultSource.js';
import GeneratorPlugin from '../../example/generator/plugin.js';
import ExampleImagery from '../../example/imagery/plugin.js';
+import ActivityStatesPlugin from './activityStates/plugin.js';
import AutoflowPlugin from './autoflow/AutoflowTabularPlugin.js';
import BarChartPlugin from './charts/bar/plugin.js';
import ScatterPlotPlugin from './charts/scatter/plugin.js';
@@ -101,6 +102,7 @@ plugins.LocalTimeSystem = LocalTimeSystem;
plugins.RemoteClock = RemoteClock;
plugins.MyItems = MyItems;
+plugins.ActivityStates = ActivityStatesPlugin;
plugins.StaticRootPlugin = StaticRootPlugin;