## Add standard command menu items
### Summary
This PR introduces standard command menu items, migrating hardcoded
command menu actions to the backend command menu item architecture
powered by front components. It adds a new `twenty-standard-application`
package that defines, builds, and registers front components as standard
command menu items, gated behind the `IS_COMMAND_MENU_ITEM_ENABLED`
feature flag.
### Description
- **New `twenty-standard-application` package**: Contains front
component definitions with an esbuild-based build pipeline that
generates minified `.mjs` bundles and a manifest with checksums.
- **Server-side registration**: New constants register all items with
metadata (labels, icons, positions, availability types, conditional
expressions). A `StandardFrontComponentUploadService` uploads built
components to file storage.
- **`FALLBACK` availability type**: New enum value for command menu
items that appear as fallback options (e.g., "Search Records" fallback).
- **`CommandMenuContextApi` refactor**
- **Conditional availability enhancements**: New array-based helper
functions for evaluating multi-record conditions.
- **Frontend wiring** (twenty-front):
`useCommandMenuItemFrontComponentCommands`
## Next steps
Only simple commands have been implemented for now:
- **Navigation (9)** -- `CommandLink`: go-to-companies,
go-to-dashboards, go-to-notes, go-to-opportunities, go-to-people,
go-to-runs, go-to-settings, go-to-tasks, go-to-workflows
- **Side panel (4)** -- `CommandOpenSidePanelPage`: ask-ai,
search-records, search-records-fallback, view-previous-ai-chats
We still have to implement front components for all the following
commands:
All have placeholder `execute` logic (`async () => {}`) with a `// TODO:
implement execute logic` comment:
**Record (22)**
- `add-to-favorites`, `remove-from-favorites`
- `create-new-record`, `create-new-view`
- `delete-single-record`, `delete-multiple-records`
- `destroy-single-record`, `destroy-multiple-records`
- `restore-single-record`, `restore-multiple-records`
- `export-from-record-index`, `export-from-record-show`,
`export-multiple-records`, `export-note-to-pdf`, `export-view`
- `hide-deleted-records`, `see-deleted-records`
- `import-records`, `merge-multiple-records`, `update-multiple-records`
- `navigate-to-next-record`, `navigate-to-previous-record`
**Page layout (3)** -- `cancel-record-page-layout`,
`edit-record-page-layout`, `save-record-page-layout`
**Dashboard (4)** -- `cancel-dashboard-layout`, `duplicate-dashboard`,
`edit-dashboard-layout`, `save-dashboard-layout`
**Workflow (10)** -- `activate-workflow`, `add-node-workflow`,
`deactivate-workflow`, `discard-draft-workflow`, `duplicate-workflow`,
`see-active-version-workflow`, `see-runs-workflow`,
`see-versions-workflow`, `test-workflow`, `tidy-up-workflow`
**Workflow version (4)** -- `see-runs-workflow-version`,
`see-versions-workflow-version`, `see-workflow-workflow-version`,
`use-as-draft-workflow-version`
**Workflow run (3)** -- `see-version-workflow-run`,
`see-workflow-workflow-run`, `stop-workflow-run`
82 lines
1.9 KiB
TypeScript
82 lines
1.9 KiB
TypeScript
import path from 'path';
|
|
import { type PackageJson } from 'type-fest';
|
|
import { defineConfig } from 'vite';
|
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
|
|
import packageJson from './package.json';
|
|
|
|
export default defineConfig(() => {
|
|
return {
|
|
root: __dirname,
|
|
cacheDir: '../../node_modules/.vite/packages/twenty-sdk-node',
|
|
resolve: {
|
|
alias: {
|
|
'@/': path.resolve(__dirname, 'src') + '/',
|
|
},
|
|
},
|
|
plugins: [
|
|
tsconfigPaths({
|
|
root: __dirname,
|
|
}),
|
|
],
|
|
build: {
|
|
emptyOutDir: false,
|
|
outDir: 'dist',
|
|
lib: {
|
|
entry: {
|
|
index: 'src/sdk/index.ts',
|
|
cli: 'src/cli/cli.ts',
|
|
operations: 'src/cli/public-operations/index.ts',
|
|
build: 'src/build/index.ts',
|
|
clients: 'src/clients/index.ts',
|
|
},
|
|
name: 'twenty-sdk',
|
|
},
|
|
rollupOptions: {
|
|
external: (id: string) => {
|
|
if (/^node:/.test(id)) {
|
|
return true;
|
|
}
|
|
|
|
const builtins = [
|
|
'child_process',
|
|
'crypto',
|
|
'fs',
|
|
'fs/promises',
|
|
'module',
|
|
'os',
|
|
'path',
|
|
'stream',
|
|
'url',
|
|
'util',
|
|
];
|
|
|
|
if (builtins.includes(id)) {
|
|
return true;
|
|
}
|
|
|
|
const deps = Object.keys(
|
|
(packageJson as PackageJson).dependencies || {},
|
|
);
|
|
|
|
return deps.some((dep) => id === dep || id.startsWith(dep + '/'));
|
|
},
|
|
output: [
|
|
{
|
|
format: 'es' as const,
|
|
entryFileNames: '[name].mjs',
|
|
},
|
|
{
|
|
format: 'cjs' as const,
|
|
interop: 'auto' as const,
|
|
esModule: true,
|
|
exports: 'named' as const,
|
|
entryFileNames: '[name].cjs',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
logLevel: 'warn' as const,
|
|
};
|
|
});
|