commit
06acc47cdb
@ -1,160 +0,0 @@
|
|||||||
import { AppModel } from 'app/client/models/AppModel';
|
|
||||||
import { AdminChecks, ProbeDetails } from 'app/client/models/AdminChecks';
|
|
||||||
import { createAppPage } from 'app/client/ui/createAppPage';
|
|
||||||
import { pagePanels } from 'app/client/ui/PagePanels';
|
|
||||||
import { BootProbeInfo, BootProbeResult } from 'app/common/BootProbe';
|
|
||||||
import { getGristConfig } from 'app/common/urlUtils';
|
|
||||||
import { Disposable, dom, Observable, styled, UseCBOwner } from 'grainjs';
|
|
||||||
|
|
||||||
const cssBody = styled('div', `
|
|
||||||
padding: 20px;
|
|
||||||
overflow: auto;
|
|
||||||
`);
|
|
||||||
|
|
||||||
const cssHeader = styled('div', `
|
|
||||||
padding: 20px;
|
|
||||||
`);
|
|
||||||
|
|
||||||
const cssResult = styled('div', `
|
|
||||||
max-width: 500px;
|
|
||||||
`);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* A "boot" page for inspecting the state of the Grist installation.
|
|
||||||
*
|
|
||||||
* TODO: deferring using any localization machinery so as not
|
|
||||||
* to have to worry about its failure modes yet, but it should be
|
|
||||||
* fine as long as assets served locally are used.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export class Boot extends Disposable {
|
|
||||||
|
|
||||||
private _checks: AdminChecks;
|
|
||||||
|
|
||||||
constructor(_appModel: AppModel) {
|
|
||||||
super();
|
|
||||||
// Setting title in constructor seems to be how we are doing this,
|
|
||||||
// based on other similar pages.
|
|
||||||
document.title = 'Booting Grist';
|
|
||||||
this._checks = new AdminChecks(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the page. Uses the generic Grist layout with an empty
|
|
||||||
* side panel, just for convenience. Could be made a lot prettier.
|
|
||||||
*/
|
|
||||||
public buildDom() {
|
|
||||||
this._checks.fetchAvailableChecks().catch(e => reportError(e));
|
|
||||||
|
|
||||||
const config = getGristConfig();
|
|
||||||
const errMessage = config.errMessage;
|
|
||||||
const rootNode = dom('div',
|
|
||||||
dom.domComputed(
|
|
||||||
use => {
|
|
||||||
return pagePanels({
|
|
||||||
leftPanel: {
|
|
||||||
panelWidth: Observable.create(this, 240),
|
|
||||||
panelOpen: Observable.create(this, false),
|
|
||||||
hideOpener: true,
|
|
||||||
header: null,
|
|
||||||
content: null,
|
|
||||||
},
|
|
||||||
headerMain: cssHeader(dom('h1', 'Grist Boot')),
|
|
||||||
contentMain: this.buildBody(use, {errMessage}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return rootNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The body of the page is very simple right now, basically a
|
|
||||||
* placeholder. Make a section for each probe, and kick them off in
|
|
||||||
* parallel, showing results as they come in.
|
|
||||||
*/
|
|
||||||
public buildBody(use: UseCBOwner, options: {errMessage?: string}) {
|
|
||||||
if (options.errMessage) {
|
|
||||||
return cssBody(cssResult(this.buildError()));
|
|
||||||
}
|
|
||||||
return cssBody([
|
|
||||||
...use(this._checks.probes).map(probe => {
|
|
||||||
const req = this._checks.requestCheck(probe);
|
|
||||||
return cssResult(
|
|
||||||
this.buildResult(req.probe, use(req.result), req.details));
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is used when there is an attempt to access the boot page
|
|
||||||
* but something isn't right - either the page isn't enabled, or
|
|
||||||
* the key in the URL is wrong. Give the user some information about
|
|
||||||
* how to set things up.
|
|
||||||
*/
|
|
||||||
public buildError() {
|
|
||||||
return dom(
|
|
||||||
'div',
|
|
||||||
dom('p',
|
|
||||||
'A diagnostics page can be made available at:',
|
|
||||||
dom('blockquote', '/boot/GRIST_BOOT_KEY'),
|
|
||||||
'GRIST_BOOT_KEY is an environment variable ',
|
|
||||||
' set before Grist starts. It should only',
|
|
||||||
' contain characters that are valid in a URL.',
|
|
||||||
' It should be a secret, since no authentication is needed',
|
|
||||||
' to visit the diagnostics page.'),
|
|
||||||
dom('p',
|
|
||||||
'You are seeing this page because either the key is not set,',
|
|
||||||
' or it is not in the URL.'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An ugly rendering of information returned by the probe.
|
|
||||||
*/
|
|
||||||
public buildResult(info: BootProbeInfo, result: BootProbeResult,
|
|
||||||
details: ProbeDetails|undefined) {
|
|
||||||
const out: (HTMLElement|string|null)[] = [];
|
|
||||||
out.push(dom('h2', info.name));
|
|
||||||
if (details) {
|
|
||||||
out.push(dom('p', '> ', details.info));
|
|
||||||
}
|
|
||||||
if (result.verdict) {
|
|
||||||
out.push(dom('pre', result.verdict));
|
|
||||||
}
|
|
||||||
if (result.success !== undefined) {
|
|
||||||
out.push(result.success ? '✅' : '❌');
|
|
||||||
}
|
|
||||||
if (result.done === true) {
|
|
||||||
out.push(dom('p', 'no fault detected'));
|
|
||||||
}
|
|
||||||
if (result.details) {
|
|
||||||
for (const [key, val] of Object.entries(result.details)) {
|
|
||||||
out.push(dom(
|
|
||||||
'div',
|
|
||||||
cssLabel(key),
|
|
||||||
dom('input', dom.prop('value', JSON.stringify(val)))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a stripped down page to show boot information.
|
|
||||||
* Make sure the API isn't used since it may well be unreachable
|
|
||||||
* due to a misconfiguration, especially in multi-server setups.
|
|
||||||
*/
|
|
||||||
createAppPage(appModel => {
|
|
||||||
return dom.create(Boot, appModel);
|
|
||||||
}, {
|
|
||||||
useApi: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const cssLabel = styled('div', `
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 100px;
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 5px;
|
|
||||||
`);
|
|
@ -0,0 +1,22 @@
|
|||||||
|
import { checkMinIOBucket, checkMinIOExternalStorage,
|
||||||
|
configureMinIOExternalStorage } from 'app/server/lib/configureMinIOExternalStorage';
|
||||||
|
import { makeSimpleCreator } from 'app/server/lib/ICreate';
|
||||||
|
import { Telemetry } from 'app/server/lib/Telemetry';
|
||||||
|
|
||||||
|
export const makeCoreCreator = () => makeSimpleCreator({
|
||||||
|
deploymentType: 'core',
|
||||||
|
// This can and should be overridden by GRIST_SESSION_SECRET
|
||||||
|
// (or generated randomly per install, like grist-omnibus does).
|
||||||
|
sessionSecret: 'Phoo2ag1jaiz6Moo2Iese2xoaphahbai3oNg7diemohlah0ohtae9iengafieS2Hae7quungoCi9iaPh',
|
||||||
|
storage: [
|
||||||
|
{
|
||||||
|
name: 'minio',
|
||||||
|
check: () => checkMinIOExternalStorage() !== undefined,
|
||||||
|
checkBackend: () => checkMinIOBucket(),
|
||||||
|
create: configureMinIOExternalStorage,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
telemetry: {
|
||||||
|
create: (dbManager, gristServer) => new Telemetry(dbManager, gristServer),
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,12 @@
|
|||||||
|
import { getForwardAuthLoginSystem } from 'app/server/lib/ForwardAuthLogin';
|
||||||
|
import { GristLoginSystem } from 'app/server/lib/GristServer';
|
||||||
|
import { getMinimalLoginSystem } from 'app/server/lib/MinimalLogin';
|
||||||
|
import { getOIDCLoginSystem } from 'app/server/lib/OIDCConfig';
|
||||||
|
import { getSamlLoginSystem } from 'app/server/lib/SamlConfig';
|
||||||
|
|
||||||
|
export async function getCoreLoginSystem(): Promise<GristLoginSystem> {
|
||||||
|
return await getSamlLoginSystem() ||
|
||||||
|
await getOIDCLoginSystem() ||
|
||||||
|
await getForwardAuthLoginSystem() ||
|
||||||
|
await getMinimalLoginSystem();
|
||||||
|
}
|
@ -1,15 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf8">
|
|
||||||
<!-- INSERT BASE -->
|
|
||||||
<link rel="icon" type="image/x-icon" href="icons/favicon.png" />
|
|
||||||
<link rel="stylesheet" href="icons/icons.css">
|
|
||||||
<!-- INSERT LOCALE -->
|
|
||||||
<!-- INSERT CONFIG -->
|
|
||||||
<title>Loading...<!-- INSERT TITLE SUFFIX --></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script crossorigin="anonymous" src="boot.bundle.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"ACUserManager": {
|
||||||
|
"Enter email address": "Vložiť emailovú adresu",
|
||||||
|
"Invite new member": "Pozvať nového člena",
|
||||||
|
"We'll email an invite to {{email}}": "Pozvánku poslať e-mailom na adresu {{email}}"
|
||||||
|
},
|
||||||
|
"AccessRules": {
|
||||||
|
"Add Default Rule": "Pridať predvolené pravidlo",
|
||||||
|
"Add Column Rule": "Pridať pravidlo stĺpca",
|
||||||
|
"Add Table Rules": "Pridať pravidlá tabuľky",
|
||||||
|
"Add User Attributes": "Pridať používateľské atribúty",
|
||||||
|
"Allow everyone to view Access Rules.": "Umožniť každému zobraziť Prístupové Pravidlá.",
|
||||||
|
"Attribute name": "Názov atribútu",
|
||||||
|
"Checking...": "Kontroluje sa…",
|
||||||
|
"Condition": "Podmienka",
|
||||||
|
"Default Rules": "Predvolené Pravidlá",
|
||||||
|
"Delete Table Rules": "Odstrániť Pravidlá Tabuľky",
|
||||||
|
"Enter Condition": "Zadať Podmienku",
|
||||||
|
"Everyone": "Každý",
|
||||||
|
"Everyone Else": "Hocikto Iný",
|
||||||
|
"Invalid": "Neplatné",
|
||||||
|
"Attribute to Look Up": "Vyhľadávaný Atribút",
|
||||||
|
"Lookup Column": "Vyhľadávací stĺpec",
|
||||||
|
"Lookup Table": "Vyhľadávacia Tabuľka",
|
||||||
|
"Permission to access the document in full when needed": "Povolenie na úplný prístup k dokumentu v prípade potreby",
|
||||||
|
"Permission to view Access Rules": "Povolenie na zobrazenie Prístupových Pravidiel",
|
||||||
|
"Permissions": "Povolenia",
|
||||||
|
"Remove column {{- colId }} from {{- tableId }} rules": "Odstrániť stĺpec {{- colId }} z pravidiel {{- tableId }}",
|
||||||
|
"Remove {{- tableId }} rules": "Odstrániť pravidlá {{- tableId }}",
|
||||||
|
"Reset": "Reset",
|
||||||
|
"Rules for table ": "Pravidlá pre tabuľku ",
|
||||||
|
"Save": "Uložiť",
|
||||||
|
"Special Rules": "Špeciálné pravidlá",
|
||||||
|
"Type a message...": "Napísať správu…",
|
||||||
|
"User Attributes": "Používateľské Atribúty",
|
||||||
|
"View As": "Zobraziť Ako",
|
||||||
|
"Seed rules": "Seed Pravidlá",
|
||||||
|
"When adding table rules, automatically add a rule to grant OWNER full access.": "Pri pridávaní pravidiel tabuľky automaticky pridať pravidlo na udelenie úplného prístupu VLASTNÍKOVI.",
|
||||||
|
"Permission to edit document structure": "Povolenie upravovať štruktúru dokumentu",
|
||||||
|
"This default should be changed if editors' access is to be limited. ": "Toto predvolené nastavenie by sa malo zmeniť, ak má byť prístup redaktorov obmedzený. ",
|
||||||
|
"Allow everyone to copy the entire document, or view it in full in fiddle mode.\nUseful for examples and templates, but not for sensitive data.": "Umožnite každému skopírovať celý dokument alebo ho zobraziť celý vo fiddle móde.\n Užitočné pre príklady a šablóny, ale nie pre citlivé údaje.",
|
||||||
|
"Saved": "Uložené",
|
||||||
|
"Allow editors to edit structure (e.g. modify and delete tables, columns, layouts), and to write formulas, which give access to all data regardless of read restrictions.": "Umožniť editorom upravovať štruktúru (napr. upravovať a mazať tabuľky, stĺpce, rozloženia) a písať vzorce, ktoré umožňujú prístup ku všetkým údajom bez ohľadu na obmedzenia čítania.",
|
||||||
|
"Remove {{- name }} user attribute": "Odstrániť používateľský atribút {{- name }}"
|
||||||
|
},
|
||||||
|
"AccountPage": {
|
||||||
|
"API": "API",
|
||||||
|
"API Key": "API Kľúč",
|
||||||
|
"Account settings": "Nastavenia účtu",
|
||||||
|
"Allow signing in to this account with Google": "Povoliť prihlásenie do tohto účtu pomocou Google",
|
||||||
|
"Change Password": "Zmeniť Heslo",
|
||||||
|
"Login Method": "Metóda Prihlásenia",
|
||||||
|
"Password & Security": "Heslo a Zabezpečenie",
|
||||||
|
"Save": "Uložiť",
|
||||||
|
"Theme": "Téma",
|
||||||
|
"Two-factor authentication": "Dvojvázové overenie",
|
||||||
|
"Two-factor authentication is an extra layer of security for your Grist account designed to ensure that you're the only person who can access your account, even if someone knows your password.": "Dvojfázová autentifikácia je ďalšou vrstvou zabezpečenia vášho účtu Grist, ktorá je navrhnutá tak, aby zaistila, že ste jedinou osobou, ktorá môže pristupovať k vášmu účtu, aj keď niekto pozná vaše heslo.",
|
||||||
|
"Language": "Jazyk",
|
||||||
|
"Edit": "Upraviť",
|
||||||
|
"Email": "E-mail",
|
||||||
|
"Names only allow letters, numbers and certain special characters": "Názvy povoľujú iba písmená, čísla a určité špeciálne znaky",
|
||||||
|
"Name": "Meno"
|
||||||
|
},
|
||||||
|
"AccountWidget": {
|
||||||
|
"Access Details": "Prístupové podrobnosti",
|
||||||
|
"Accounts": "Účty",
|
||||||
|
"Add Account": "Pridať účet",
|
||||||
|
"Document Settings": "Nastavenie Dokumentu",
|
||||||
|
"Manage Team": "Spravovať tím",
|
||||||
|
"Pricing": "Cenník",
|
||||||
|
"Profile Settings": "Nastavenie profilu",
|
||||||
|
"Sign Out": "Odhlásiť sa",
|
||||||
|
"Sign in": "Prihlásiť sa",
|
||||||
|
"Switch Accounts": "Prepnúť Účty",
|
||||||
|
"Toggle Mobile Mode": "Prepnúť Mobilný Režim",
|
||||||
|
"Activation": "Aktivácia",
|
||||||
|
"Billing Account": "Fakturačný účet",
|
||||||
|
"Support Grist": "Podpora Grist",
|
||||||
|
"Upgrade Plan": "Plán Inovácie",
|
||||||
|
"Sign In": "Prihlásiť sa",
|
||||||
|
"Use This Template": "Použiť túto Šablónu"
|
||||||
|
},
|
||||||
|
"ViewAsDropdown": {
|
||||||
|
"View As": "Zobraziť Ako"
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,13 @@
|
|||||||
import { checkMinIOBucket, checkMinIOExternalStorage,
|
import {ICreate} from "app/server/lib/ICreate";
|
||||||
configureMinIOExternalStorage } from 'app/server/lib/configureMinIOExternalStorage';
|
import {makeCoreCreator} from "app/server/lib/coreCreator";
|
||||||
import { makeSimpleCreator } from 'app/server/lib/ICreate';
|
|
||||||
import { Telemetry } from 'app/server/lib/Telemetry';
|
|
||||||
|
|
||||||
export const create = makeSimpleCreator({
|
export const create: ICreate = makeCoreCreator();
|
||||||
deploymentType: 'core',
|
|
||||||
// This can and should be overridden by GRIST_SESSION_SECRET
|
/**
|
||||||
// (or generated randomly per install, like grist-omnibus does).
|
* Fetch the ICreate object for grist-core.
|
||||||
sessionSecret: 'Phoo2ag1jaiz6Moo2Iese2xoaphahbai3oNg7diemohlah0ohtae9iengafieS2Hae7quungoCi9iaPh',
|
* Placeholder to enable eventual refactoring away from a global singleton constant.
|
||||||
storage: [
|
* Needs to exist in all repositories before core can be switched!
|
||||||
{
|
*/
|
||||||
name: 'minio',
|
export function getCreator(): ICreate {
|
||||||
check: () => checkMinIOExternalStorage() !== undefined,
|
return create;
|
||||||
checkBackend: () => checkMinIOBucket(),
|
}
|
||||||
create: configureMinIOExternalStorage,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
telemetry: {
|
|
||||||
create: (dbManager, gristServer) => new Telemetry(dbManager, gristServer),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
import { getForwardAuthLoginSystem } from 'app/server/lib/ForwardAuthLogin';
|
import { getCoreLoginSystem } from "app/server/lib/coreLogins";
|
||||||
import { GristLoginSystem } from 'app/server/lib/GristServer';
|
import { GristLoginSystem } from "app/server/lib/GristServer";
|
||||||
import { getMinimalLoginSystem } from 'app/server/lib/MinimalLogin';
|
|
||||||
import { getOIDCLoginSystem } from 'app/server/lib/OIDCConfig';
|
|
||||||
import { getSamlLoginSystem } from 'app/server/lib/SamlConfig';
|
|
||||||
|
|
||||||
export async function getLoginSystem(): Promise<GristLoginSystem> {
|
export async function getLoginSystem(): Promise<GristLoginSystem> {
|
||||||
return await getSamlLoginSystem() ||
|
return getCoreLoginSystem();
|
||||||
await getOIDCLoginSystem() ||
|
|
||||||
await getForwardAuthLoginSystem() ||
|
|
||||||
await getMinimalLoginSystem();
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue