mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) updates from grist-core
This commit is contained in:
@@ -41,7 +41,7 @@ export type PageType =
|
||||
| "billing"
|
||||
| "welcome"
|
||||
| "account"
|
||||
| "support-grist"
|
||||
| "support"
|
||||
| "activation";
|
||||
|
||||
const G = getBrowserGlobals('document', 'window');
|
||||
@@ -316,7 +316,7 @@ export class AppModelImpl extends Disposable implements AppModel {
|
||||
} else if (state.account) {
|
||||
return 'account';
|
||||
} else if (state.supportGrist) {
|
||||
return 'support-grist';
|
||||
return 'support';
|
||||
} else if (state.activation) {
|
||||
return 'activation';
|
||||
} else {
|
||||
|
||||
@@ -226,7 +226,7 @@ export class AccountWidget extends Disposable {
|
||||
return menuItemLink(
|
||||
t('Support Grist'),
|
||||
cssHeartIcon('💛'),
|
||||
urlState().setLinkUrl({supportGrist: 'support-grist'}),
|
||||
urlState().setLinkUrl({supportGrist: 'support'}),
|
||||
testId('usermenu-support-grist'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ function createMainPage(appModel: AppModel, appObj: App) {
|
||||
return dom.create(WelcomePage, appModel);
|
||||
} else if (pageType === 'account') {
|
||||
return domAsync(loadAccountPage().then(ap => dom.create(ap.AccountPage, appModel)));
|
||||
} else if (pageType === 'support-grist') {
|
||||
} else if (pageType === 'support') {
|
||||
return domAsync(loadSupportGristPage().then(sgp => dom.create(sgp.SupportGristPage, appModel)));
|
||||
} else if (pageType === 'activation') {
|
||||
return domAsync(loadActivationPage().then(ap => dom.create(ap.ActivationPage, appModel)));
|
||||
|
||||
@@ -22,7 +22,7 @@ type ButtonState =
|
||||
| 'expanded';
|
||||
|
||||
type CardPage =
|
||||
| 'support-grist'
|
||||
| 'support'
|
||||
| 'opted-in';
|
||||
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ export class SupportGristNudge extends Disposable {
|
||||
this._buttonState = localStorageObs(
|
||||
`u=${this._appModel.currentValidUser?.id ?? 0};supportGristNudge`, 'expanded'
|
||||
) as Observable<ButtonState>;
|
||||
this._currentPage = Observable.create(null, 'support-grist');
|
||||
this._currentPage = Observable.create(null, 'support');
|
||||
this._isClosed = Observable.create(this, false);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export class SupportGristNudge extends Disposable {
|
||||
private _buildCard() {
|
||||
return cssCard(
|
||||
dom.domComputed(this._currentPage, page => {
|
||||
if (page === 'support-grist') {
|
||||
if (page === 'support') {
|
||||
return this._buildSupportGristCardContent();
|
||||
} else {
|
||||
return this._buildOptedInCardContent();
|
||||
@@ -205,7 +205,7 @@ function helpCenterLink() {
|
||||
function supportGristLink() {
|
||||
return cssLink(
|
||||
t('Support Grist page'),
|
||||
{href: urlState().makeUrl({supportGrist: 'support-grist'}), target: '_blank'},
|
||||
{href: urlState().makeUrl({supportGrist: 'support'}), target: '_blank'},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ export class SupportGristPage extends Disposable {
|
||||
const suffix = getPageTitleSuffix(getGristConfig());
|
||||
switch (page) {
|
||||
case undefined:
|
||||
case 'support-grist': {
|
||||
case 'support': {
|
||||
return document.title = `Support Grist${suffix}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export type ActivationPage = typeof ActivationPage.type;
|
||||
export const LoginPage = StringUnion('signup', 'login', 'verified', 'forgot-password');
|
||||
export type LoginPage = typeof LoginPage.type;
|
||||
|
||||
export const SupportGristPage = StringUnion('support-grist');
|
||||
export const SupportGristPage = StringUnion('support');
|
||||
export type SupportGristPage = typeof SupportGristPage.type;
|
||||
|
||||
// Overall UI style. "full" is normal, "singlePage" is a single page focused, panels hidden experience.
|
||||
@@ -408,8 +408,8 @@ export function decodeUrl(gristConfig: Partial<GristLoadConfig>, location: Locat
|
||||
state.activation = ActivationPage.parse(map.get('activation')) || 'activation';
|
||||
}
|
||||
if (map.has('welcome')) { state.welcome = WelcomePage.parse(map.get('welcome')); }
|
||||
if (map.has('support-grist')) {
|
||||
state.supportGrist = SupportGristPage.parse(map.get('support-grist')) || 'support-grist';
|
||||
if (map.has('support')) {
|
||||
state.supportGrist = SupportGristPage.parse(map.get('support')) || 'support';
|
||||
}
|
||||
if (sp.has('planType')) { state.params!.planType = sp.get('planType')!; }
|
||||
if (sp.has('billingPlan')) { state.params!.billingPlan = sp.get('billingPlan')!; }
|
||||
|
||||
@@ -212,6 +212,6 @@ export function attachAppEndpoint(options: AttachOptions): void {
|
||||
// The * is a wildcard in express 4, rather than a regex symbol.
|
||||
// See https://expressjs.com/en/guide/routing.html
|
||||
app.get('/doc/:urlId([^/]+):remainder(*)', ...docMiddleware, docHandler);
|
||||
app.get('/:urlId([^/]{12,})/:slug([^/]+):remainder(*)',
|
||||
app.get('/:urlId([^/]{12,})(/:slug([^/]+):remainder(*))?',
|
||||
...docMiddleware, docHandler);
|
||||
}
|
||||
|
||||
@@ -1998,8 +1998,13 @@ export class FlexServer implements GristServer {
|
||||
// Only used as {userRoot}/plugins as a place for plugins in addition to {appRoot}/plugins
|
||||
const userRoot = path.resolve(process.env.GRIST_USER_ROOT || getAppPathTo(this.appRoot, '.grist'));
|
||||
this.info.push(['userRoot', userRoot]);
|
||||
|
||||
const pluginManager = new PluginManager(this.appRoot, userRoot);
|
||||
// Some custom widgets may be included as an npm package called @gristlabs/grist-widget.
|
||||
const bundledRoot = isAffirmative(process.env.GRIST_SKIP_BUNDLED_WIDGETS) ? undefined : path.join(
|
||||
getAppPathTo(this.appRoot, 'node_modules'),
|
||||
'@gristlabs', 'grist-widget', 'dist'
|
||||
);
|
||||
this.info.push(['bundledRoot', bundledRoot]);
|
||||
const pluginManager = new PluginManager(this.appRoot, userRoot, bundledRoot);
|
||||
// `initialize()` is asynchronous and reads plugins manifests; if PluginManager is used before it
|
||||
// finishes, it will act as if there are no plugins.
|
||||
// ^ I think this comment was here to justify calling initialize without waiting for
|
||||
|
||||
@@ -46,7 +46,8 @@ function servePluginContent(req: express.Request, res: express.Response,
|
||||
req.get('X-From-Plugin-WebView') === "true" ||
|
||||
mimeTypes.lookup(path.extname(pluginPath)) === "application/javascript") {
|
||||
const dirs = pluginManager.dirs();
|
||||
const contentRoot = pluginKind === "installed" ? dirs.installed : dirs.builtIn;
|
||||
const contentRoot = pluginKind === "installed" ? dirs.installed :
|
||||
(pluginKind === "builtIn" ? dirs.builtIn : dirs.bundled);
|
||||
// Note that pluginPath may not be safe, but `sendFile` with the "root" option restricts
|
||||
// relative paths to be within the root folder (see the 3rd party library unit-test:
|
||||
// https://github.com/pillarjs/send/blob/3daa901cf731b86187e4449fa2c52f971e0b3dbc/test/send.js#L1363)
|
||||
|
||||
@@ -14,9 +14,14 @@ export interface PluginDirectories {
|
||||
*/
|
||||
readonly builtIn?: string;
|
||||
/**
|
||||
* Directory where user installed plugins are localted.
|
||||
* Directory where user installed plugins are located.
|
||||
*/
|
||||
readonly installed?: string;
|
||||
/**
|
||||
* Yet another option, for plugins that are included
|
||||
* during a build but not part of the codebase itself.
|
||||
*/
|
||||
readonly bundled?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,10 +49,12 @@ export class PluginManager {
|
||||
* @param {string} userRoot: path to user's grist directory; `null` is allowed, to only uses built in plugins.
|
||||
*
|
||||
*/
|
||||
public constructor(public appRoot?: string, userRoot?: string) {
|
||||
public constructor(public appRoot?: string, userRoot?: string,
|
||||
public bundledRoot?: string) {
|
||||
this._dirs = {
|
||||
installed: userRoot ? path.join(userRoot, 'plugins') : undefined,
|
||||
builtIn: appRoot ? getAppPathTo(appRoot, 'plugins') : undefined
|
||||
builtIn: appRoot ? getAppPathTo(appRoot, 'plugins') : undefined,
|
||||
bundled: bundledRoot ? getAppPathTo(bundledRoot, 'plugins') : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,6 +98,11 @@ export class PluginManager {
|
||||
this._entries.push(...await scanDirectory(this._dirs.builtIn, "builtIn"));
|
||||
}
|
||||
|
||||
// Load bundled plugins
|
||||
if (this._dirs.bundled) {
|
||||
this._entries.push(...await scanDirectory(this._dirs.bundled, "bundled"));
|
||||
}
|
||||
|
||||
if (!process.env.GRIST_EXPERIMENTAL_PLUGINS ||
|
||||
process.env.GRIST_EXPERIMENTAL_PLUGINS === '0') {
|
||||
// Remove experimental plugins
|
||||
@@ -130,7 +142,7 @@ export class PluginManager {
|
||||
}
|
||||
|
||||
|
||||
async function scanDirectory(dir: string, kind: "installed"|"builtIn"): Promise<DirectoryScanEntry[]> {
|
||||
async function scanDirectory(dir: string, kind: "installed"|"builtIn"|"bundled"): Promise<DirectoryScanEntry[]> {
|
||||
const plugins: DirectoryScanEntry[] = [];
|
||||
let listDir;
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ export class Telemetry implements ITelemetry {
|
||||
|
||||
public addPages(app: express.Application, middleware: express.RequestHandler[]) {
|
||||
if (this._deploymentType === 'core') {
|
||||
app.get('/support-grist', ...middleware, expressWrap(async (req, resp) => {
|
||||
app.get('/support', ...middleware, expressWrap(async (req, resp) => {
|
||||
return this._gristServer.sendAppPage(req, resp,
|
||||
{path: 'app.html', status: 200, config: {}});
|
||||
}));
|
||||
|
||||
@@ -142,6 +142,7 @@ export function getTypeORMSettings(): DataSourceOptions {
|
||||
"subscribers": [
|
||||
`${codeRoot}/app/gen-server/subscriber/*.js`
|
||||
],
|
||||
...JSON.parse(process.env.TYPEORM_EXTRA || "{}"),
|
||||
...cache,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user