apostrophe 3.18.0 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.stylelintrc +2 -1
- package/CHANGELOG.md +23 -1
- package/lib/moog-require.js +7 -1
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +1 -1
- package/modules/@apostrophecms/asset/index.js +281 -24
- package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.config.js +7 -0
- package/modules/@apostrophecms/asset/lib/webpack/src/webpack.config.js +7 -0
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +10 -1
- package/modules/@apostrophecms/i18n/i18n/en.json +3 -0
- package/modules/@apostrophecms/i18n/i18n/es.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/sk.json +1 -0
- package/modules/@apostrophecms/image/ui/apos/components/AposImageCropper.vue +2 -2
- package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +5 -5
- package/modules/@apostrophecms/login/ui/apos/components/TheAposLoginHeader.vue +3 -2
- package/modules/@apostrophecms/schema/index.js +2 -1123
- package/modules/@apostrophecms/schema/lib/addFieldTypes.js +1139 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputDateAndTime.vue +115 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +21 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposSpinner.vue +7 -7
- package/modules/@apostrophecms/ui/ui/apos/components/AposToggle.vue +68 -0
- package/package.json +2 -3
- package/test/assets.js +462 -4
- package/test/schemas.js +25 -0
- package/test-lib/test.js +12 -0
- package/test-lib/util.js +4 -3
package/.stylelintrc
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 3.19.0
|
|
4
|
+
|
|
5
|
+
### Adds
|
|
6
|
+
|
|
7
|
+
* New schema field type `dateAndTime` added. This schema field type saves in ISO8601 format, as UTC (Universal Coordinated Time), but is edited in a user-friendly way in the user's current time zone and locale.
|
|
8
|
+
* Webpack disk cache for better build performance in development and, if appropriately configured, production as well.
|
|
9
|
+
* In development, Webpack rebuilds the front end without the need to restart the Node.js process, yielding an additional speedup. To get this speedup for existing projects, see the `nodemonConfig` section of the latest `package.json` in [a3-boilerplate](https://github.com/apostrophecms/a3-boilerplate) for the new "ignore" rules you'll need to prevent nodemon from stopping the process and restarting.
|
|
10
|
+
* Added the new command line task `apostrophecms/asset:clear-cache` for clearing the webpack disk cache. This should be necessary only in rare cases where the configuration has changed in ways Apostrophe can't automatically detect.
|
|
11
|
+
|
|
12
|
+
### 3.18.1
|
|
13
|
+
|
|
14
|
+
### Adds
|
|
15
|
+
|
|
16
|
+
* Webpack cache for build performance in development and production mode.
|
|
17
|
+
* Add a watcher in development mode to rebuild the assets on changes in the same process.
|
|
18
|
+
* Add asset task `apostrophecms/asset:clear-cache` for force clearing the webpack build cache.
|
|
19
|
+
|
|
20
|
+
### Fixes
|
|
21
|
+
|
|
22
|
+
* The admin UI now rebuilds properly in a development environment when new npm modules are installed in a multisite project (`apos.rootDir` differs from `apos.npmRootDir`).
|
|
23
|
+
|
|
24
|
+
## 3.18.0 (2022-05-03)
|
|
4
25
|
|
|
5
26
|
### Adds
|
|
6
27
|
|
|
@@ -26,6 +47,7 @@
|
|
|
26
47
|
* The `self.email` method of modules now correctly accepts a default `from` address configured for a specific module via the `from` subproperty of the `email` option to that module. Thanks to `chmdebeer` for pointing out the issue and the fix.
|
|
27
48
|
* Fixes `_urls` not added on attachment fields when pieces API index is requested (#3643)
|
|
28
49
|
* Fixes float field UI bug that transforms the value to integer when there is no field error and the first number after the decimal is `0`.
|
|
50
|
+
* The `nestedModuleSubdirs` feature no longer throws an error and interrupts startup if a project contains both `@apostrophecms/asset` and `asset`, which should be considered separate module names.
|
|
29
51
|
|
|
30
52
|
## 3.17.0 (2022-03-31)
|
|
31
53
|
|
package/lib/moog-require.js
CHANGED
|
@@ -5,6 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const glob = require('glob');
|
|
6
6
|
const importFresh = require('import-fresh');
|
|
7
7
|
const resolveFrom = require('resolve-from');
|
|
8
|
+
const regExpQuote = require('regexp-quote');
|
|
8
9
|
|
|
9
10
|
module.exports = function(options) {
|
|
10
11
|
const self = require('./moog')(options);
|
|
@@ -62,7 +63,12 @@ module.exports = function(options) {
|
|
|
62
63
|
self._indexes = glob.sync(self.options.localModules + '/**/index.js');
|
|
63
64
|
}
|
|
64
65
|
const matches = self._indexes.filter(function(index) {
|
|
65
|
-
|
|
66
|
+
// Double-check that we're not confusing "@apostrophecms/asset" with "asset" by
|
|
67
|
+
// making sure "type" is not preceded by an npm namespace folder. If type is itself namespaced
|
|
68
|
+
// this never comes up (because npm namespaces don't nest). The risk is that a legitimate
|
|
69
|
+
// project level module that happens to end with the same name as a namespaced module
|
|
70
|
+
// will be rejected as a duplicate when nestedModuleSubdirs is present
|
|
71
|
+
return index.endsWith('/' + type + '/index.js') && !index.match(new RegExp(`/@[^/]+/${regExpQuote(type)}/index\\.js$`));
|
|
66
72
|
});
|
|
67
73
|
if (matches.length > 1) {
|
|
68
74
|
throw new Error('The module ' + type + ' appears in multiple locations:\n' + matches.join('\n'));
|
|
@@ -4,10 +4,13 @@ const Promise = require('bluebird');
|
|
|
4
4
|
const webpackModule = require('webpack');
|
|
5
5
|
const globalIcons = require('./lib/globalIcons');
|
|
6
6
|
const path = require('path');
|
|
7
|
+
const util = require('util');
|
|
7
8
|
const express = require('express');
|
|
8
9
|
const { stripIndent } = require('common-tags');
|
|
9
10
|
const { merge: webpackMerge } = require('webpack-merge');
|
|
10
11
|
const cuid = require('cuid');
|
|
12
|
+
const chokidar = require('chokidar');
|
|
13
|
+
const _ = require('lodash');
|
|
11
14
|
const {
|
|
12
15
|
checkModulesWebpackConfig,
|
|
13
16
|
getWebpackExtensions,
|
|
@@ -28,7 +31,13 @@ module.exports = {
|
|
|
28
31
|
// If this option is true and process.env.NODE_ENV is not `production`,
|
|
29
32
|
// the browser will refresh when the Apostrophe application
|
|
30
33
|
// restarts. A useful companion to `nodemon`.
|
|
31
|
-
refreshOnRestart: false
|
|
34
|
+
refreshOnRestart: false,
|
|
35
|
+
// If false no UI assets sources will be watched in development.
|
|
36
|
+
// This option has no effect in production (watch disabled).
|
|
37
|
+
watch: true,
|
|
38
|
+
// Miliseconds to wait between asset sources changes before
|
|
39
|
+
// performing a build.
|
|
40
|
+
watchDebounceMs: 1000
|
|
32
41
|
},
|
|
33
42
|
|
|
34
43
|
async init(self) {
|
|
@@ -47,26 +56,17 @@ module.exports = {
|
|
|
47
56
|
self.extraBundles = fillExtraBundles(verifiedBundles);
|
|
48
57
|
self.webpackExtensions = extensions;
|
|
49
58
|
self.verifiedBundles = verifiedBundles;
|
|
59
|
+
self.buildWatcherEnable = process.env.APOS_ASSET_WATCH !== '0' && self.options.watch !== false;
|
|
60
|
+
self.buildWatcherDebounceMs = parseInt(self.options.watchDebounceMs || 1000, 10);
|
|
61
|
+
self.buildWatcher = null;
|
|
50
62
|
},
|
|
51
63
|
handlers (self) {
|
|
52
64
|
return {
|
|
53
65
|
'apostrophe:modulesRegistered': {
|
|
54
66
|
async runUiBuildTask() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Or if we're in production
|
|
59
|
-
process.env.NODE_ENV !== 'production' &&
|
|
60
|
-
// Or if we've set an app option to skip the auto build
|
|
61
|
-
self.apos.options.autoBuild !== false
|
|
62
|
-
) {
|
|
63
|
-
|
|
64
|
-
checkModulesWebpackConfig(self.apos.modules, self.apos.task.getReq().t);
|
|
65
|
-
// If starting up normally, run the build task, checking if we
|
|
66
|
-
// really need to update the apos build
|
|
67
|
-
await self.apos.task.invoke('@apostrophecms/asset:build', {
|
|
68
|
-
'check-apos-build': true
|
|
69
|
-
});
|
|
67
|
+
const ran = await self.autorunUiBuildTask();
|
|
68
|
+
if (ran) {
|
|
69
|
+
await self.watchUiAndRebuild();
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
injectAssetsPlaceholders() {
|
|
@@ -79,6 +79,12 @@ module.exports = {
|
|
|
79
79
|
if (self.uploadfs && (self.uploadfs !== self.apos.uploadfs)) {
|
|
80
80
|
await Promise.promisify(self.uploadfs.destroy)();
|
|
81
81
|
}
|
|
82
|
+
},
|
|
83
|
+
async destroyBuildWatcher() {
|
|
84
|
+
if (self.buildWatcher) {
|
|
85
|
+
await self.buildWatcher.close();
|
|
86
|
+
self.buildWatcher = null;
|
|
87
|
+
}
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
90
|
};
|
|
@@ -111,6 +117,8 @@ module.exports = {
|
|
|
111
117
|
usage: 'Build Apostrophe frontend CSS and JS bundles',
|
|
112
118
|
afterModuleInit: true,
|
|
113
119
|
async task(argv) {
|
|
120
|
+
// The lock could become huge, cache it, see computeCacheMeta()
|
|
121
|
+
let packageLockContentCached;
|
|
114
122
|
const req = self.apos.task.getReq();
|
|
115
123
|
const namespace = self.getNamespace();
|
|
116
124
|
const buildDir = `${self.apos.rootDir}/apos-build/${namespace}`;
|
|
@@ -317,7 +325,13 @@ module.exports = {
|
|
|
317
325
|
? webpackMerge(webpackInstanceConfig, ...Object.values(self.webpackExtensions))
|
|
318
326
|
: webpackInstanceConfig;
|
|
319
327
|
|
|
328
|
+
// Inject the cache location at the end - we need the merged
|
|
329
|
+
const cacheMeta = await computeCacheMeta(name, webpackInstanceConfigMerged);
|
|
330
|
+
webpackInstanceConfigMerged.cache.cacheLocation = cacheMeta.location;
|
|
331
|
+
|
|
320
332
|
const result = await webpack(webpackInstanceConfigMerged);
|
|
333
|
+
await writeCacheMeta(name, cacheMeta);
|
|
334
|
+
|
|
321
335
|
if (result.compilation.errors.length) {
|
|
322
336
|
// Throwing a string is appropriate in a command line task
|
|
323
337
|
throw cleanErrors(result.toString('errors'));
|
|
@@ -632,11 +646,9 @@ module.exports = {
|
|
|
632
646
|
async function lockFileIsNewer(name) {
|
|
633
647
|
const timestamp = fs.readFileSync(`${bundleDir}/${name}-build-timestamp.txt`, 'utf8');
|
|
634
648
|
let pkgStats;
|
|
635
|
-
|
|
636
|
-
if (
|
|
637
|
-
pkgStats = await fs.stat(
|
|
638
|
-
} else if (await fs.pathExists(`${self.apos.rootDir}/yarn.lock`)) {
|
|
639
|
-
pkgStats = await fs.stat(`${self.apos.rootDir}/yarn.lock`);
|
|
649
|
+
const packageLock = await findPackageLock();
|
|
650
|
+
if (packageLock) {
|
|
651
|
+
pkgStats = await fs.stat(packageLock);
|
|
640
652
|
}
|
|
641
653
|
|
|
642
654
|
const pkgTimestamp = pkgStats && pkgStats.mtimeMs;
|
|
@@ -644,6 +656,18 @@ module.exports = {
|
|
|
644
656
|
return pkgTimestamp > parseInt(timestamp);
|
|
645
657
|
}
|
|
646
658
|
|
|
659
|
+
async function findPackageLock() {
|
|
660
|
+
const packageLockPath = path.join(self.apos.npmRootDir, 'package-lock.json');
|
|
661
|
+
const yarnPath = path.join(self.apos.npmRootDir, 'yarn.lock');
|
|
662
|
+
if (await fs.pathExists(packageLockPath)) {
|
|
663
|
+
return packageLockPath;
|
|
664
|
+
} else if (await fs.pathExists(yarnPath)) {
|
|
665
|
+
return yarnPath;
|
|
666
|
+
} else {
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
647
671
|
function getComponentName(component, { enumerateImports } = {}, i) {
|
|
648
672
|
return path
|
|
649
673
|
.basename(component)
|
|
@@ -657,6 +681,93 @@ module.exports = {
|
|
|
657
681
|
// confused by this
|
|
658
682
|
return errors.replace(/(ERROR in[\s\S]*?Module parse failed[\s\S]*)You may need an appropriate loader.*/, '$1');
|
|
659
683
|
}
|
|
684
|
+
|
|
685
|
+
// A (CPU intensive) webpack cache helper to compute a hash and build paths.
|
|
686
|
+
// Cache the result when possible.
|
|
687
|
+
// The base cache path is by default `data/temp/webpack-cache`
|
|
688
|
+
// but it can be overridden by an APOS_ASSET_CACHE environment.
|
|
689
|
+
// In order to compute an accurate hash, this helper needs
|
|
690
|
+
// the final, merged webpack configuration.
|
|
691
|
+
async function computeCacheMeta(name, webpackConfig) {
|
|
692
|
+
const cacheBase = self.getCacheBasePath();
|
|
693
|
+
|
|
694
|
+
if (!packageLockContentCached) {
|
|
695
|
+
const packageLock = await findPackageLock();
|
|
696
|
+
if (packageLock === false) {
|
|
697
|
+
// this should happen only when testing and
|
|
698
|
+
// we don't want to break all non-core module tests
|
|
699
|
+
packageLockContentCached = 'none';
|
|
700
|
+
} else {
|
|
701
|
+
packageLockContentCached = await fs.readFile(packageLock, 'utf8');
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Plugins can output timestamps or other random information as
|
|
706
|
+
// configuration (e.g. StylelintWebpackPlugin). As we don't have
|
|
707
|
+
// control over plugins, we need to remove their configuration values.
|
|
708
|
+
// We keep only the plugin name and config keys sorted list.
|
|
709
|
+
// Additionally plugins are sorted by their constructor names.
|
|
710
|
+
// A shallow clone is enough to avoid modification of the original
|
|
711
|
+
// config.
|
|
712
|
+
const config = { ...webpackConfig };
|
|
713
|
+
config.plugins = (config.plugins || []).map(p => {
|
|
714
|
+
const result = [];
|
|
715
|
+
if (p.constructor && p.constructor.name) {
|
|
716
|
+
result.push(p.constructor.name);
|
|
717
|
+
}
|
|
718
|
+
const keys = Object.keys(p);
|
|
719
|
+
keys.sort();
|
|
720
|
+
result.push(...keys);
|
|
721
|
+
return result;
|
|
722
|
+
});
|
|
723
|
+
config.plugins.sort((a, b) => (a[0] || '').localeCompare(b[0]));
|
|
724
|
+
const configString = util.inspect(config, {
|
|
725
|
+
depth: 10,
|
|
726
|
+
compact: true,
|
|
727
|
+
breakLength: Infinity
|
|
728
|
+
});
|
|
729
|
+
const hash = self.apos.util.md5(
|
|
730
|
+
`${self.getNamespace()}:${name}:${packageLockContentCached}:${configString}`
|
|
731
|
+
);
|
|
732
|
+
const location = path.resolve(cacheBase, hash);
|
|
733
|
+
|
|
734
|
+
return {
|
|
735
|
+
base: cacheBase,
|
|
736
|
+
hash,
|
|
737
|
+
location
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Add .apos, useful for debugging, testing and cache invalidation.
|
|
742
|
+
// It also keeps in sync the modified time of the cache folder.
|
|
743
|
+
async function writeCacheMeta(name, cacheMeta) {
|
|
744
|
+
try {
|
|
745
|
+
const cachePath = path.join(cacheMeta.location, '.apos');
|
|
746
|
+
const lastModified = new Date();
|
|
747
|
+
await fs.writeFile(
|
|
748
|
+
cachePath,
|
|
749
|
+
`${lastModified.toISOString()} ${self.getNamespace()}:${name}`,
|
|
750
|
+
'utf8'
|
|
751
|
+
);
|
|
752
|
+
// should be the same as the meta
|
|
753
|
+
await fs.utimes(cachePath, lastModified, lastModified);
|
|
754
|
+
} catch (e) {
|
|
755
|
+
// Build probably failed, path is missing, ignore
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
|
|
761
|
+
'clear-cache': {
|
|
762
|
+
usage: 'Clear build cache',
|
|
763
|
+
afterModuleInit: true,
|
|
764
|
+
async task(argv) {
|
|
765
|
+
const cacheBaseDir = self.getCacheBasePath();
|
|
766
|
+
|
|
767
|
+
await fs.emptyDir(cacheBaseDir);
|
|
768
|
+
self.apos.util.log(
|
|
769
|
+
self.apos.task.getReq().t('apostrophe:assetWebpackCacheCleared')
|
|
770
|
+
);
|
|
660
771
|
}
|
|
661
772
|
}
|
|
662
773
|
};
|
|
@@ -757,6 +868,144 @@ module.exports = {
|
|
|
757
868
|
return `/apos-frontend/${namespace}`;
|
|
758
869
|
}
|
|
759
870
|
},
|
|
871
|
+
getCacheBasePath() {
|
|
872
|
+
return process.env.APOS_ASSET_CACHE ||
|
|
873
|
+
path.join(self.apos.rootDir, 'data/temp/webpack-cache');
|
|
874
|
+
},
|
|
875
|
+
// Run build task automatically when appropriate
|
|
876
|
+
async autorunUiBuildTask() {
|
|
877
|
+
if (
|
|
878
|
+
// Do not automatically build the UI if we're starting from a task
|
|
879
|
+
!self.apos.isTask() &&
|
|
880
|
+
// Or if we're in production
|
|
881
|
+
process.env.NODE_ENV !== 'production' &&
|
|
882
|
+
// Or if we've set an app option to skip the auto build
|
|
883
|
+
self.apos.options.autoBuild !== false
|
|
884
|
+
) {
|
|
885
|
+
|
|
886
|
+
checkModulesWebpackConfig(self.apos.modules, self.apos.task.getReq().t);
|
|
887
|
+
// If starting up normally, run the build task, checking if we
|
|
888
|
+
// really need to update the apos build
|
|
889
|
+
await self.apos.task.invoke('@apostrophecms/asset:build', {
|
|
890
|
+
'check-apos-build': true
|
|
891
|
+
});
|
|
892
|
+
return true;
|
|
893
|
+
}
|
|
894
|
+
return false;
|
|
895
|
+
},
|
|
896
|
+
// Start watching assets from `modules/` and
|
|
897
|
+
// every symlinked package found in `node_modules/`.
|
|
898
|
+
// `rebuildCallback` is invoked with queue length argument
|
|
899
|
+
// on actual build attempt only.
|
|
900
|
+
// It's there mainly for testing and debugging purposes.
|
|
901
|
+
async watchUiAndRebuild(rebuildCallback) {
|
|
902
|
+
if (!self.buildWatcherEnable || self.buildWatcher) {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
const rootDir = self.apos.rootDir;
|
|
906
|
+
// chokidar may invoke ready event multiple times,
|
|
907
|
+
// we want one "watch enabled" message.
|
|
908
|
+
let loggedOnce = false;
|
|
909
|
+
const logOnce = (...msg) => {
|
|
910
|
+
if (!loggedOnce) {
|
|
911
|
+
self.apos.util.log(...msg);
|
|
912
|
+
loggedOnce = true;
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
const error = self.apos.util.error;
|
|
916
|
+
const queue = [];
|
|
917
|
+
let queueLength = 0;
|
|
918
|
+
let queueRunning = false;
|
|
919
|
+
|
|
920
|
+
const debounceRebuild = _.debounce(chain, self.buildWatcherDebounceMs, {
|
|
921
|
+
leading: false,
|
|
922
|
+
trailing: true
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
const symLinkModules = await findSymlinks();
|
|
926
|
+
const watchDirs = [
|
|
927
|
+
'./modules/**/ui/apos/**',
|
|
928
|
+
'./modules/**/ui/src/**',
|
|
929
|
+
'./modules/**/ui/public/**',
|
|
930
|
+
...symLinkModules.reduce(
|
|
931
|
+
(prev, m) => [
|
|
932
|
+
...prev,
|
|
933
|
+
`./node_modules/${m}/modules/**/ui/apos/**`,
|
|
934
|
+
`./node_modules/${m}/modules/**/ui/src/**`,
|
|
935
|
+
`./node_modules/${m}/modules/**/ui/public/**`
|
|
936
|
+
],
|
|
937
|
+
[]
|
|
938
|
+
)
|
|
939
|
+
];
|
|
940
|
+
self.buildWatcher = chokidar.watch(watchDirs, {
|
|
941
|
+
cwd: rootDir,
|
|
942
|
+
ignoreInitial: true
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
self.buildWatcher
|
|
946
|
+
.on('add', debounceRebuild)
|
|
947
|
+
.on('change', debounceRebuild)
|
|
948
|
+
.on('unlink', debounceRebuild)
|
|
949
|
+
.on('addDir', debounceRebuild)
|
|
950
|
+
.on('unlinkDir', debounceRebuild)
|
|
951
|
+
.on('error', e => error(`Watcher error: ${e}`))
|
|
952
|
+
.on('ready', () => logOnce(
|
|
953
|
+
self.apos.task.getReq().t('apostrophe:assetBuildWatchStarted')
|
|
954
|
+
));
|
|
955
|
+
|
|
956
|
+
async function rebuild() {
|
|
957
|
+
await self.autorunUiBuildTask();
|
|
958
|
+
self.restartId = self.apos.util.generateId();
|
|
959
|
+
if (typeof rebuildCallback === 'function') {
|
|
960
|
+
rebuildCallback(queueLength);
|
|
961
|
+
};
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
// Simple, capped, self-exhausting queue implementation.
|
|
965
|
+
function enqueue(fn) {
|
|
966
|
+
if (queueLength === 2) {
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
queue.push(fn);
|
|
970
|
+
queueLength++;
|
|
971
|
+
};
|
|
972
|
+
async function dequeue() {
|
|
973
|
+
if (!queueLength) {
|
|
974
|
+
queueRunning = false;
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
queueRunning = true;
|
|
978
|
+
await queue.pop()();
|
|
979
|
+
queueLength--;
|
|
980
|
+
await dequeue();
|
|
981
|
+
}
|
|
982
|
+
async function chain(f) {
|
|
983
|
+
enqueue(rebuild);
|
|
984
|
+
if (!queueRunning) {
|
|
985
|
+
await dequeue();
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Find all symlinks in node modules.
|
|
990
|
+
// This would find both `module-name` and `@company/module-name`
|
|
991
|
+
// package symlinks
|
|
992
|
+
async function findSymlinks(sub = '') {
|
|
993
|
+
let result = [];
|
|
994
|
+
const handle = await fs.promises.opendir(path.join(rootDir, 'node_modules', sub));
|
|
995
|
+
let mod = await handle.read();
|
|
996
|
+
while (mod) {
|
|
997
|
+
if (mod.isSymbolicLink()) {
|
|
998
|
+
result.push(sub + mod.name);
|
|
999
|
+
} else if (!sub && mod.name.startsWith('@')) {
|
|
1000
|
+
const dres = await findSymlinks(`${mod.name}/`);
|
|
1001
|
+
result = [ ...result, ...dres ];
|
|
1002
|
+
}
|
|
1003
|
+
mod = await handle.read();
|
|
1004
|
+
}
|
|
1005
|
+
await handle.close();
|
|
1006
|
+
return result;
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
760
1009
|
// An implementation method that you should not need to call.
|
|
761
1010
|
// Sets a predetermined configuration for the frontend builds.
|
|
762
1011
|
// If you are trying to enable IE11 support for ui/src, use the
|
|
@@ -903,9 +1152,17 @@ module.exports = {
|
|
|
903
1152
|
// Long polling: keep the logs quiet by responding slowly, except the
|
|
904
1153
|
// first time. If we restart, the request will fail immediately,
|
|
905
1154
|
// and the client will know to try again with `fast`. The client also
|
|
906
|
-
// uses `fast` the first time
|
|
907
|
-
if (
|
|
908
|
-
|
|
1155
|
+
// uses `fast` the first time.
|
|
1156
|
+
if (req.query.fast) {
|
|
1157
|
+
return self.restartId;
|
|
1158
|
+
}
|
|
1159
|
+
// Long polling will be interrupted if restartId changes.
|
|
1160
|
+
let delay = 30000;
|
|
1161
|
+
const step = 300;
|
|
1162
|
+
const oldRestartId = self.restartId;
|
|
1163
|
+
while (delay > 0 && oldRestartId === self.restartId) {
|
|
1164
|
+
delay -= step;
|
|
1165
|
+
await Promise.delay(step);
|
|
909
1166
|
}
|
|
910
1167
|
return self.restartId;
|
|
911
1168
|
}
|
|
@@ -33,6 +33,13 @@ module.exports = ({
|
|
|
33
33
|
path: outputPath,
|
|
34
34
|
filename: outputFilename
|
|
35
35
|
},
|
|
36
|
+
// cacheLocation will be added dynamically later
|
|
37
|
+
cache: {
|
|
38
|
+
type: 'filesystem',
|
|
39
|
+
buildDependencies: {
|
|
40
|
+
config: [ __filename ]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
36
43
|
// we could extend this with aliases for other apostrophe modules
|
|
37
44
|
// at a later date if needed
|
|
38
45
|
resolveLoader: {
|
|
@@ -50,6 +50,13 @@ module.exports = ({
|
|
|
50
50
|
: `[name]-${moduleName}-bundle.js`;
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
|
+
// cacheLocation will be added dynamically later
|
|
54
|
+
cache: {
|
|
55
|
+
type: 'filesystem',
|
|
56
|
+
buildDependencies: {
|
|
57
|
+
config: [ __filename ]
|
|
58
|
+
}
|
|
59
|
+
},
|
|
53
60
|
resolveLoader: {
|
|
54
61
|
extensions: [ '*', '.js' ],
|
|
55
62
|
// Make sure css-loader and postcss-loader can always be found, even
|
|
@@ -125,6 +125,11 @@ export default {
|
|
|
125
125
|
AposAdvisoryLockMixin,
|
|
126
126
|
AposArchiveMixin
|
|
127
127
|
],
|
|
128
|
+
provide () {
|
|
129
|
+
return {
|
|
130
|
+
originalDoc: this.originalDoc
|
|
131
|
+
};
|
|
132
|
+
},
|
|
128
133
|
props: {
|
|
129
134
|
moduleName: {
|
|
130
135
|
type: String,
|
|
@@ -153,6 +158,9 @@ export default {
|
|
|
153
158
|
},
|
|
154
159
|
triggerValidation: false,
|
|
155
160
|
original: null,
|
|
161
|
+
originalDoc: {
|
|
162
|
+
ref: null
|
|
163
|
+
},
|
|
156
164
|
published: null,
|
|
157
165
|
errorCount: 0,
|
|
158
166
|
restoreOnly: false,
|
|
@@ -363,7 +371,8 @@ export default {
|
|
|
363
371
|
manuallyPublished() {
|
|
364
372
|
this.saveMenu = this.computeSaveMenu();
|
|
365
373
|
},
|
|
366
|
-
original() {
|
|
374
|
+
original(newVal) {
|
|
375
|
+
this.originalDoc.ref = newVal;
|
|
367
376
|
this.saveMenu = this.computeSaveMenu();
|
|
368
377
|
},
|
|
369
378
|
tabs() {
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"assetTypeBuilding": "🧑💻 Building the {{ label }}...",
|
|
36
36
|
"assetWebpackConfigWarning": "⚠️ In the module {{ module }}, your webpack config is incorrect. It must be an object and should contain only two properties extensions and bundles.",
|
|
37
37
|
"assetWebpackBundlesWarning": "⚠️ In the module {{ module }} your webpack config is incorrect. Each bundle can only have one property 'templates' that must be an array of strings.",
|
|
38
|
+
"assetWebpackCacheCleared": "Build cache cleared.",
|
|
39
|
+
"assetBuildWatchStarted": "Watching for UI changes...",
|
|
40
|
+
"at": "at",
|
|
38
41
|
"back": "Back",
|
|
39
42
|
"backToHome": "Back to Home",
|
|
40
43
|
"basics": "Basics",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"archivingWillLoseDraftChanges": "Cambios al borrador de este {{ type }} sin publicar serán eliminados permanentemente.",
|
|
26
26
|
"archivingWillUnpublish": "Esto también despublicará el {{ type }}.",
|
|
27
27
|
"areYouSure": "¿Está Seguro?",
|
|
28
|
+
"at": "a las",
|
|
28
29
|
"aspectRatio": "Relación de aspecto",
|
|
29
30
|
"aspectRatioFree": "Libre",
|
|
30
31
|
"aspectRatioWarning": "La relación de aspecto no se puede cambiar para este widget",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"aspectRatioWarning": "A proporção não pode ser alterada para este widget",
|
|
31
31
|
"assetTypeBuildComplete": "👍 {{ label }} completado!",
|
|
32
32
|
"assetTypeBuilding": "🧑💻 Fazendo o build: {{ label }}...",
|
|
33
|
+
"at": "às",
|
|
33
34
|
"back": "Voltar",
|
|
34
35
|
"backToHome": "Voltar ao início",
|
|
35
36
|
"basics": "Básico",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"aspectRatioWarning": "Pre túto miniaplikáciu nie je možné zmeniť pomer strán",
|
|
34
34
|
"assetTypeBuildComplete": "👍 {{ label }} je kompletný!",
|
|
35
35
|
"assetTypeBuilding": "🧑💻 Budovanie {{ label }}...",
|
|
36
|
+
"at": "o",
|
|
36
37
|
"back": "Naspäť",
|
|
37
38
|
"backToHome": "Naspäť na domovskú stránku",
|
|
38
39
|
"basics": "Základy",
|
|
@@ -428,15 +428,15 @@ export default {
|
|
|
428
428
|
// flex-grow: 0;
|
|
429
429
|
|
|
430
430
|
.apos-image-focal-point {
|
|
431
|
+
z-index: $z-index-default;
|
|
431
432
|
position: absolute;
|
|
432
|
-
z-index: 1;
|
|
433
433
|
width: 10px;
|
|
434
434
|
height: 10px;
|
|
435
435
|
border-radius: 50%;
|
|
436
436
|
border: 1px solid var(--a-white);
|
|
437
437
|
background-color: var(--a-primary);
|
|
438
438
|
box-shadow: 0 0 4px var(--a-black);
|
|
439
|
-
transition: left 0.
|
|
439
|
+
transition: left 0.15s ease, top 0.15s ease;
|
|
440
440
|
cursor: grab;
|
|
441
441
|
}
|
|
442
442
|
}
|
|
@@ -427,7 +427,7 @@ export default {
|
|
|
427
427
|
.apos-schema {
|
|
428
428
|
margin: 30px 15px 0;
|
|
429
429
|
|
|
430
|
-
|
|
430
|
+
.apos-field {
|
|
431
431
|
margin-bottom: 20px;
|
|
432
432
|
|
|
433
433
|
&__label {
|
|
@@ -448,9 +448,9 @@ export default {
|
|
|
448
448
|
flex-direction: row;
|
|
449
449
|
|
|
450
450
|
.apos-field {
|
|
451
|
+
position: relative;
|
|
451
452
|
display: flex;
|
|
452
453
|
align-items: center;
|
|
453
|
-
position: relative;
|
|
454
454
|
flex-grow: 1;
|
|
455
455
|
|
|
456
456
|
&:first-child {
|
|
@@ -472,7 +472,7 @@ export default {
|
|
|
472
472
|
}
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
.apos-input[type=
|
|
475
|
+
.apos-input[type='number'] {
|
|
476
476
|
padding-right: 5px;
|
|
477
477
|
}
|
|
478
478
|
|
|
@@ -495,16 +495,16 @@ export default {
|
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
.apos-field__label--aligned {
|
|
498
|
-
margin: 0
|
|
498
|
+
margin: 0;
|
|
499
499
|
}
|
|
500
500
|
|
|
501
501
|
.apos-image-cropper__container {
|
|
502
502
|
display: flex;
|
|
503
503
|
justify-content: center;
|
|
504
504
|
align-items: center;
|
|
505
|
-
margin: 30px 10%;
|
|
506
505
|
// We remove the modal's paddings - header height - container margin
|
|
507
506
|
height: calc(100vh - 40px - 75px - 60px);
|
|
507
|
+
margin: 30px 10%;
|
|
508
508
|
box-sizing: border-box;
|
|
509
509
|
}
|
|
510
510
|
</style>
|
|
@@ -89,15 +89,16 @@ export default {
|
|
|
89
89
|
|
|
90
90
|
&__header--tiny {
|
|
91
91
|
flex-direction: row;
|
|
92
|
+
// stylelint-disable-next-line scale-unlimited/declaration-strict-value
|
|
92
93
|
color: #F8F9FA;
|
|
93
94
|
|
|
94
95
|
.apos-login__project {
|
|
95
|
-
opacity: 0.7
|
|
96
|
+
opacity: 0.7;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
.apos-login__project-name {
|
|
100
|
+
// stylelint-disable-next-line scale-unlimited/declaration-strict-value
|
|
99
101
|
font-size: 21px;
|
|
100
|
-
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
.apos-login__project-env {
|