# Context Menu

The module allows creating the item in the context menu where possible. A context menu item can open a specified app module with additional context related to the selected record or custom URL.

[Context Menu Module](https://support.crowdin.com/developer/crowdin-apps-module-context-menu/)

## Sample

### Redirect to Integration App

```js ins={12-17} title="index.js"
    import crowdinModule from '@crowdin/app-project-module';

    const configuration = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      contextMenu: [{
        key: 'redirect-context',
        location: 'source_file',
        type: 'redirect',
        module: 'project-integrations'
      }],
      projectIntegration: {
        // integration app logic
        getIntegrationFiles: async () => [],
        updateCrowdin: async () => {},
        updateIntegration: async () => {}
      }
    };

    crowdinModule.createApp(configuration);
    ```
  ```ts ins={14-19} title="index.ts"
    import crowdinModule from '@crowdin/app-project-module';
    import type { ClientConfig } from '@crowdin/app-project-module';
    import { ContextOptionsLocations, ContextOptionsTypes } from '@crowdin/app-project-module/modules/context-menu';

    const configuration: ClientConfig = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      contextMenu: [{
        key: 'redirect-context',
        location: ContextOptionsLocations.SOURCE_FILE,
        type: ContextOptionsTypes.REDIRECT,
        module: 'project-integrations'
      }],
      projectIntegration: {
        // integration app logic
        getIntegrationFiles: async () => [],
        updateCrowdin: async () => {},
        updateIntegration: async () => {}
      }
    };

    crowdinModule.createApp(configuration);
    ```
  ### Open in New Tab

```js ins={14-23} title="index.js"
    import crowdinModule from '@crowdin/app-project-module';

    const app = crowdinModule.express();

    const configuration = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      contextMenu: [{
        key: 'new-tab-context',
        location: 'source_file',
        type: 'new_tab',
        uiPath: import.meta.dirname + '/public',
        signaturePatterns: {
          fileName: '.*\\.json'
        },
        name: 'Check file structure'
      }]
    };

    const crowdinApp = crowdinModule.addCrowdinEndpoints(app, configuration);

    app.get('/result', (req, res) => {
      res.json({
        organizationId: req.query.organization_id,
        projectId: req.query.project_id,
        fileId: req.query.file_id
      });
    });

    app.listen(3000, () =>  console.log('Crowdin app started'));
    ```
  ```ts ins={16-25} title="index.ts"
    import crowdinModule from '@crowdin/app-project-module';
    import type { ClientConfig } from '@crowdin/app-project-module';
    import { ContextOptionsLocations, ContextOptionsTypes } from '@crowdin/app-project-module/modules/context-menu';

    const app = crowdinModule.express();

    const configuration: ClientConfig = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      contextMenu: [{
        key: 'new-tab-context',
        location: ContextOptionsLocations.SOURCE_FILE,
        type: ContextOptionsTypes.NEW_TAB,
        uiPath: import.meta.dirname + '/public',
        signaturePatterns: {
          fileName: '.*\\.json'
        },
        name: 'Check file structure'
      }]
    };

    const crowdinApp = crowdinModule.addCrowdinEndpoints(app, configuration);

    app.get('/result', (req, res) => {
      res.json({
        organizationId: req.query.organization_id,
        projectId: req.query.project_id,
        fileId: req.query.file_id
      });
    });

    app.listen(3000, () =>  console.log('Crowdin app started'));
    ```
  Please note that the App defines a new endpoint `/result` by utilizing the Express instance provided by the Crowdin module. The endpoint is used to receive the context data from the Crowdin app.

### Open Modal

```js ins={43-49} collapse={14-41} title="index.js"
    import crowdinModule from '@crowdin/app-project-module';

    const configuration = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      modal: [{
        key: 'sample-modal',
        formSchema: {
          "title": "A registration form",
          "description": "A simple form example.",
          "type": "object",
          "required": [
            "firstName",
            "lastName"
          ],
          "properties": {
            "firstName": {
              "type": "string",
              "title": "First name",
              "default": "Chuck"
            },
            "lastName": {
              "type": "string",
              "title": "Last name"
            }
          }
        },
        formUiSchema: {
          "ui:submitButtonOptions": {
            "submitText": "Confirm Details"
          },
          "lastName": {
            "ui:help": "Hint: Choose cool lastname!"
          }
        }
      }],
      contextMenu: [{
        key: 'modal-context',
        location: 'source_file',
        type: 'modal',
        module: 'modal',
        moduleKey: 'sample-modal'
      }]
    };

    crowdinModule.createApp(configuration);
    ```
  ```ts ins={45-51} collapse={16-43} title="index.ts"
    import crowdinModule from '@crowdin/app-project-module';
    import type { ClientConfig } from '@crowdin/app-project-module';
    import { ContextOptionsLocations, ContextOptionsTypes } from '@crowdin/app-project-module/modules/context-menu';

    const configuration: ClientConfig = {
      baseUrl: 'https://123.ngrok.io',
      clientId: 'clientId',
      clientSecret: 'clientSecret',
      name: 'Sample App',
      identifier: 'sample-app',
      description: 'Sample App description',
      dbFolder: import.meta.dirname,
      imagePath: import.meta.dirname + '/logo.png',
      modal: [{
        key: 'sample-modal',
        formSchema: {
          "title": "A registration form",
          "description": "A simple form example.",
          "type": "object",
          "required": [
            "firstName",
            "lastName"
          ],
          "properties": {
            "firstName": {
              "type": "string",
              "title": "First name",
              "default": "Chuck"
            },
            "lastName": {
              "type": "string",
              "title": "Last name"
            }
          }
        },
        formUiSchema: {
          "ui:submitButtonOptions": {
            "submitText": "Confirm Details"
          },
          "lastName": {
            "ui:help": "Hint: Choose cool lastname!"
          }
        }
      }],
      contextMenu: [{
        key: 'modal-context',
        location: ContextOptionsLocations.SOURCE_FILE,
        type: ContextOptionsTypes.MODAL,
        module: 'modal',
        moduleKey: 'sample-modal'
      }]
    };

    crowdinModule.createApp(configuration);
    ```
  Read more about [Modal](/app-project-module/tools/modal/) and [React JSON Schema forms](/app-project-module/user-interface/).

### Multiple Context Menu Items

You can define multiple context menu items by providing an array:

```js title="index.js"
const configuration = {
  // ... other configuration
  contextMenu: [
    {
      key: 'first-context',
      location: 'source_file',
      type: 'new_tab',
      name: 'First Action',
      uiPath: import.meta.dirname + '/public'
    },
    {
      key: 'second-context',
      location: 'translated_file',
      type: 'modal',
      name: 'Second Action',
      module: 'modal',
      moduleKey: 'my-modal'
    }
  ]
};
```

## Configuration

| Parameter<div class="w-40"/> | Description                                                           | Allowed values                                                                              |
|------------------------------|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| `key`                        | Unique identifier for the context menu item.                          | -                                                                                           |
| `location`                   | The location in UI where the context menu can be added.               | `tm`, `glossary`, `style_guide`, `language`, `screenshot`, `source_file`, `translated_file` |
| `type`                       | The type of action this module will perform.                          | `modal`, `new_tab`, `redirect`                                                              |
| `module`                     | UI Modules type.                                                      | `modal`, `redirect`                                                                         |
| `moduleKey`                  | Key of the specific module to open (when using modal type).           | -                                                                                           |
| `uiPath`                     | Folder where UI of the module is located (`js`, `html`, `css` files). | -                                                                                           |
| `name`                       | The label of the context menu item displayed to the user.             | -                                                                                           |
| `signaturePatterns`          | Contains `fileName` and/or `nodeType` used to detect file             | -                                                                                           |

### Detecting File Type

```js title="index.js"
    signaturePatterns: {
      fileName: '.*\\.json',
      nodeType: [0, 1]
    },
```

| Parameter<div class="w-40"/> | Description                                                           | Allowed values                                                               |
|------------------------------|-----------------------------------------------------------------------|------------------------------------------------------------------------------|
| `fileName`                   | Contains `fileName` regular expressions used to detect file type.     | Regex                                                                        |
| `nodeType`                   | Array of node types                                                   | `0` - folder, `1` - file, `2` - branch                                       |