mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
* Add support for MIGRATIONS_PATH (#20627) * Deprecate "local" extension types (#20624) * No longer resolve local non-package extensions * Remove local extensions from watcher * Install fs-extra for app dev * Replace usage of get-extensions * Rename create functions to match behavior * Drop extensions prefix from cli create * Drop name requirement from cli add * Drop extensions name regex checks * Don't rely on regex for extension identification * Add changeset * Fix build for @directus/extensions * Don't ensure nested dirs * Load npm dependency by name prefix * Throw more helpful error when pkg json is missing * Fix dependency loading paths * Only load local extensions if extensions path exists * Fix merge conflict * Remove unused fs-extra * Only sync extensions if location is defined * `extensions` -> `localExtensions` * Fix resolving of package extensions - consistent usage of term "package extensions" - enhance error messages * Fix syncing extension from storage * Revert-revert change from #20627 --------- Co-authored-by: ian <licitdev@gmail.com> Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch> * Add back `MIGRATIONS_PATH` to `@directus/env` (#21053) * Setup browse endpoint for browsing Directus extensions (#21033) * Rename tag directus-custom to directus-extension * Devil's in the details * [WIP] Start on search lib * Setup extensions-registry package * Update pnpm lock * Move registry search fn to new package * Squash bugs * Remove unused deps * Remove unused dep in `extensions` * Add tests for validate-limit * Finish test coverage * Remove unused constant * Add back lodash-es 😇 * Install extensions-registry * Add default keywords * Expose registry endpoint in rest api * Add describe module * Reinstal pnpm * Drop reliance on author field The problem is that there's no requirement for it to be a valid(ated) user. Publisher is the only field we can rely on being an existing NPM user. * Update convertSearchResult test after author change * Format * Allow anything after the route To support packages with scopes * Add test for describe * Add more tests * Throw unprocessablecontenterror instead of error * Install errors pkg * Finish test coverage * Don't require description * Don't wrap individual keywords * Run formatter * Add changeset * Update packages/extensions-registry/src/modules/search/utils/validate-text.ts Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch> * Return sandbox information * Drop support for directus-custom keyword * Set type to null for multiple tags * Restart api for new registry * Add version utility * Add out-of-date error * Add assertion for api versions * Finish new list method * Add describe * Use updated registry functions * Fix controller usage * Return output in data flag to be consistent * Add tests for the describe module * Add tests for list module * Finish tests for extensions-registry package * Remove vscode shenanigans --------- Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch> * Project Forum: Browse UX (#21276) * Render marketplace route in-app * Update api list integration * Add support for limit/offset in list * Boilerplate route for drawer * Render extension readme in drawer * Render extension detail as separate page * Setup markup for extension banner * Render readme with markdown styling * Boilerplate metadata block * Use v-list for extension metadata metrics * Render compatibility metric * Show downloads and publish date * Refactor to individual files * Fix missing import * Add size metric * Show author on metadat * Show verified badge * Finish metadata * Run formatter * Style forum detail banner (#21290) * Style banner contents * Add background art * Add banner styles to default dark mode theme * Undo base style change to avoid conflict * Add beta chip badge to settings nav (#21296) * Add layout styling for detail page (#21297) * Render metadata as grid if size allows * Finish layout for detail page * Fix alignment of count * Fix search-input active state * Finalize forum header * Add marketplace banner * Style registry filter * Change v-list-item height to min-height Allows rows for forum registry to grow * Finalize styling for extension list item * Finalize styling for registry * Don't rely on format util * Forum account detail page (#21299) * Add support for author describe endpoint * Boilerplate author page * Add author endpoint * Update naming to account * Render github name on registry list * Render user's name + avatar on detail * Load account data on account page * Restructure module * Render account banner on account page * Render account metadata * Finish account detail page * Run formatter * Add sidebar info detail sections * install extensions from registry (#21070) * added an endpoint to install extensions from registries * add changeset * Revert format/lint scripts * Update pnpm-lock * Remove unused dependency * Add download module to extensions-registry abstraction * Download from extension registry instead of direct npm * Throw on error * Install based on version ID rather than name * Install based on ID in body Allows us to extend it in the future if need be * Download to tmp path instead of extensions * Save to extensions manager flattened * Use const for package folder name * Run more in try/catch to avoid server exit * Remove changeset * Undo docs updates We'll do all docs in a single PR :) --------- Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch> Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com> * Manage extensions by directus_extensions primary key instead of npm package name (#21300) * Add marketplace migration * Include bundle info * Rename name to folder * Store name as folder * [WIP] Change name to ID * Update API to use UUIDs for extensions * Update app to use extensions id * Run formatter * Add changeset * Update generate-app-entrypoint to use updated format * Fix graphql usage * Format * Add forum uninstall endpoint (#21301) * Bootstrap uninstall * Finish uninstall endpoint * Use shared extensions store state for managing extensions in settings (#21317) * Use extensionsstore for extensions management * Use shared store for extensions state and modification * Remove unused emit * Adds install/uninstall GUI elements for project forum (#21319) * Use warning color for incompatible * Styling tweaks * Transition optional background color * Add keys for installing * Add install button to extension detail * Finish install button * Add uninstall option to extensions item * Empty local cached extensions on start * Add (hopefully) temporary hack to await reload * Add install / uninstall buttons * Update lockfile * Fix bundle entries not rendering properly * Clean up spinner styling * Properly wait for reload to be done * Run formatter * Fix registry name * Fix local extension loading * Render location/company in byline * Rearchitect metadata to unstyled listitems * Add max-width to page container * Only allow admins to install/uninstall extensions * Remove unused link * Disable eslint for map use * Run formatter * Add no-results indicator (#21389) * Add no-results indicator * add error state as well * Standardize trailing slash * Standardize pk check * Resolve unnecessary check * Move all deps to dev deps in app * Optimize exec order * Pull data from top level package * Redesign filter bar * Reset page count on filter change * Use default padding on top of page Feels weird now, but there's a theme-update coming that'll make this make sense :) * Show first/last in pagination * Auto-format package name * Use updated registry api return names * Add sorting by total downloads * Add sparkline for downloads * Add a bit of padding * Finalize sparkline styling * Run formatterg * Add sandbox flag in list call * Add MARKETPLACE_TRUST env var * Set sandbox requirement on download * Render list item badge * Fix padding * Show license in gui * Add support for multiple maintainers * Add activity tracking for install * Make incompatibility notice friendlier * Tweak margin of sparkline * Update default CSP headers to include github content * Make extension readme selectable * Consistent icon, add tooltips * Reduce size of install button * Run formatter * Render readme anchors with target blank * Add min width to v-select components * Fix background on search input * Reduce padding on marketplace pages * Fix showing no results * Be consistent * Render type filter menu in full height * Clean up compatibility notice * Hide count result when search count is 0 * Use v-show instead * Bump no results notice down a bit * Cleanup size of install buttons * Use buttons for install / author * Fix sparkline rendering * Add better loading state for extension detail page * Add spinners * Render proper error message in case readme is missing * Use heart logo for marketplace * Add image border shadow * Add loading banner on account page * Show reload warning as persistent notification * Only show one notification * Update snapshot * Add padding to verified icon * Base extensions id on package id, show installed badge * Sync pagination / search / filter with URL Special shoutout to Tim * Next max ext (#21541) * Add limit exceeded error * Add limit exceeded translation * Add extensions_limit env var * Load extensions limit in app * Don't allow installing unknown versions * Don't require installed flag * Return bundled entries in describe * Update chip to match style * Prevent install on limit reached * Run formatter * Fix bundle loading * Resolve npm extensions by package manifest (#21478) * Merge main into next (#21669) * Clean-up deps * Don't export type (as long as not used anywhere) * Update semver to latest * Relax compatibility notice * Use more suitable icon for version * Re-render download charts on color-scheme change * Link extensions to marketplace --------- Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com> Co-authored-by: ian <licitdev@gmail.com> Co-authored-by: Mahendra Kumar <22556323+mahendraHegde@users.noreply.github.com>
193 lines
4.8 KiB
JavaScript
193 lines
4.8 KiB
JavaScript
import { APP_SHARED_DEPS } from '@directus/extensions';
|
|
import { generateExtensionsEntrypoint, resolveFsExtensions, resolveModuleExtensions } from '@directus/extensions/node';
|
|
import yaml from '@rollup/plugin-yaml';
|
|
import UnheadVite from '@unhead/addons/vite';
|
|
import vue from '@vitejs/plugin-vue';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { searchForWorkspaceRoot } from 'vite';
|
|
import { defineConfig } from 'vitest/config';
|
|
|
|
const API_PATH = path.join('..', 'api');
|
|
|
|
/*
|
|
* @TODO This extension path is hardcoded to the env default (./extensions). This won't work
|
|
* as expected when extensions are read from a different location locally through the
|
|
* EXTENSIONS_LOCATION env var
|
|
*/
|
|
const EXTENSIONS_PATH = path.join(API_PATH, 'extensions');
|
|
|
|
const extensionsPathExists = fs.existsSync(EXTENSIONS_PATH);
|
|
|
|
// https://vitejs.dev/config/
|
|
export default defineConfig({
|
|
plugins: [
|
|
directusExtensions(),
|
|
vue(),
|
|
UnheadVite(),
|
|
yaml({
|
|
transform(data) {
|
|
return data === null ? {} : undefined;
|
|
},
|
|
}),
|
|
{
|
|
name: 'watch-directus-dependencies',
|
|
configureServer: (server) => {
|
|
server.watcher.options = {
|
|
...server.watcher.options,
|
|
ignored: [/node_modules\/(?!@directus\/).*/, '**/.git/**'],
|
|
};
|
|
},
|
|
},
|
|
],
|
|
define: {
|
|
__INTLIFY_JIT_COMPILATION__: true,
|
|
__VUE_I18N_LEGACY_API__: false,
|
|
},
|
|
resolve: {
|
|
alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
|
|
},
|
|
base: process.env.NODE_ENV === 'production' ? '' : '/admin/',
|
|
...(!process.env.HISTOIRE && {
|
|
server: {
|
|
port: 8080,
|
|
proxy: {
|
|
'^/(?!admin)': {
|
|
target: process.env.API_URL ? process.env.API_URL : 'http://127.0.0.1:8055/',
|
|
changeOrigin: true,
|
|
},
|
|
},
|
|
fs: {
|
|
allow: [searchForWorkspaceRoot(process.cwd()), ...getExtensionsRealPaths()],
|
|
},
|
|
},
|
|
}),
|
|
test: {
|
|
environment: 'happy-dom',
|
|
deps: {
|
|
optimizer: {
|
|
web: {
|
|
exclude: ['pinia', 'url'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
function getExtensionsRealPaths() {
|
|
return extensionsPathExists
|
|
? fs
|
|
.readdirSync(EXTENSIONS_PATH)
|
|
.flatMap((typeDir) => {
|
|
const extensionTypeDir = path.join(EXTENSIONS_PATH, typeDir);
|
|
if (!fs.statSync(extensionTypeDir).isDirectory()) return;
|
|
return fs.readdirSync(extensionTypeDir).map((dir) => fs.realpathSync(path.join(extensionTypeDir, dir)));
|
|
})
|
|
.filter((v) => v)
|
|
: [];
|
|
}
|
|
|
|
function directusExtensions() {
|
|
const virtualExtensionsId = '@directus-extensions';
|
|
|
|
let extensionsEntrypoint = null;
|
|
|
|
return [
|
|
{
|
|
name: 'directus-extensions-serve',
|
|
apply: 'serve',
|
|
config: () => ({
|
|
optimizeDeps: {
|
|
include: APP_SHARED_DEPS,
|
|
},
|
|
}),
|
|
async buildStart() {
|
|
await loadExtensions();
|
|
},
|
|
resolveId(id) {
|
|
if (id === virtualExtensionsId) {
|
|
return id;
|
|
}
|
|
},
|
|
load(id) {
|
|
if (id === virtualExtensionsId) {
|
|
return extensionsEntrypoint;
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: 'directus-extensions-build',
|
|
apply: 'build',
|
|
config: () => ({
|
|
build: {
|
|
rollupOptions: {
|
|
input: {
|
|
index: path.resolve(__dirname, 'index.html'),
|
|
...APP_SHARED_DEPS.reduce((acc, dep) => ({ ...acc, [dep.replace(/\//g, '_')]: dep }), {}),
|
|
},
|
|
output: {
|
|
entryFileNames: 'assets/[name].[hash].entry.js',
|
|
},
|
|
external: [virtualExtensionsId],
|
|
preserveEntrySignatures: 'exports-only',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
];
|
|
|
|
async function loadExtensions() {
|
|
// eslint-disable-next-line no-undef
|
|
const localExtensions = extensionsPathExists ? await resolveFsExtensions(EXTENSIONS_PATH) : new Map();
|
|
const moduleExtensions = await resolveModuleExtensions(API_PATH);
|
|
|
|
const registryExtensions = extensionsPathExists
|
|
? await resolveFsExtensions(path.join(EXTENSIONS_PATH, '.registry'))
|
|
: // eslint-disable-next-line no-undef
|
|
new Map();
|
|
|
|
const mockSetting = (source, folder, extension) => {
|
|
const settings = [
|
|
{
|
|
id: extension.name,
|
|
enabled: true,
|
|
folder: folder,
|
|
bundle: null,
|
|
source: source,
|
|
},
|
|
];
|
|
|
|
if (extension.type === 'bundle') {
|
|
settings.push(
|
|
...extension.entries.map((entry) => ({
|
|
enabled: true,
|
|
folder: entry.name,
|
|
bundle: extension.name,
|
|
source: source,
|
|
})),
|
|
);
|
|
}
|
|
|
|
return settings;
|
|
};
|
|
|
|
// default to enabled for app extension in developer mode
|
|
const extensionSettings = [
|
|
...Array.from(localExtensions.entries()).flatMap(([folder, extension]) =>
|
|
mockSetting('local', folder, extension),
|
|
),
|
|
...Array.from(moduleExtensions.entries()).flatMap(([folder, extension]) =>
|
|
mockSetting('module', folder, extension),
|
|
),
|
|
...Array.from(registryExtensions.entries()).flatMap(([folder, extension]) =>
|
|
mockSetting('registry', folder, extension),
|
|
),
|
|
];
|
|
|
|
extensionsEntrypoint = generateExtensionsEntrypoint(
|
|
{ module: moduleExtensions, local: localExtensions, registry: registryExtensions },
|
|
extensionSettings,
|
|
);
|
|
}
|
|
}
|