mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
first functionnal POC
Co-authored-by: hexaltation <gregoire@cutzach.com> Co-authored-by: fflorent <florent.git@zeteo.me>
This commit is contained in:
parent
e9b5b98bcb
commit
f40bd9d075
@ -29,6 +29,7 @@ import {Holder, Observable, subscribe} from 'grainjs';
|
|||||||
import {Computed, Disposable, dom, DomArg, DomElementArg} from 'grainjs';
|
import {Computed, Disposable, dom, DomArg, DomElementArg} from 'grainjs';
|
||||||
import {makeT} from 'app/client/lib/localization';
|
import {makeT} from 'app/client/lib/localization';
|
||||||
import {logTelemetryEvent} from 'app/client/lib/telemetry';
|
import {logTelemetryEvent} from 'app/client/lib/telemetry';
|
||||||
|
import {DocumentType} from 'app/common/UserAPI';
|
||||||
|
|
||||||
// tslint:disable:no-console
|
// tslint:disable:no-console
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ export interface DocPageModel {
|
|||||||
isTutorialTrunk: Observable<boolean>;
|
isTutorialTrunk: Observable<boolean>;
|
||||||
isTutorialFork: Observable<boolean>;
|
isTutorialFork: Observable<boolean>;
|
||||||
isTemplate: Observable<boolean>;
|
isTemplate: Observable<boolean>;
|
||||||
|
type: Observable<DocumentType|null>;
|
||||||
importSources: ImportSource[];
|
importSources: ImportSource[];
|
||||||
|
|
||||||
undoState: Observable<IUndoState|null>; // See UndoStack for details.
|
undoState: Observable<IUndoState|null>; // See UndoStack for details.
|
||||||
@ -147,6 +148,8 @@ export class DocPageModelImpl extends Disposable implements DocPageModel {
|
|||||||
(use, doc) => doc ? doc.isTutorialFork : false);
|
(use, doc) => doc ? doc.isTutorialFork : false);
|
||||||
public readonly isTemplate = Computed.create(this, this.currentDoc,
|
public readonly isTemplate = Computed.create(this, this.currentDoc,
|
||||||
(use, doc) => doc ? doc.isTemplate : false);
|
(use, doc) => doc ? doc.isTemplate : false);
|
||||||
|
public readonly type = Computed.create(this, this.currentDoc,
|
||||||
|
(use, doc) => doc?.type?? null);
|
||||||
|
|
||||||
public readonly importSources: ImportSource[] = [];
|
public readonly importSources: ImportSource[] = [];
|
||||||
|
|
||||||
@ -499,7 +502,8 @@ function buildDocInfo(doc: Document, mode: OpenDocMode | undefined): DocInfo {
|
|||||||
const isFork = Boolean(idParts.forkId || idParts.snapshotId);
|
const isFork = Boolean(idParts.forkId || idParts.snapshotId);
|
||||||
const isBareFork = isFork && idParts.trunkId === NEW_DOCUMENT_CODE;
|
const isBareFork = isFork && idParts.trunkId === NEW_DOCUMENT_CODE;
|
||||||
const isSnapshot = Boolean(idParts.snapshotId);
|
const isSnapshot = Boolean(idParts.snapshotId);
|
||||||
const isTutorial = doc.type === 'tutorial';
|
const type = doc.type;
|
||||||
|
const isTutorial = type === 'tutorial';
|
||||||
const isTutorialTrunk = isTutorial && !isFork && mode !== 'default';
|
const isTutorialTrunk = isTutorial && !isFork && mode !== 'default';
|
||||||
const isTutorialFork = isTutorial && isFork;
|
const isTutorialFork = isTutorial && isFork;
|
||||||
|
|
||||||
@ -511,7 +515,7 @@ function buildDocInfo(doc: Document, mode: OpenDocMode | undefined): DocInfo {
|
|||||||
// mode. Since the document's 'openMode' has no effect, don't bother trying
|
// mode. Since the document's 'openMode' has no effect, don't bother trying
|
||||||
// to set it here, as it'll potentially be confusing for other code reading it.
|
// to set it here, as it'll potentially be confusing for other code reading it.
|
||||||
openMode = 'default';
|
openMode = 'default';
|
||||||
} else if (!isFork && doc.type === 'template') {
|
} else if (!isFork && type === 'template') {
|
||||||
// Templates should always open in fork mode by default.
|
// Templates should always open in fork mode by default.
|
||||||
openMode = 'fork';
|
openMode = 'fork';
|
||||||
} else {
|
} else {
|
||||||
@ -521,7 +525,7 @@ function buildDocInfo(doc: Document, mode: OpenDocMode | undefined): DocInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isPreFork = openMode === 'fork';
|
const isPreFork = openMode === 'fork';
|
||||||
const isTemplate = doc.type === 'template' && (isFork || isPreFork);
|
const isTemplate = type === 'template' && (isFork || isPreFork);
|
||||||
const isEditable = !isSnapshot && (canEdit(doc.access) || isPreFork);
|
const isEditable = !isSnapshot && (canEdit(doc.access) || isPreFork);
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
@ -534,6 +538,7 @@ function buildDocInfo(doc: Document, mode: OpenDocMode | undefined): DocInfo {
|
|||||||
isSnapshot,
|
isSnapshot,
|
||||||
isTutorialTrunk,
|
isTutorialTrunk,
|
||||||
isTutorialFork,
|
isTutorialFork,
|
||||||
|
type,
|
||||||
isTemplate,
|
isTemplate,
|
||||||
isReadonly: !isEditable,
|
isReadonly: !isEditable,
|
||||||
idParts,
|
idParts,
|
||||||
|
@ -31,6 +31,7 @@ import {getCurrency, locales} from 'app/common/Locales';
|
|||||||
import {isOwner, isOwnerOrEditor} from 'app/common/roles';
|
import {isOwner, isOwnerOrEditor} from 'app/common/roles';
|
||||||
import {Computed, Disposable, dom, fromKo, IDisposableOwner, makeTestId, Observable, styled} from 'grainjs';
|
import {Computed, Disposable, dom, fromKo, IDisposableOwner, makeTestId, Observable, styled} from 'grainjs';
|
||||||
import * as moment from 'moment-timezone';
|
import * as moment from 'moment-timezone';
|
||||||
|
import {DocumentType} from 'app/common/UserAPI';
|
||||||
|
|
||||||
const t = makeT('DocumentSettings');
|
const t = makeT('DocumentSettings');
|
||||||
const testId = makeTestId('test-settings-');
|
const testId = makeTestId('test-settings-');
|
||||||
@ -41,6 +42,7 @@ export class DocSettingsPage extends Disposable {
|
|||||||
private _timezone = this._docInfo.timezone;
|
private _timezone = this._docInfo.timezone;
|
||||||
private _locale: KoSaveableObservable<string> = this._docInfo.documentSettingsJson.prop('locale');
|
private _locale: KoSaveableObservable<string> = this._docInfo.documentSettingsJson.prop('locale');
|
||||||
private _currency: KoSaveableObservable<string|undefined> = this._docInfo.documentSettingsJson.prop('currency');
|
private _currency: KoSaveableObservable<string|undefined> = this._docInfo.documentSettingsJson.prop('currency');
|
||||||
|
// private _type: KoSaveableObservable<string|undefined> = this._docInfo.documentSettingsJson.prop('type');
|
||||||
private _engine: Computed<EngineCode|undefined> = Computed.create(this, (
|
private _engine: Computed<EngineCode|undefined> = Computed.create(this, (
|
||||||
use => use(this._docInfo.documentSettingsJson.prop('engine'))
|
use => use(this._docInfo.documentSettingsJson.prop('engine'))
|
||||||
))
|
))
|
||||||
@ -194,6 +196,14 @@ export class DocSettingsPage extends Disposable {
|
|||||||
value: cssSmallLinkButton(t('Manage webhooks'), urlState().setLinkUrl({docPage: 'webhook'})),
|
value: cssSmallLinkButton(t('Manage webhooks'), urlState().setLinkUrl({docPage: 'webhook'})),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
dom.create(AdminSection, t('Document conversion'), [
|
||||||
|
dom.create(AdminSectionItem, {
|
||||||
|
id: 'document-type',
|
||||||
|
name: t('Document type'),
|
||||||
|
description: t('Convert the document'),
|
||||||
|
value: dom.create(buildTypeSelect, docPageModel.type, docPageModel.currentDocId.get()),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +308,15 @@ export class DocSettingsPage extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function persistType(type: string|null, docId: string|undefined){
|
||||||
|
docId = docId?.split("~")[0];
|
||||||
|
return fetch(`/o/docs/api/docs/${docId}`,
|
||||||
|
{ method:'PATCH',
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
credentials: 'include',
|
||||||
|
body:JSON.stringify({type})
|
||||||
|
}).catch((err)=>{ console.log(err); });
|
||||||
|
}
|
||||||
|
|
||||||
function getApiConsoleLink(docPageModel: DocPageModel) {
|
function getApiConsoleLink(docPageModel: DocPageModel) {
|
||||||
const url = new URL(location.href);
|
const url = new URL(location.href);
|
||||||
@ -343,6 +361,45 @@ function buildLocaleSelect(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DocumentTypeItem = ACSelectItem & {type?: string};
|
||||||
|
|
||||||
|
function buildTypeSelect(
|
||||||
|
owner: IDisposableOwner,
|
||||||
|
type: Observable<DocumentType|null>,
|
||||||
|
id: string|undefined,
|
||||||
|
) {
|
||||||
|
const typeList: DocumentTypeItem[] = [{
|
||||||
|
label: t('Regular'),
|
||||||
|
type: ''
|
||||||
|
}, {
|
||||||
|
label: t('Template'),
|
||||||
|
type: 'template'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Tutorial'),
|
||||||
|
type: 'tutorial'
|
||||||
|
}].map((el) => ({
|
||||||
|
...el,
|
||||||
|
value: el.label,
|
||||||
|
cleanText: el.label.trim().toLowerCase()
|
||||||
|
}));
|
||||||
|
const typeObs = Computed.create(owner, use => {
|
||||||
|
const typeCode = use(type)??"";
|
||||||
|
const typeName = typeList.find(ty => ty.type === typeCode)?.label || typeCode;
|
||||||
|
return typeName;
|
||||||
|
});
|
||||||
|
const acIndex = new ACIndexImpl<DocumentTypeItem>(typeList, {maxResults: 200, keepOrder: true});
|
||||||
|
return buildACSelect(owner, {
|
||||||
|
acIndex, valueObs: typeObs,
|
||||||
|
save(_value, item: DocumentTypeItem | undefined) {
|
||||||
|
if (!item) { throw new Error("Invalid DocumentType"); }
|
||||||
|
persistType(item.type!, id)
|
||||||
|
.then(()=>window.location.reload())
|
||||||
|
.catch(err=>console.log(err));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const cssContainer = styled('div', `
|
const cssContainer = styled('div', `
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
Loading…
Reference in New Issue
Block a user