mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Welcome intro for viewers on a team site.
Summary: Adding intro for a viewer on a teamsite. Showing upgrade button for owners only. Test Plan: new test Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3557
This commit is contained in:
parent
b7686fa664
commit
c359547f6b
@ -150,10 +150,9 @@ export class HomeModelImpl extends Disposable implements HomeModel, ViewSettings
|
|||||||
return destWS && roles.canEdit(destWS.access) ? destWS : null;
|
return destWS && roles.canEdit(destWS.access) ? destWS : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Whether to show intro: no docs (other than examples) and user may create docs.
|
// Whether to show intro: no docs (other than examples).
|
||||||
public readonly showIntro = Computed.create(this, this.workspaces, (use, wss) => (
|
public readonly showIntro = Computed.create(this, this.workspaces, (use, wss) => (
|
||||||
wss.every((ws) => ws.isSupportWorkspace || ws.docs.length === 0) &&
|
wss.every((ws) => ws.isSupportWorkspace || ws.docs.length === 0)));
|
||||||
Boolean(use(this.newDocWorkspace))));
|
|
||||||
|
|
||||||
private _userOrgPrefs = Observable.create<UserOrgPrefs|undefined>(this, this._app.currentOrg?.userOrgPrefs);
|
private _userOrgPrefs = Observable.create<UserOrgPrefs|undefined>(this, this._app.currentOrg?.userOrgPrefs);
|
||||||
|
|
||||||
|
@ -11,30 +11,69 @@ import {cssLink} from 'app/client/ui2018/links';
|
|||||||
import {commonUrls, shouldHideUiElement} from 'app/common/gristUrls';
|
import {commonUrls, shouldHideUiElement} from 'app/common/gristUrls';
|
||||||
import {FullUser} from 'app/common/LoginSessionAPI';
|
import {FullUser} from 'app/common/LoginSessionAPI';
|
||||||
import * as roles from 'app/common/roles';
|
import * as roles from 'app/common/roles';
|
||||||
import {dom, DomContents, styled} from 'grainjs';
|
import {Computed, dom, DomContents, styled} from 'grainjs';
|
||||||
|
|
||||||
|
|
||||||
export function buildHomeIntro(homeModel: HomeModel): DomContents {
|
export function buildHomeIntro(homeModel: HomeModel): DomContents {
|
||||||
|
const isViewer = homeModel.app.currentOrg?.access === roles.VIEWER;
|
||||||
const user = homeModel.app.currentValidUser;
|
const user = homeModel.app.currentValidUser;
|
||||||
if (user) {
|
const isAnonym = !user;
|
||||||
return homeModel.app.isTeamSite ? makeTeamSiteIntro(homeModel) : makePersonalIntro(homeModel, user);
|
const isPersonal = !homeModel.app.isTeamSite;
|
||||||
} else {
|
if (isAnonym) {
|
||||||
return makeAnonIntro(homeModel);
|
return makeAnonIntro(homeModel);
|
||||||
|
} else if (isPersonal) {
|
||||||
|
return makePersonalIntro(homeModel, user);
|
||||||
|
} else { // isTeamSite
|
||||||
|
if (isViewer) {
|
||||||
|
return makeViewerTeamSiteIntro(homeModel);
|
||||||
|
} else {
|
||||||
|
return makeTeamSiteIntro(homeModel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeViewerTeamSiteIntro(homeModel: HomeModel) {
|
||||||
|
const personalOrg = Computed.create(null, use => use(homeModel.app.topAppModel.orgs).find(o => o.owner));
|
||||||
|
const docLink = (dom.maybe(personalOrg, org => {
|
||||||
|
return cssLink(
|
||||||
|
urlState().setLinkUrl({org: org.domain ?? undefined}),
|
||||||
|
'free, personal site',
|
||||||
|
testId('welcome-personal-url'));
|
||||||
|
}));
|
||||||
|
return [
|
||||||
|
css.docListHeader(
|
||||||
|
dom.autoDispose(personalOrg),
|
||||||
|
`Welcome to ${homeModel.app.currentOrgName}`,
|
||||||
|
productPill(homeModel.app.currentOrg, {large: true}),
|
||||||
|
testId('welcome-title')
|
||||||
|
),
|
||||||
|
cssIntroLine(
|
||||||
|
testId('welcome-info'),
|
||||||
|
"You have read-only access to this site. Currently there are no documents.", dom('br'),
|
||||||
|
"Any documents created in this site will appear here."),
|
||||||
|
cssIntroLine(
|
||||||
|
'Interested in using Grist outside of your team? Visit your ', docLink, '.',
|
||||||
|
testId('welcome-text')
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeTeamSiteIntro(homeModel: HomeModel) {
|
function makeTeamSiteIntro(homeModel: HomeModel) {
|
||||||
const sproutsProgram = cssLink({href: commonUrls.sproutsProgram, target: '_blank'}, 'Sprouts Program');
|
const sproutsProgram = cssLink({href: commonUrls.sproutsProgram, target: '_blank'}, 'Sprouts Program');
|
||||||
return [
|
return [
|
||||||
css.docListHeader(`Welcome to ${homeModel.app.currentOrgName}`,
|
css.docListHeader(
|
||||||
|
`Welcome to ${homeModel.app.currentOrgName}`,
|
||||||
productPill(homeModel.app.currentOrg, {large: true}),
|
productPill(homeModel.app.currentOrg, {large: true}),
|
||||||
testId('welcome-title')),
|
testId('welcome-title')
|
||||||
|
),
|
||||||
cssIntroLine('Get started by inviting your team and creating your first Grist document.'),
|
cssIntroLine('Get started by inviting your team and creating your first Grist document.'),
|
||||||
(shouldHideUiElement('helpCenter') ? null :
|
(shouldHideUiElement('helpCenter') ? null :
|
||||||
cssIntroLine('Learn more in our ', helpCenterLink(), ', or find an expert via our ', sproutsProgram, '.',
|
cssIntroLine(
|
||||||
testId('welcome-text'))
|
'Learn more in our ', helpCenterLink(), ', or find an expert via our ', sproutsProgram, '.',
|
||||||
|
testId('welcome-text')
|
||||||
|
)
|
||||||
),
|
),
|
||||||
makeCreateButtons(homeModel),
|
makeCreateButtons(homeModel)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* page, both for anonymous and logged-in users.
|
* page, both for anonymous and logged-in users.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {assert, driver, stackWrapFunc, WebElement} from 'mocha-webdriver';
|
import {assert, driver, Key, stackWrapFunc, WebElement} from 'mocha-webdriver';
|
||||||
import * as gu from 'test/nbrowser/gristUtils';
|
import * as gu from 'test/nbrowser/gristUtils';
|
||||||
import {server, setupTestSuite} from 'test/nbrowser/testUtils';
|
import {server, setupTestSuite} from 'test/nbrowser/testUtils';
|
||||||
|
|
||||||
@ -42,6 +42,42 @@ describe('HomeIntro', function() {
|
|||||||
it('should render selected Examples workspace specially', testSelectedExamplesPage);
|
it('should render selected Examples workspace specially', testSelectedExamplesPage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Viewer on a team site", function() {
|
||||||
|
it('should show welcome for viewers', async function() {
|
||||||
|
// Sign in as to a team that has no docs.
|
||||||
|
await server.simulateLogin("Chimpy", "chimpy@getgrist.com", "FreeTeam");
|
||||||
|
await driver.get(server.getUrl('freeteam', ''));
|
||||||
|
await gu.editOrgAcls();
|
||||||
|
const orgInput = await driver.find('.test-um-member-new input');
|
||||||
|
await orgInput.sendKeys('charon@getgrist.com', Key.ENTER);
|
||||||
|
await gu.saveAcls();
|
||||||
|
await gu.removeLogin();
|
||||||
|
await server.simulateLogin("Charon", "charon@getgrist.com", "abyss");
|
||||||
|
await driver.get(server.getUrl('freeteam', ''));
|
||||||
|
|
||||||
|
// Check message specific to logged-in user and an empty team site.
|
||||||
|
assert.match(await driver.findWait('.test-welcome-title', 1000).getText(), new RegExp(`Welcome.* FreeTeam`));
|
||||||
|
assert.match(await driver.find('.test-welcome-info').getText(),
|
||||||
|
/You have read-only access to this site.*/);
|
||||||
|
assert.match(await driver.find('.test-welcome-text').getText(),
|
||||||
|
/Interested in using Grist outside of your team\? Visit your free, personal site\./);
|
||||||
|
assert.notMatch(await driver.find('.test-welcome-text').getText(), /sign up/);
|
||||||
|
await driver.find(".test-welcome-personal-url").click();
|
||||||
|
await gu.waitForDocMenuToLoad();
|
||||||
|
assert.equal(
|
||||||
|
await driver.find('.test-dm-other-sites-message').getText(),
|
||||||
|
'You are on your personal site. You also have access to the following sites:'
|
||||||
|
);
|
||||||
|
await driver.get(server.getUrl('freeteam', ''));
|
||||||
|
await gu.waitForDocMenuToLoad();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show Other Sites section', testOtherSitesSection);
|
||||||
|
it('should not show welcome buttons', testNoButtonsOnHome);
|
||||||
|
it('should show examples workspace with the intro', testExamplesSection);
|
||||||
|
it('should render selected Examples workspace specially', testSelectedExamplesPage);
|
||||||
|
});
|
||||||
|
|
||||||
describe("Logged-in on merged-org", function() {
|
describe("Logged-in on merged-org", function() {
|
||||||
it('should show welcome for logged-in user', async function() {
|
it('should show welcome for logged-in user', async function() {
|
||||||
// Sign in as a new user who has no docs.
|
// Sign in as a new user who has no docs.
|
||||||
@ -117,6 +153,13 @@ describe('HomeIntro', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function testNoButtonsOnHome() {
|
||||||
|
const buttons = ['test-intro-templates', 'test-intro-import-doc', 'test-intro-create-doc'];
|
||||||
|
for (const button of buttons) {
|
||||||
|
assert.isFalse(await driver.find(`.${button}`).isPresent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function testCreateImport(isLoggedIn: boolean) {
|
async function testCreateImport(isLoggedIn: boolean) {
|
||||||
// Create doc from intro button
|
// Create doc from intro button
|
||||||
await driver.find('.test-intro-create-doc').click();
|
await driver.find('.test-intro-create-doc').click();
|
||||||
@ -160,7 +203,7 @@ describe('HomeIntro', function() {
|
|||||||
|
|
||||||
// Wait for doc to load, check it, then return to home page, and remove the doc so that we
|
// Wait for doc to load, check it, then return to home page, and remove the doc so that we
|
||||||
// can see the intro again.
|
// can see the intro again.
|
||||||
const checkDocAndRestore = stackWrapFunc(async function(isLoggedIn: boolean, docChecker: () => Promise<void>,
|
const checkDocAndRestore = async function(isLoggedIn: boolean, docChecker: () => Promise<void>,
|
||||||
stepsBackToDocMenu: number = 1) {
|
stepsBackToDocMenu: number = 1) {
|
||||||
await gu.waitForDocToLoad();
|
await gu.waitForDocToLoad();
|
||||||
await gu.dismissWelcomeTourIfNeeded();
|
await gu.dismissWelcomeTourIfNeeded();
|
||||||
@ -180,7 +223,7 @@ describe('HomeIntro', function() {
|
|||||||
await driver.wait(async () => !(await driver.find('.test-modal-dialog').isPresent()), 3000);
|
await driver.wait(async () => !(await driver.find('.test-modal-dialog').isPresent()), 3000);
|
||||||
}
|
}
|
||||||
assert.equal(await driver.find('.test-dm-doc').isPresent(), false);
|
assert.equal(await driver.find('.test-dm-doc').isPresent(), false);
|
||||||
});
|
};
|
||||||
|
|
||||||
async function testExamplesCollapsing() {
|
async function testExamplesCollapsing() {
|
||||||
assert.equal(await driver.find('.test-dm-pinned-doc-name').isDisplayed(), true);
|
assert.equal(await driver.find('.test-dm-pinned-doc-name').isDisplayed(), true);
|
||||||
|
Loading…
Reference in New Issue
Block a user