Studio Developer Manual / Version 2412.0
Table Of ContentsThe Apps Menu is part of the Side Bar that each Studio app has. It can be opened via the burger menu button in the top-left corner of a Studio app.
One speciality of the Apps Menu is that it includes entries from all Studio apps. For example, the entries under Workflows are shortcuts for the Workflow App while all others are shortcuts for the Main App. The entries should fulfil certain conditions:
- The entries need to be dynamic in the way that they are tied to the existence of their respective app. If for example the Workflow App was removed from the Studio client build, its Apps Menu shortcuts should also vanish.
- The shortcuts for an app need to be in the Apps Menu even if this app is not yet opened. For example, if a user worked with the main Studio and the Workflow App was not yet opened in a browser window/tab, the Workflow App shortcuts should still be present in the menu.
- The complete set of Apps Menu shortcuts should not be configured for each app separately as this does not scale with more apps. Instead, each app should just declare, which individual shortcuts it adds to the menu.
App Manifests
To meet the conditions from above, a customization approach based on app manifests was chosen. It is based on the Web standard Web App Manifests but adds some CoreMedia-specific attributes. Via its manifest, each app defines its shortcuts and all of them appear in all Apps Menus of all apps.
The manifest for a Studio app is assembled by the build process. To this end, multiple
modules can add app manifests fragments which are deep-merged to obtain the complete manifest.
Modules add their manifest fragments as part of their jangaroo.config.js
file in the
module's root folder. The complete assembled manifest for an app lies under
APP_MODULE_PATH/build/manifest.webmanifest
. In addition, the manifests
are locale-specific so that you also find the files manifest-de.webmanifest
and manifest-ja.webmanifest
for German and Japanese.
App manifests contain a lot information but this section focuses on the shortcuts part of the manifests.
The grouping of shortcuts under the collapsible sections of the menu mainly
follows the question, which app defines the shortcuts. So they are grouped under
Content for the Main App and
Workflows for the Workflow App.
However, a cmCategory
can be defined for a shortcut (see below).
For the apps menu, categories normally do not have an impact.
The exception is when you use the config option topLevelCategories
of the AppsMenu
. In that case
shortcuts of the configured categories are assembled under a joint section
alongside the sections for the apps.
For example, even though Google
is a shortcut of the Main App, it appears under External Services
in the menu because this category is configured to be a top level category.
Defining App Shortcuts
There are two kinds of app shortcuts, (1) app path shortcuts and (2) service shortcuts.
App Path Shortcuts
App path shortcuts assume that the app can deal with different app sub-paths.
For example, if you switch to the Pending Workflows overview list of the app, you can see
that the browser URL has the hash parameter #path=pending
. So an app path
shortcut simply sets the path
hash parameter of the app to a specific value and
assumes that the app reacts to this in some way.
Examples for app path shortcuts can be found in the manifest fragment for the Workflow App module (part of the core).
module.exports = jangarooConfig({ ... appManifests: { de: { shortcuts: [ { name: "Offen", }, { name: "Laufend", }, { name: "Abgeschlossen", }, ], }, en: { ... categories: [ "Workflow", ], ... shortcuts: [ { cmKey: "cmInbox", name: "Open", url: "inbox", icons: [ { src: "appIcons/inbox_24.svg", sizes: "24x24", type: "image/svg", }, { src: "appIcons/inbox_192.png", sizes: "192x192", type: "image/png", }, { src: "appIcons/inbox_512.png", sizes: "512x512", type: "image/png", }, ], }, { cmKey: "cmPending", name: "Running", url: "pending", ... }, { cmKey: "cmFinished", name: "Closed", url: "finished", ... }, ], }, }, additionalLocales: [ "de", "ja", ] });
Example 9.3. App Path Shortcuts for the workflow app
An app path shortcut defines an url
property that is exactly the value that will
be set for for the path
hash parameter of the app's URL. In addition a name
and a unique cmKey
are set.
Icons in different sizes for the shortcut are optional. If they
are provided they need to reside in the APP_MODULE_ROOT/sencha/appIcons folder
of the module.
The example also shows how different locales are handled. Only selected properties need to be overwritten, everything else is kept from the manifest of the base locale.
Service Shortcuts
The Main App does not handle app paths. Instead, service shortcuts are used. Service shortcuts do not change the app path in any way. Instead, an action inside the corresponding app is triggered to display something. An example is the Tags view of the Main App. Instead of setting a sub-path of the app, a new Studio tab for the Tags sub-app is opened.
To obtain this behaviour, first of all a corresponding service needs to be set up in the
associated app. For the Tags sub-app this is done in the TaxonomyStudioPlugin
in the Blueprint.
studioAppsContext._.getShortcutRunnerRegistry().registerShortcutRunner({ cmKey: "cmTaxonomy" }, (): void => { const openTagsAction = new OpenTaxonomyEditorAction(); openTagsAction.execute(); });
Example 9.4. Registering a Service Method to Trigger the Tags App
A sub-app launcher is registered for the key cmTaxonomy
which simply triggers the
OpenTaxonomyEditorAction
.
With such a sub-app launcher service in place, service shortcuts can be added to the manifest.
For the example of the Tags sub-app, this is done in the
jangaroo.config.js
file of the blueprint/apps/studio-client/apps/main/extensions/taxonomy
module itself.
module.exports = jangarooConfig({ ... appManifests: { en: { ... cmServiceShortcuts: [ { cmKey: "cmTaxonomy", cmOrder: 30, cmCategory: "Content", name: "Tags", url: "", cmAdministrative: true, cmGroups: ["global-manager", "taxonomy-manager", "developer"], cmService: { name: "launchSubAppService", method: "launchSubApp", }, }, ], }, }, });
Example 9.5. Service Shortcut for the Tags Sub-App
The cmKey
parameter must match the key that was used above when registering
a sub-app launcher. Under cmService
you define that the sub-app launcher
mechanism should be used to bring the Tags sub-app to life.
Postprocessing App Manifests
As mentioned above, the app manifests are assembled from multiple fragments, coming from different modules. Some of the modules are part of the core - like the user manager, others are part of the project. App manifests as part of the project code can be customized to meet the project use cases. Unfortunately, app manifests from the core cannot be customized directly.
To customize the app manifests from the core, we recommend to post-process the assembled app manifests
using a node script. The script can be part of the project code and can be executed after the build process.
To this end, extend the build
property in the scripts
section of the package.json
file of the project:
"build": "download-plugins ./build/additional-packages && jangaroo build && node ./postprocess-manifest.js",
Example 9.6. Extending the build script by a postprocessor
The script postprocess-manifest.js
can then be used to modify the assembled app manifests.
The following example shows how to set the cmGroups
property of the Moderation app so that only the users
of the group moderators
can see the app in the menu.
#! /usr/bin/env node "use strict"; const fs = require("fs"); const path = require('path'); console.log("overwrite moderation service manifest"); // Array of JSON files to manipulate. The files are located in the dist folder. Add more files if needed. const files = ['manifest.webmanifest', 'manifest-de.webmanifest', 'manifest-ja.webmanifest']; // Function to postprocess JSON data. Customize for your use cases const postprocessJsonData = (jsonData) => { jsonData.cmServiceShortcuts = jsonData.cmServiceShortcuts.map(shortcut => { // Allow only the group "moderators" to the Moderation app if (shortcut.cmKey === 'cmModeration') { shortcut.cmGroups = ['moderators']; } return shortcut; }); return jsonData; } files.forEach(fileName => { const filePath = path.join(__dirname, 'dist', fileName); fs.readFile(filePath, 'utf8', (err, data) => { if (err) { console.error("Error reading the file:", err); return; } try { // Parse the JSON data let jsonData = JSON.parse(data); // postprocess the JSON data using the function jsonData = postprocessJsonData(jsonData); // Convert back to JSON string const updatedData = JSON.stringify(jsonData, null, 2); // Write the updated data back to the file fs.writeFile(filePath, updatedData, 'utf8', (err) => { if (err) { console.error("Error writing the file:", err); return; } console.log("File successfully updated!"); }); } catch (parseErr) { console.error("Error parsing the JSON:", parseErr); } }); });
Example 9.7. Script to Postprocess the Assembled App Manifests
The script reads the assembled app manifests (of different locales), modifies them and writes them back to the file system.
The postprocessJsonData
function can be used to modify the manifests in any way.
The following example shows how to exclude the Elastic Social Users app from the apps menu.
const postprocessJsonData = (jsonData) => { jsonData.cmServiceShortcuts = jsonData.cmServiceShortcuts // Exclude Elastic Social Users App for all users .filter(shortcut => shortcut.cmKey !== 'cmElasticSocialUsers') .map(shortcut => { // Allow only the group "moderators" to the Moderation app if (shortcut.cmKey === 'cmModeration') { shortcut.cmGroups = ['moderators']; } return shortcut; }); return jsonData; }
Example 9.8. Exclude an App using Postprocessor