(core) Polishing upgrade plan UI

Summary:
- Update nudge boxes content and collapsing on personal and free team site
- New confirmation after upgrading from a free team site
- Refactoring ProductUpgrade code, splitting plans / modals and nudges

Test Plan: Manual and updated tests

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3481
pull/214/head
Jarosław Sadziński 2 years ago
parent dd2eadc86e
commit aefe451bab

@ -1,3 +1,4 @@
import {safeJsonParse} from 'app/common/gutil';
import {Observable} from 'grainjs';
/**
@ -96,3 +97,14 @@ export function localStorageObs(key: string, defaultValue?: string): Observable<
obs.addListener((val) => (val === null) ? store.removeItem(key) : store.setItem(key, val));
return obs;
}
/**
* Helper to create a JSON observable whose state is stored in localStorage.
*/
export function localStorageJsonObs<T>(key: string, defaultValue: T): Observable<T> {
const store = getStorage();
const currentValue = safeJsonParse(store.getItem(key) || '', defaultValue ?? null);
const obs = Observable.create<T>(null, currentValue);
obs.addListener((val) => (val === null) ? store.removeItem(key) : store.setItem(key, JSON.stringify(val ?? null)));
return obs;
}

@ -50,6 +50,10 @@ export interface TopAppModel {
* Returns the UntrustedContentOrigin use settings. Throws if not defined.
*/
getUntrustedContentOrigin(): string;
/**
* Reloads orgs and accounts for current user.
*/
fetchUsersAndOrgs(): Promise<void>;
}
// AppModel is specific to the currently loaded organization and active user. It gets rebuilt when
@ -110,7 +114,7 @@ export class TopAppModelImpl extends Disposable implements TopAppModel {
this.autoDispose(subscribe(this.currentSubdomain, (use) => this.initialize()));
this.plugins = this._gristConfig?.plugins || [];
this._fetchUsersAndOrgs().catch(reportError);
this.fetchUsersAndOrgs().catch(reportError);
}
public initialize(): void {
@ -143,6 +147,15 @@ export class TopAppModelImpl extends Disposable implements TopAppModel {
return origin + ":" + G.window.location.port;
}
public async fetchUsersAndOrgs() {
const data = await this.api.getSessionAll();
if (this.isDisposed()) { return; }
bundleChanges(() => {
this.users.set(data.users);
this.orgs.set(data.orgs);
});
}
private async _doInitialize() {
this.appObs.set(null);
try {
@ -172,15 +185,6 @@ export class TopAppModelImpl extends Disposable implements TopAppModel {
AppModelImpl.create(this.appObs, this, null, null, {error: err.message, status: err.status || 500});
}
}
private async _fetchUsersAndOrgs() {
const data = await this.api.getSessionAll();
if (this.isDisposed()) { return; }
bundleChanges(() => {
this.users.set(data.users);
this.orgs.set(data.orgs);
});
}
}
export class AppModelImpl extends Disposable implements AppModel {
@ -225,13 +229,22 @@ export class AppModelImpl extends Disposable implements AppModel {
public async showUpgradeModal() {
if (this.planName && this.currentOrg) {
buildUpgradeModal(this, this.planName);
if (this.isPersonal) {
this.showNewSiteModal();
} else if (this.isTeamSite) {
buildUpgradeModal(this, this.planName);
} else {
throw new Error("Unexpected state");
}
}
}
public async showNewSiteModal() {
public showNewSiteModal() {
if (this.planName) {
buildNewSiteModal(this, this.planName);
buildNewSiteModal(this, {
planName: this.planName,
onCreate: () => this.topAppModel.fetchUsersAndOrgs().catch(reportError)
});
}
}

@ -51,10 +51,10 @@ function makePrefFunctions<P extends keyof PrefsTypes>(prefsTypeName: P) {
}
// Functions actually exported are:
// - getUserOrgPrefsObs(appModel): Observsble<UserOrgPrefs>
// - getUserOrgPrefObs(userOrgPrefsObs, prefName): Observsble<PrefType[prefName]>
// - getUserPrefsObs(appModel): Observsble<UserPrefs>
// - getUserPrefObs(userPrefsObs, prefName): Observsble<PrefType[prefName]>
// - getUserOrgPrefsObs(appModel): Observable<UserOrgPrefs>
// - getUserOrgPrefObs(userOrgPrefsObs, prefName): Observable<PrefType[prefName]>
// - getUserPrefsObs(appModel): Observable<UserPrefs>
// - getUserPrefObs(userPrefsObs, prefName): Observable<PrefType[prefName]>
export const {getPrefsObs: getUserOrgPrefsObs, getPrefObs: getUserOrgPrefObs} = makePrefFunctions('userOrgPrefs');
export const {getPrefsObs: getUserPrefsObs, getPrefObs: getUserPrefObs} = makePrefFunctions('userPrefs');

@ -14,11 +14,12 @@ import { createTopBarHome } from 'app/client/ui/TopBar';
import { cssBreadcrumbs, cssBreadcrumbsLink, separator } from 'app/client/ui2018/breadcrumbs';
import { bigBasicButton, bigBasicButtonLink, bigPrimaryButton } from 'app/client/ui2018/buttons';
import { loadingSpinner } from 'app/client/ui2018/loaders';
import { NEW_DEAL, showTeamUpgradeConfirmation } from 'app/client/ui/ProductUpgrades';
import { IconName } from 'app/client/ui2018/IconList';
import { BillingTask, IBillingCoupon } from 'app/common/BillingAPI';
import { capitalize } from 'app/common/gutil';
import { Organization } from 'app/common/UserAPI';
import { Disposable, dom, DomArg, IAttrObj, makeTestId, Observable } from 'grainjs';
import { IconName } from '../ui2018/IconList';
const testId = makeTestId('test-bp-');
const billingTasksNames = {
@ -26,6 +27,7 @@ const billingTasksNames = {
signUpLite: 'Complete Sign Up', // task for payment page
updateDomain: 'Update Name', // task for summary page
cancelPlan: 'Cancel plan', // this is not a task, but a sub page
upgraded: 'Account',
};
/**
@ -41,6 +43,8 @@ export class BillingPage extends Disposable {
constructor(private _appModel: AppModel) {
super();
// TODO: remove once NEW_DEAL is there. Execute for side effect
void NEW_DEAL();
this._appModel.refreshOrgUsage().catch(reportError);
}
@ -77,7 +81,7 @@ export class BillingPage extends Disposable {
* Builds the contentMain dom for the current billing page.
*/
private _buildCurrentPageDom() {
return css.billingWrapper(
const page = css.billingWrapper(
dom.domComputed(this._model.currentSubpage, (subpage) => {
if (!subpage) {
return this._buildSummaryPage();
@ -86,6 +90,11 @@ export class BillingPage extends Disposable {
}
})
);
if (this._model.currentTask.get() === 'upgraded') {
urlState().pushUrl({params: {}}, { replace: true }).catch(() => {});
showTeamUpgradeConfirmation(this);
}
return page;
}
private _buildSummaryPage() {

@ -10,12 +10,12 @@ import {getTimeFromNow, HomeModel, makeLocalViewSettings, ViewSettings} from 'ap
import {getWorkspaceInfo, workspaceName} from 'app/client/models/WorkspaceInfo';
import * as css from 'app/client/ui/DocMenuCss';
import {buildHomeIntro} from 'app/client/ui/HomeIntro';
import {createVideoTourTextButton} from 'app/client/ui/OpenVideoTour';
import {buildUpgradeNudge} from 'app/client/ui/ProductUpgrades';
import {buildUpgradeButton} from 'app/client/ui/ProductUpgrades';
import {buildPinnedDoc, createPinnedDocs} from 'app/client/ui/PinnedDocs';
import {shadowScroll} from 'app/client/ui/shadowScroll';
import {transition} from 'app/client/ui/transitions';
import {showWelcomeQuestions} from 'app/client/ui/WelcomeQuestions';
import {createVideoTourTextButton} from 'app/client/ui/OpenVideoTour';
import {buttonSelect, cssButtonSelect} from 'app/client/ui2018/buttonSelect';
import {colors, isNarrowScreenObs} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
@ -26,12 +26,12 @@ import {IHomePage} from 'app/common/gristUrls';
import {SortPref, ViewPref} from 'app/common/Prefs';
import * as roles from 'app/common/roles';
import {Document, Workspace} from 'app/common/UserAPI';
import {Computed, computed, dom, DomContents, makeTestId, Observable, observable} from 'grainjs';
import sortBy = require('lodash/sortBy');
import {computed, Computed, dom, DomArg, DomContents, IDisposableOwner,
makeTestId, observable, Observable} from 'grainjs';
import {buildTemplateDocs} from 'app/client/ui/TemplateDocs';
import {localStorageBoolObs} from 'app/client/lib/localStorageObs';
import {bigBasicButton} from 'app/client/ui2018/buttons';
import {getUserOrgPrefObs, getUserOrgPrefsObs} from 'app/client/models/UserPrefs';
import sortBy = require('lodash/sortBy');
const testId = makeTestId('test-dm-');
@ -45,27 +45,14 @@ export function createDocMenu(home: HomeModel) {
return dom.domComputed(home.loading, loading => (
loading === 'slow' ? css.spinner(loadingSpinner()) :
loading ? null :
createLoadedDocMenu(home)
dom.create(createLoadedDocMenu, home)
));
}
function createUpgradeNudge(home: HomeModel) {
const isLoggedIn = !!home.app.currentValidUser;
const isOnFreePersonal = home.app.currentOrg?.billingAccount?.product?.name === 'starter';
const userOrgPrefs = getUserOrgPrefsObs(home.app);
const seenNudge = getUserOrgPrefObs(userOrgPrefs, 'seenFreeTeamUpgradeNudge');
return dom.maybe(use => isLoggedIn && isOnFreePersonal && !use(seenNudge),
() => buildUpgradeNudge({
onClose: () => seenNudge.set(true),
// On show prices, we will clear the nudge in database once there is some free team site created
// The better way is to read all workspaces that this person have and decide then - but this is done
// asynchronously - so we potentially can show this nudge to people that already have team site.
onUpgrade: () => home.app.showUpgradeModal()
}));
}
function createLoadedDocMenu(home: HomeModel) {
function createLoadedDocMenu(owner: IDisposableOwner, home: HomeModel) {
const flashDocId = observable<string|null>(null);
const upgradeButton = buildUpgradeButton(owner, home.app);
return css.docList(
showWelcomeQuestions(home.app.userPrefsObs),
css.docMenu(
@ -83,14 +70,16 @@ function createLoadedDocMenu(home: HomeModel) {
page === 'templates' ? makeLocalViewSettings(home, 'templates') :
workspace ? makeLocalViewSettings(home, workspace.id) :
home;
return [
// Hide the sort option only when showing intro.
((showIntro && page === 'all') ? null :
buildPrefs(viewSettings, {hideSort: showIntro})
((showIntro && page === 'all') ? css.prefSelectors(upgradeButton.showUpgradeButton()) :
// This is float:right element
buildPrefs(viewSettings, {hideSort: showIntro}, upgradeButton.showUpgradeButton())
),
// Build the pinned docs dom. Builds nothing if the selectedOrg is unloaded or
// Build the pinned docs dom. Builds nothing if the selectedOrg is unloaded.
// TODO: this is shown on all pages, but there is a hack in currentWSPinnedDocs that
// removes all pinned docs when on trash page.
dom.maybe((use) => use(home.currentWSPinnedDocs).length > 0, () => [
css.docListHeader(css.docHeaderIconDark('PinBig'), 'Pinned Documents'),
createPinnedDocs(home, home.currentWSPinnedDocs),
@ -128,7 +117,8 @@ function createLoadedDocMenu(home: HomeModel) {
dom('div',
showIntro ? buildHomeIntro(home) : null,
buildAllDocsBlock(home, home.workspaces, showIntro, flashDocId, viewSettings),
dom.maybe(use => use(isNarrowScreenObs()), () => createUpgradeNudge(home)),
dom.maybe(use => use(isNarrowScreenObs()),
() => upgradeButton.showUpgradeCard()),
shouldShowTemplates(home, showIntro) ? buildAllDocsTemplates(home, viewSettings) : null,
) :
(page === 'trash') ?
@ -155,7 +145,8 @@ function createLoadedDocMenu(home: HomeModel) {
}),
testId('doclist')
),
dom.maybe(use => !use(isNarrowScreenObs()) && use(home.currentPage) === 'all', () => createUpgradeNudge(home)),
dom.maybe(use => !use(isNarrowScreenObs()) && ['all', 'workspace'].includes(use(home.currentPage)),
() => upgradeButton.showUpgradeCard()),
);
}
@ -309,7 +300,10 @@ function buildOtherSites(home: HomeModel) {
* If hideSort is true, will hide the sort dropdown: it has no effect on the list of examples, so
* best to hide when those are the only docs shown.
*/
function buildPrefs(viewSettings: ViewSettings, options: {hideSort: boolean}): DomContents {
function buildPrefs(
viewSettings: ViewSettings,
options: {hideSort: boolean},
...args: DomArg<HTMLElement>[]): DomContents {
return css.prefSelectors(
// The Sort selector.
options.hideSort ? null : dom.update(
@ -330,6 +324,7 @@ function buildPrefs(viewSettings: ViewSettings, options: {hideSort: boolean}): D
cssButtonSelect.cls("-light"),
testId('view-mode')
),
...args
);
}

@ -1,15 +1,11 @@
import type {AppModel} from 'app/client/models/AppModel';
import {commonUrls} from 'app/common/gristUrls';
import {Disposable} from 'grainjs';
import {Disposable, DomContents, IDisposableOwner, Observable, observable} from 'grainjs';
export function buildUpgradeNudge(options: {
onClose: () => void;
onUpgrade: () => void
export function buildNewSiteModal(context: Disposable, options: {
planName: string,
onCreate?: () => void
}) {
return null;
}
export function buildNewSiteModal(owner: Disposable, current: string | null) {
window.location.href = commonUrls.plans;
}
@ -17,11 +13,21 @@ export function buildUpgradeModal(owner: Disposable, planName: string) {
window.location.href = commonUrls.plans;
}
export class UpgradeButton extends Disposable {
constructor(appModel: AppModel) {
super();
}
public buildDom() {
return null;
}
export function showTeamUpgradeConfirmation(owner: Disposable) {
}
export interface UpgradeButton {
showUpgradeCard(): DomContents;
showUpgradeButton(): DomContents;
}
export function buildUpgradeButton(owner: IDisposableOwner, app: AppModel): UpgradeButton {
return {
showUpgradeCard : () => null,
showUpgradeButton : () => null,
};
}
export function NEW_DEAL(): Observable<boolean> {
return observable(false);
}

@ -58,6 +58,7 @@ export type IconName = "ChartArea" |
"Feedback" |
"Filter" |
"FilterSimple" |
"Fireworks" |
"Folder" |
"FontBold" |
"FontItalic" |
@ -89,6 +90,7 @@ export type IconName = "ChartArea" |
"Pivot" |
"Plus" |
"Public" |
"PublicColor" |
"PublicFilled" |
"Redo" |
"Remove" |
@ -181,6 +183,7 @@ export const IconList: IconName[] = ["ChartArea",
"Feedback",
"Filter",
"FilterSimple",
"Fireworks",
"Folder",
"FontBold",
"FontItalic",
@ -212,6 +215,7 @@ export const IconList: IconName[] = ["ChartArea",
"Pivot",
"Plus",
"Public",
"PublicColor",
"PublicFilled",
"Redo",
"Remove",

@ -15,7 +15,7 @@ export type BillingPage = typeof BillingPage.type;
// signUpLite - it is a subpage for payment, to finalize (complete) signup process
// and set domain and team name when they are not set yet (currently only from landing pages).
// signUp - it is landing page for new team sites (it doesn't ask for the name of the team)
export const BillingTask = StringUnion('signUpLite', 'updateDomain', 'signUp', 'cancelPlan');
export const BillingTask = StringUnion('signUpLite', 'updateDomain', 'signUp', 'cancelPlan', 'upgraded');
export type BillingTask = typeof BillingTask.type;
// Note that IBillingPlan includes selected fields from the Stripe plan object along with

@ -68,7 +68,12 @@ export function canAddOrgMembers(features: Features): boolean {
return features.maxWorkspacesPerOrg !== 1;
}
export const FREE_PERSONAL_PLAN = 'starter';
export const TEAM_FREE_PLAN = 'teamFree';
export const TEAM_PLAN = 'team';
// Returns true if `product` is free.
export function isFreeProduct(product: Product): boolean {
return ['starter', 'teamFree', 'Free'].includes(product?.name);
return [FREE_PERSONAL_PLAN, TEAM_FREE_PLAN, 'Free'].includes(product?.name);
}

@ -38,9 +38,6 @@ export interface UserOrgPrefs extends Prefs {
// List of document IDs where the user has seen and dismissed the document tour.
seenDocTours?: string[];
// Whether the user seen the nudge to upgrade to Free Team Site and dismissed it.
seenFreeTeamUpgradeNudge?: boolean;
}
export type OrgPrefs = Prefs;

@ -1,4 +1,4 @@
import {Features, Product as IProduct} from 'app/common/Features';
import {Features, FREE_PERSONAL_PLAN, Product as IProduct, TEAM_FREE_PLAN, TEAM_PLAN} from 'app/common/Features';
import {nativeValues} from 'app/gen-server/lib/values';
import * as assert from 'assert';
import {BillingAccount} from 'app/gen-server/entity/BillingAccount';
@ -100,7 +100,7 @@ export const PRODUCTS: IProduct[] = [
// These are products set up in stripe.
// TODO: this is not true anymore
{
name: 'starter',
name: FREE_PERSONAL_PLAN,
features: starterFeatures,
},
{
@ -108,7 +108,7 @@ export const PRODUCTS: IProduct[] = [
features: teamFeatures,
},
{
name: 'team',
name: TEAM_PLAN,
features: teamFeatures
},
@ -119,7 +119,7 @@ export const PRODUCTS: IProduct[] = [
features: suspendedFeatures
},
{
name: 'teamFree',
name: TEAM_FREE_PLAN,
features: teamFreeFeatures
},
];
@ -131,11 +131,11 @@ export const PRODUCTS: IProduct[] = [
export function getDefaultProductNames() {
const defaultProduct = process.env.GRIST_DEFAULT_PRODUCT;
return {
personal: defaultProduct || 'starter', // Personal site start off on a functional plan.
personal: defaultProduct || FREE_PERSONAL_PLAN, // Personal site start off on a functional plan.
teamInitial: defaultProduct || 'stub', // Team site starts off on a limited plan, requiring subscription.
teamCancel: 'suspended', // Team site that has been 'turned off'.
team: defaultProduct || 'team', // Functional team site.
teamFree: defaultProduct || 'teamFree',
team: defaultProduct || TEAM_PLAN, // Functional team site.
teamFree: defaultProduct || TEAM_FREE_PLAN,
};
}

@ -59,6 +59,7 @@
--icon-Feedback: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTcuMjE4MjEzMyw5IEM3LjIyNTE1MTk3LDguOTk5ODU1MTUgNy4yMzIwODMyMSw4Ljk5OTg1NTY0IDcuMjM5MDAyNiw5IEw4LjUyNCw5IEw4LjcxMDQ2NjY3LDkuMDM2MDcwOTMgTDEzLDEwLjc2MDE1OTkgTDEzLDMuMjM5ODQwMTEgTDguNzEwNDY2NjcsNC45NjM5MjkwNyBMOC41MjQsNSBMNSw1IEMzLjg5NTQzMDUsNSAzLDUuODk1NDMwNSAzLDcgQzMsNy41MzA0MzI5OCAzLjIxMDcxMzY4LDguMDM5MTQwODEgMy41ODU3ODY0NCw4LjQxNDIxMzU2IEMzLjk2MDg1OTE5LDguNzg5Mjg2MzIgNC40Njk1NjcwMiw5IDUsOSBMNy4yMTgyMTMwNiw5IFogTTguMDQwNTAzNzksMTAgTDguODQ1MDUxNTMsMTEuNTk4MTIwMyBDOS4wNDQ1NTkzMywxMS45ODc3NjEzIDkuMDgxMDU2NTQsMTIuNDQwNzEyNSA4Ljk0NjUwOTQsMTIuODU3MjcwNSBDOC44MTE5NjIyNywxMy4yNzM4Mjg0IDguNTE3Mzk5NSwxMy42MTk4NDgxIDguMTI3NDkyODksMTMuODE5MjQ5NCBDNy4zMTYyMzEwMywxNC4yMzM3NTA0IDYuMzIyNTQ0NjIsMTMuOTEyNzkyMiA1LjkwNzc3MTk4LDEzLjEwMzQ4MDkgTDQuMjU2MTc5MDUsOS45MDYzMzQ3NyBDMy43MzkyNzk1OSw5Ljc3NDAyODg2IDMuMjYyMzY1MzEsOS41MDUwMDYgMi44Nzg2Nzk2Niw5LjEyMTMyMDM0IEMyLjMxNjA3MDUyLDguNTU4NzExMjEgMiw3Ljc5NTY0OTQ3IDIsNyBDMiw1LjM0MzE0NTc1IDMuMzQzMTQ1NzUsNCA1LDQgTDguNDI3Mjc3ODEsNCBMMTMuMzEzNTMzMywyLjAzNjA3MDkzIEMxMy42NDIwNzYyLDEuOTA0MDE5OTQgMTQsMi4xNDU5MTI2MiAxNCwyLjUgTDE0LDExLjUgQzE0LDExLjg1NDA4NzQgMTMuNjQyMDc2MiwxMi4wOTU5ODAxIDEzLjMxMzUzMzMsMTEuOTYzOTI5MSBMOC40MjcyNzc4MSwxMCBMOC4wNDA1MDM3OSwxMCBaIE01LjQzMDExMjQsMTAgTDYuNzk2OTY1ODQsMTIuNjQ1OTUzMSBDNi45NjA4MDQzMSwxMi45NjU2MzUyIDcuMzUyNjIxMzEsMTMuMDkyMTkxMSA3LjY3MjMzOTc4LDEyLjkyODgzNjIgQzcuODI1ODczNDMsMTIuODUwMzE3OSA3Ljk0MTkxMzMxLDEyLjcxNDAwNzEgNy45OTQ5MTY3MywxMi41NDk5MDg1IEM4LjA0NzkyMDE1LDEyLjM4NTgwOTkgOC4wMzM1NDI0NiwxMi4yMDczNzQ2IDcuOTUzNDAyNSwxMi4wNTA4MzQ4IEw2LjkyMDkzMTUxLDEwIEw1LjQzMDExMjQsMTAgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
--icon-Filter: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTIuNSw0IEwxLjUsNCBDMS4yMjQsNCAxLDMuNzc2IDEsMy41IEMxLDMuMjI0IDEuMjI0LDMgMS41LDMgTDIuNSwzIEMyLjc3NiwzIDMsMy4yMjQgMywzLjUgQzMsMy43NzYgMi43NzYsNCAyLjUsNCBaIE00LjUsNyBMMS41LDcgQzEuMjI0LDcgMSw2Ljc3NiAxLDYuNSBDMSw2LjIyNCAxLjIyNCw2IDEuNSw2IEw0LjUsNiBDNC43NzYsNiA1LDYuMjI0IDUsNi41IEM1LDYuNzc2IDQuNzc2LDcgNC41LDcgWiBNNi41LDEwIEwxLjUsMTAgQzEuMjI0LDEwIDEsOS43NzYgMSw5LjUgQzEsOS4yMjQgMS4yMjQsOSAxLjUsOSBMNi41LDkgQzYuNzc2LDkgNyw5LjIyNCA3LDkuNSBDNyw5Ljc3NiA2Ljc3NiwxMCA2LjUsMTAgWiBNOC41LDEzIEwxLjUsMTMgQzEuMjI0LDEzIDEsMTIuNzc2IDEsMTIuNSBDMSwxMi4yMjQgMS4yMjQsMTIgMS41LDEyIEw4LjUsMTIgQzguNzc2LDEyIDksMTIuMjI0IDksMTIuNSBDOSwxMi43NzYgOC43NzYsMTMgOC41LDEzIFogTTE0Ljk3Mjg4OCwyLjI4NDkwODg1IEMxNS4wMjY1MzgyLDIuNDU3MzYxNzggMTQuOTk2ODg2NCwyLjY1NTk2NzI1IDE0Ljg5Nzg5MzIsMi43ODc4MDY4MyBMMTEuNjgxMzA2OCw3LjA3NjY2OTY1IEMxMS42MTE3MzQ3LDcuMTY5NTg4MDkgMTEuNTM4MDA5LDcuNDA2ODA3MDIgMTEuNTM4MDA5LDcuNTM4MTg1MDggTDExLjUzODAwOSwxMy41Mzc4ODU2IEMxMS41MzgwMDksMTMuNzI0NjQ1NSAxMS40NTM3ODQsMTMuODkyOTQ0OCAxMS4zMjQzMzE0LDEzLjk2NDE3MiBDMTEuMjgxNTI2NiwxMy45ODgwMTcgMTEuMjM2NTI5NywxMy45OTk0MDEgMTEuMTkxOTk0MywxMy45OTk0MDEgQzExLjEwMTg4NTEsMTMuOTk5NDAxIDExLjAxMzI3NTgsMTMuOTUyNDgwMyAxMC45NDcxNjUsMTMuODY0MTc3IEw5LjU2MjY0NDg2LDEyLjAxODExNTMgQzkuNDk3Njg3NzksMTEuOTMxNjU4MSA5LjQ2MTIyODc2LDExLjgxNDI3OTMgOS40NjEyMjg3NiwxMS42OTE4MjM5IEw5LjQ2MTIyODc2LDcuNTM4MTg1MDggQzkuNDYxMjI4NzYsNy40MDY4MDcwMiA5LjM4NzYxODQ0LDcuMTY5NTg4MDkgOS4zMTc5MzA5Miw3LjA3Njk3NzMzIEw2LjEwMTM0NDUyLDIuNzg3OTYwNjcgQzYuMDAyMzUxMzMsMi42NTU5NjcyNSA1Ljk3MjgxNDksMi40NTc1MTU2MiA2LjAyNjM0OTY4LDIuMjg0OTA4ODUgQzYuMDc5ODg0NDUsMi4xMTIzMDIwOSA2LjIwNjEwNjU0LDIgNi4zNDYwNTg0NSwyIEwxNC42NTMxNzkzLDIgQzE0Ljc5MzI0NjYsMiAxNC45MTk0Njg2LDIuMTEyMzAyMDkgMTQuOTcyODg4LDIuMjg0OTA4ODUgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
--icon-FilterSimple: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTkuOTUwODMzMzMsMC4yMiBDOS44NzgyODY2NywwLjA4NDQ5NzcxMDggOS43MzcwMzQsLTYuMTY5Njc5NTFlLTA1IDkuNTgzMzMzMzMsLTQuNjI1OTMyOGUtMTcgTDAuNDE2NjY2NjY3LC00LjYyNTkzMjhlLTE3IEMwLjI2MzEwMzQ1NCw3LjkzMjczNDM1ZS0wNSAwLjEyMjAzMTQsMC4wODQ2MTg0ODc1IDAuMDQ5NTQ5NDAxMiwwLjIxOTk5OTUyOSBDLTAuMDIyOTMyNTk3OCwwLjM1NTM4MDU3MSAtMC4wMTUwNzQwNTE3LDAuNTE5NjU2MDYyIDAuMDcsMC42NDc1IEwzLjMzMzMzMzMzLDUuNTQyNSBMMy4zMzMzMzMzMyw5LjU4MzMzMzMzIEMzLjMzMzMzMzMzLDkuODEzNDUyIDMuNTE5ODgxMzYsMTAgMy43NSwxMCBMNi4yNSwxMCBDNi40ODAxMTg2NCwxMCA2LjY2NjY2NjY3LDkuODEzNDUyIDYuNjY2NjY2NjcsOS41ODMzMzMzMyBMNi42NjY2NjY2Nyw1LjU0MjUgTDkuOTMsMC42NDc1IEMxMC4wMTUxOTU2LDAuNTE5NzI3OTkxIDEwLjAyMzIwMTMsMC4zNTU0NTA1NDcgOS45NTA4MzMzMywwLjIyIFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDMgMykiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
--icon-Fireworks: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTguNjY2NDcgMTUuMzMzM0g3LjMzMzE0QzcuMzMzMTQgOS44NDc5NyA0LjQ0NzggOC42MzA2MyA0LjQxODQ3IDguNjE5M0wzLjc5OTggOC4zNzEzIDQuMjk1MTQgNy4xMzMzIDQuOTE0NDcgNy4zODA2M0M1LjAyNTE0IDcuNDI1OTcgNi45NTE4IDguMjM1MyA3Ljk5OTggMTEuMTE0IDkuMDQ3OCA4LjIzNTk3IDEwLjk3NDUgNy40MjY2MyAxMS4wODUxIDcuMzgwNjNMMTEuNzA0NSA3LjEzMzMgMTIuMTk5OCA4LjM3MTMgMTEuNTg0NSA4LjYxNzNDMTEuNDM5OCA4LjY3OTk3IDguNjY2NDcgOS45NDE5NyA4LjY2NjQ3IDE1LjMzMzN6TTEwLjQ1MzEgMS43OTA1NEw4Ljc1NzcyIDEuNTQ0NTQgNy45OTk3Mi4wMDg1NDQ5MiA3LjI0MTcyIDEuNTQ0NTQgNS41NDYzOSAxLjc5MDU0IDYuNzczMDUgMi45ODY1NCA2LjQ4MzcyIDQuNjc1MjEgNy45OTk3MiAzLjg3Nzg4IDkuNTE1NzIgNC42NzUyMSA5LjIyNjM5IDIuOTg2NTQgMTAuNDUzMSAxLjc5MDU0ek01LjI5OTE3IDEyLjM1OEwzLjY5ODUgMTIuMTI1MyAyLjk4MzE3IDEwLjY3NTMgMi4yNjcxNyAxMi4xMjUzLjY2NjUwNCAxMi4zNTggMS44MjQ1IDEzLjQ4NjYgMS41NTExNyAxNS4wODA2IDIuOTgzMTcgMTQuMzI4NiA0LjQxNDUgMTUuMDgwNiA0LjE0MTE3IDEzLjQ4NjYgNS4yOTkxNyAxMi4zNTh6TTE1LjMzMzMgMTIuMzU4TDEzLjczMjcgMTIuMTI1MyAxMy4wMTY3IDEwLjY3NTMgMTIuMzAxMyAxMi4xMjUzIDEwLjcwMDcgMTIuMzU4IDExLjg1ODcgMTMuNDg2NiAxMS41ODUzIDE1LjA4MDYgMTMuMDE2NyAxNC4zMjg2IDE0LjQ0ODcgMTUuMDgwNiAxNC4xNzUzIDEzLjQ4NjYgMTUuMzMzMyAxMi4zNTh6IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTguNjY2MzQgNy41MzMxM1Y1LjM0MThINy4zMzMwMVY3LjUyMDQ2QzcuNTc2MjEgNy43NjgxMSA3LjgwMjUgOC4wMzE4MSA4LjAxMDM0IDguMzA5OCA4LjIxMjIgOC4wMzcxNyA4LjQzMTMyIDcuNzc3NzUgOC42NjYzNCA3LjUzMzEzek0xLjY2NjUgNy4zMzMyNUMyLjIxODc5IDcuMzMzMjUgMi42NjY1IDYuODg1NTQgMi42NjY1IDYuMzMzMjUgMi42NjY1IDUuNzgwOTcgMi4yMTg3OSA1LjMzMzI1IDEuNjY2NSA1LjMzMzI1IDEuMTE0MjIgNS4zMzMyNS42NjY1MDQgNS43ODA5Ny42NjY1MDQgNi4zMzMyNS42NjY1MDQgNi44ODU1NCAxLjExNDIyIDcuMzMzMjUgMS42NjY1IDcuMzMzMjV6TTE0LjMzMyA3LjMzMzI1QzE0Ljg4NTMgNy4zMzMyNSAxNS4zMzMgNi44ODU1NCAxNS4zMzMgNi4zMzMyNSAxNS4zMzMgNS43ODA5NyAxNC44ODUzIDUuMzMzMjUgMTQuMzMzIDUuMzMzMjUgMTMuNzgwNyA1LjMzMzI1IDEzLjMzMyA1Ljc4MDk3IDEzLjMzMyA2LjMzMzI1IDEzLjMzMyA2Ljg4NTU0IDEzLjc4MDcgNy4zMzMyNSAxNC4zMzMgNy4zMzMyNXoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=');
--icon-Folder: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMsNSBMMTMsNSBDMTMuNTUyMjg0Nyw1IDE0LDUuNDQ3NzE1MjUgMTQsNiBMMTQsMTMgQzE0LDEzLjU1MjI4NDcgMTMuNTUyMjg0NywxNCAxMywxNCBMMywxNCBDMi40NDc3MTUyNSwxNCAyLDEzLjU1MjI4NDcgMiwxMyBMMiw2IEMyLDUuNDQ3NzE1MjUgMi40NDc3MTUyNSw1IDMsNSBaIE00LDIgTDEyLDIgTDEyLDQgTDQsNCBMNCwyIFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
--icon-FontBold: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTMuMTk1MDk4OCAxLjgzNTQxOTloNS42OTAzODE4Yy43NTQ1OTUyIDAgMS40NzgyNzI0LjI5OTc1NjcgMi4wMTE4NTM0LjgzMzMzNzUuNTMzNTgxLjUzMzU4MDguODMzMzM3IDEuMjU3MjU4Mi44MzMzMzcgMi4wMTE4NTM1IDAgLjc1NDU5NTItLjI5OTc1NiAxLjQ3ODI3MjctLjgzMzMzNyAyLjAxMTg1MzVDMTAuMzYzNzUzIDcuMjI2MDQ1MSA5LjY0MDA3NTggNy41MjU4MDE4IDguODg1NDgwNiA3LjUyNTgwMThINS4wOTE4OTI3TTUuMDkxODkyNyA3LjUyNTgwMThoNS4yMTYxODMzYy44ODAzNTIgMCAxLjcyNDY1My4zNDk3MTgyIDIuMzQ3MTY5Ljk3MjIyMDcuNjIyNTAyLjYyMjUxNTIuOTcyMjIgMS40NjY4MTYxLjk3MjIyIDIuMzQ3MTY4NXYwYzAgLjg4MDM1My0uMzQ5NzE4IDEuNzI0NjU0LS45NzIyMiAyLjM0NzIxOS0uNjIyNTE2LjYyMjQwMi0xLjQ2NjgxNy45NzIxNy0yLjM0NzE2OS45NzIxN0gzLjE5NTA5ODhNNS4wOTE4OTI3IDEuODM1NDE5OVYxNC4xNjQ1OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDMwMDAwIiBzdHJva2Utd2lkdGg9IjEuMjY1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=');
--icon-FontItalic: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwSDEyVjEySDB6Ii8+PC9jbGlwUGF0aD48L2RlZnM+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMS4xMzU2IDAgMCAxLjEzNTYgLjk4MyAxLjM5KSIgY2xpcC1wYXRoPSJ1cmwoI2EpIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0ibSA0Ljg3NSwwLjM3NSBoIDQuNSIgc3Ryb2tlPSIjMDAwIi8+PHBhdGggZD0ibSAyLjYyNSwxMS42MjUgaCA0LjUiIHN0cm9rZT0iIzA2MDAwMCIvPjxwYXRoIGQ9Im0gNy4xMjUsMC4zNzUgLTIuMjUsMTEuMjUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLW9wYWNpdHk9Ii45OSIvPjwvZz48L3N2Zz4=');
@ -90,6 +91,7 @@
--icon-Pivot: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMsMSBMMTMsMSBDMTQuMTA0NTY5NSwxIDE1LDEuODk1NDMwNSAxNSwzIEwxNSwxMyBDMTUsMTQuMTA0NTY5NSAxNC4xMDQ1Njk1LDE1IDEzLDE1IEwzLDE1IEMxLjg5NTQzMDUsMTUgMSwxNC4xMDQ1Njk1IDEsMTMgTDEsMyBDMSwxLjg5NTQzMDUgMS44OTU0MzA1LDEgMywxIFogTTUuMzc1LDQuNSBMNS4zNzUsNC43ODU0NjM0MSBMNy42MzQ2NTAxLDguMDIyNzA3MzIgTDUuMzc1LDExLjA5NDUxMjIgTDUuMzc1LDExLjUgTDEwLjYyNSwxMS41IEwxMC42MjUsMTAuMDMyODE3MSBMOS44MjY0OTkwMSwxMC43MjY0MTQ2IEw2LjkxOTczMTYxLDEwLjcyNjQxNDYgTDYuOTE5NzMxNjEsMTAuNDE2OTYzNCBMOC45MDI4MzMsNy42MTU4NTM2NiBMNi45MTk3MzE2MSw0Ljk5MDg1MzY2IEw5Ljc3NDMxMjEzLDQuOTg3MzUzNjYgTDEwLjYyNSw2LjA5NTMxNzA3IEwxMC42MjUsNC41IEw1LjM3NSw0LjUgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
--icon-Plus: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTguNSw3LjUgTDEzLDcuNSBDMTMuMjc2MTQyNCw3LjUgMTMuNSw3LjcyMzg1NzYzIDEzLjUsOCBDMTMuNSw4LjI3NjE0MjM3IDEzLjI3NjE0MjQsOC41IDEzLDguNSBMOC41LDguNSBMOC41LDEzIEM4LjUsMTMuMjc2MTQyNCA4LjI3NjE0MjM3LDEzLjUgOCwxMy41IEM3LjcyMzg1NzYzLDEzLjUgNy41LDEzLjI3NjE0MjQgNy41LDEzIEw3LjUsOC41IEwzLDguNSBDMi43MjM4NTc2Myw4LjUgMi41LDguMjc2MTQyMzcgMi41LDggQzIuNSw3LjcyMzg1NzYzIDIuNzIzODU3NjMsNy41IDMsNy41IEw3LjUsNy41IEw3LjUsMyBDNy41LDIuNzIzODU3NjMgNy43MjM4NTc2MywyLjUgOCwyLjUgQzguMjc2MTQyMzcsMi41IDguNSwyLjcyMzg1NzYzIDguNSwzIEw4LjUsNy41IFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
--icon-Public: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6Ii8+PGcgc3Ryb2tlPSIjMTZCMzc4IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik05Ljc3NSAxMS4yOTNMNy4zMTIgMTAuNTkzQzcuMTIyMjE2NjEgMTAuNTM4OTUxMSA2Ljk4MTk3MzAyIDEwLjM3ODMzNyA2Ljk1NCAxMC4xODNMNi43NDcgOC43MjZDNy44MTQxMjAyNiA4LjIzODMwNjE1IDguNDk5MDAyMDkgNy4xNzMyODE3IDguNSA2TDguNSA0LjYyNkM4LjUyNTE5NzU2IDIuOTczMDAzMjUgNy4yNDI1MDU0NyAxLjU5NDE1MzM3IDUuNTkyIDEuNSA0Ljc4MDUzMjcgMS40NzUxMDMyIDMuOTkzNjIwMiAxLjc4MDE0ODI3IDMuNDEwOTUzMjMgMi4zNDU0Nzg0NiAyLjgyODI4NjI1IDIuOTEwODA4NjQgMi40OTk2MTgxNiAzLjY4ODE1MDk1IDIuNSA0LjVMMi41IDZDMi41MDA5OTc5MSA3LjE3MzI4MTcgMy4xODU4Nzk3NCA4LjIzODMwNjE1IDQuMjUzIDguNzI2TDQuMDQ2IDEwLjE3OUM0LjAxODAyNjk4IDEwLjM3NDMzNyAzLjg3Nzc4MzM5IDEwLjUzNDk1MTEgMy42ODggMTAuNTg5TDEuMjI1IDExLjI4OUMuNzk1OTk1Njg4IDExLjQxMTcwNzIuNTAwMTk4MjMgMTEuODAzNzkxOC41IDEyLjI1TC41IDE0LjUgMTAuNSAxNC41IDEwLjUgMTIuMjU0QzEwLjQ5OTgwMTggMTEuODA3NzkxOCAxMC4yMDQwMDQzIDExLjQxNTcwNzIgOS43NzUgMTEuMjkzek0xMi41IDE0LjVMMTUuNSAxNC41IDE1LjUgMTEuMjgxQzE1LjQ5OTk4NzkgMTAuODIyMzIwNiAxNS4xODc5MzExIDEwLjQyMjQ1OTEgMTQuNzQzIDEwLjMxMUwxMS44MjYgOS41ODJDMTEuNjI4NDcxIDkuNTMyNzA4NDEgMTEuNDgwNTUyNCA5LjM2ODU3NDEgMTEuNDUyIDkuMTY3TDExLjI0NyA3LjcyNkMxMi4zMTQxMjAzIDcuMjM4MzA2MTUgMTIuOTk5MDAyMSA2LjE3MzI4MTcgMTMgNUwxMyAzLjYyNkMxMy4wMjUxOTc2IDEuOTczMDAzMjUgMTEuNzQyNTA1NS41OTQxNTMzNjUgMTAuMDkyLjUgOS41MzQ0NjYxNC40ODI3MzcyNzIgOC45ODMxNjAzOS42MjEyNTYzMDYgOC41LjkiLz48L2c+PC9nPjwvc3ZnPg==');
--icon-PublicColor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTQiIHdpZHRoPSIxNiI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC0xKSIvPjxnIG9wYWNpdHk9Ii43ODMiPjxwYXRoIGQ9Ik0gMTUuMjc1LDEwLjI5MyAxMy4wODcsOS42NjggQyAxMi43MjY0NzgsOS41NjQ5MTc4IDEyLjQ1MzkyLDkuMjY4ODEwNSAxMi4zODEsOC45MDEgTCAxMi4yNDcsOC4yMjYgQyAxMy4zMTQxMiw3LjczODMwNjEgMTMuOTk5MDAyLDYuNjczMjgxNyAxNCw1LjUgViA0LjEyNiBDIDE0LjAyNTE5OCwyLjQ3MzAwMzMgMTIuNzQyNTA2LDEuMDk0MTUzNCAxMS4wOTIsMSA5Ljg3OTM3MDksMC45NjM0MTA4MiA4Ljc2NDA2NTUsMS42NjA3NzI3IDguMjY2LDIuNzY3IDguNzQzMDQ3OCwzLjQ2MTI3ODUgOC45OTg5MTk4LDQuMjgzNjI0NyA5LDUuMTI2IFYgNi41IEMgOC45OTgyMDc3LDYuODYzNzcwNiA4Ljk0NjA0NTYsNy4yMjU1NDA0IDguODQ1LDcuNTc1IDkuMTA0MjMyNSw3Ljg0Njk0MjMgOS40MTIyMzk1LDguMDY3NzcxMSA5Ljc1Myw4LjIyNiBMIDkuNjE5LDguOSBDIDkuNTQ2MDc5Niw5LjI2NzgxMDUgOS4yNzM1MjE5LDkuNTYzOTE3OCA4LjkxMyw5LjY2NyBMIDguMDcsOS45MDggOS41NSwxMC4zMzEgYyAwLjg1Njk2NCwwLjI0NzU1NCAxLjQ0NzcwNiwxLjAzMDk5OSAxLjQ1LDEuOTIzIFYgMTQuNSBjIC0wLjAwMTcsMC4xNzA3MiAtMC4wMzI3OCwwLjMzOTg3MSAtMC4wOTIsMC41IEggMTUuNSBjIDAuMjc2MTQyLDAgMC41LC0wLjIyMzg1OCAwLjUsLTAuNSB2IC0zLjI0NiBjIC0xLjk4ZS00LC0wLjQ0NjIwOCAtMC4yOTU5OTYsLTAuODM4MjkzIC0wLjcyNSwtMC45NjEgeiIgZmlsbD0iI2U2YTExNyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMSkiLz48cGF0aCBkPSJNIDkuMjc1LDExLjI5MyA3LjA4NywxMC42NjggQyA2LjcyNjIwMjMsMTAuNTY0NzU0IDYuNDUzNTgzLDEwLjI2ODE5NCA2LjM4MSw5LjkgTCA2LjI0Nyw5LjIyNSBDIDcuMzEzNzkxNCw4LjczNzQ1NjkgNy45OTg2MTEyLDcuNjcyOTE5NSA4LDYuNSBWIDUuMTI2IEMgOC4wMjUxOTc2LDMuNDczMDAzMyA2Ljc0MjUwNTUsMi4wOTQxNTM0IDUuMDkyLDIgNC4yODA1MzI3LDEuOTc1MTAzMiAzLjQ5MzYyMDIsMi4yODAxNDgzIDIuOTEwOTUzMiwyLjg0NTQ3ODUgMi4zMjgyODYzLDMuNDEwODA4NiAxLjk5OTYxODIsNC4xODgxNTA5IDIsNSB2IDEuNSBjIDkuOTc5ZS00LDEuMTczMjgxNyAwLjY4NTg3OTcsMi4yMzgzMDYyIDEuNzUzLDIuNzI2IEwgMy42MTksOS45IEMgMy41NDYwOCwxMC4yNjc4MTEgMy4yNzM1MjE5LDEwLjU2MzkxOCAyLjkxMywxMC42NjcgTCAwLjcyNSwxMS4yOTIgQyAwLjI5NTYzOTI2LDExLjQxNDgwOSAtMi40ODE3NzE2ZS00LDExLjgwNzQyMSAwLDEyLjI1NCBWIDE0LjUgQyAwLDE0Ljc3NjE0MiAwLjIyMzg1NzYzLDE1IDAuNSwxNSBoIDkgQyA5Ljc3NjE0MjQsMTUgMTAsMTQuNzc2MTQyIDEwLDE0LjUgViAxMi4yNTQgQyA5Ljk5OTgwMTgsMTEuODA3NzkyIDkuNzA0MDA0MywxMS40MTU3MDcgOS4yNzUsMTEuMjkzIFoiIGZpbGw9IiNmZmYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTEpIi8+PC9nPjwvZz48L3N2Zz4=');
--icon-PublicFilled: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC0xKSIvPjxnIGZpbGw9IiMxNkIzNzgiIGZpbGwtcnVsZT0ibm9uemVybyI+PHBhdGggZD0iTTE1LjI3NSwxMC4yOTMgTDEzLjA4Nyw5LjY2OCBDMTIuNzI2NDc4MSw5LjU2NDkxNzggMTIuNDUzOTIwNCw5LjI2ODgxMDUgMTIuMzgxLDguOTAxIEwxMi4yNDcsOC4yMjYgQzEzLjMxNDEyMDMsNy43MzgzMDYxNSAxMy45OTkwMDIxLDYuNjczMjgxNyAxNCw1LjUgTDE0LDQuMTI2IEMxNC4wMjUxOTc2LDIuNDczMDAzMjUgMTIuNzQyNTA1NSwxLjA5NDE1MzM3IDExLjA5MiwxIEM5Ljg3OTM3MDksMC45NjM0MTA4MjIgOC43NjQwNjU1LDEuNjYwNzcyNjkgOC4yNjYsMi43NjcgQzguNzQzMDQ3OCwzLjQ2MTI3ODUgOC45OTg5MTk4NCw0LjI4MzYyNDc0IDksNS4xMjYgTDksNi41IEM4Ljk5ODIwNzc0LDYuODYzNzcwNTcgOC45NDYwNDU1OCw3LjIyNTU0MDM4IDguODQ1LDcuNTc1IEM5LjEwNDIzMjUzLDcuODQ2OTQyMjYgOS40MTIyMzk1Myw4LjA2Nzc3MTA2IDkuNzUzLDguMjI2IEw5LjYxOSw4LjkgQzkuNTQ2MDc5NTcsOS4yNjc4MTA1IDkuMjczNTIxODcsOS41NjM5MTc4IDguOTEzLDkuNjY3IEw4LjA3LDkuOTA4IEw5LjU1LDEwLjMzMSBDMTAuNDA2OTY0MywxMC41Nzg1NTM2IDEwLjk5NzcwNTksMTEuMzYxOTk5MyAxMSwxMi4yNTQgTDExLDE0LjUgQzEwLjk5ODM0MjgsMTQuNjcwNzE5OCAxMC45NjcyMTg5LDE0LjgzOTg3MTUgMTAuOTA4LDE1IEwxNS41LDE1IEMxNS43NzYxNDI0LDE1IDE2LDE0Ljc3NjE0MjQgMTYsMTQuNSBMMTYsMTEuMjU0IEMxNS45OTk4MDE4LDEwLjgwNzc5MTggMTUuNzA0MDA0MywxMC40MTU3MDcyIDE1LjI3NSwxMC4yOTMgWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMSkiLz48cGF0aCBkPSJNOS4yNzUsMTEuMjkzIEw3LjA4NywxMC42NjggQzYuNzI2MjAyMzIsMTAuNTY0NzUzOSA2LjQ1MzU4MywxMC4yNjgxOTM1IDYuMzgxLDkuOSBMNi4yNDcsOS4yMjUgQzcuMzEzNzkxNDEsOC43Mzc0NTY5MyA3Ljk5ODYxMTI1LDcuNjcyOTE5NTQgOCw2LjUgTDgsNS4xMjYgQzguMDI1MTk3NTYsMy40NzMwMDMyNSA2Ljc0MjUwNTQ3LDIuMDk0MTUzMzcgNS4wOTIsMiBDNC4yODA1MzI3LDEuOTc1MTAzMiAzLjQ5MzYyMDIsMi4yODAxNDgyNyAyLjkxMDk1MzIzLDIuODQ1NDc4NDYgQzIuMzI4Mjg2MjUsMy40MTA4MDg2NCAxLjk5OTYxODE2LDQuMTg4MTUwOTUgMiw1IEwyLDYuNSBDMi4wMDA5OTc5MSw3LjY3MzI4MTcgMi42ODU4Nzk3NCw4LjczODMwNjE1IDMuNzUzLDkuMjI2IEwzLjYxOSw5LjkgQzMuNTQ2MDc5NTcsMTAuMjY3ODEwNSAzLjI3MzUyMTg3LDEwLjU2MzkxNzggMi45MTMsMTAuNjY3IEwwLjcyNSwxMS4yOTIgQzAuMjk1NjM5MjYyLDExLjQxNDgwOTEgLTAuMDAwMjQ4MTc3MTU3LDExLjgwNzQyMTIgMCwxMi4yNTQgTDAsMTQuNSBDMy4zODE3NjU4MWUtMTcsMTQuNzc2MTQyNCAwLjIyMzg1NzYyNSwxNSAwLjUsMTUgTDkuNSwxNSBDOS43NzYxNDIzNywxNSAxMCwxNC43NzYxNDI0IDEwLDE0LjUgTDEwLDEyLjI1NCBDOS45OTk4MDE3NywxMS44MDc3OTE4IDkuNzA0MDA0MzEsMTEuNDE1NzA3MiA5LjI3NSwxMS4yOTMgWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMSkiLz48L2c+PC9nPjwvc3ZnPg==');
--icon-Redo: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTIuMzU1MzI4LDUgTDYuNTAwMTAyMzgsNSBDNi43NzYyNDQ3Niw1IDcuMDAwMTAyMzgsNS4yMjM4NTc2MyA3LjAwMDEwMjM4LDUuNSBDNy4wMDAxMDIzOCw1Ljc3NjE0MjM3IDYuNzc2MjQ0NzYsNiA2LjUwMDEwMjM4LDYgTDEuNTEwMjEyMzgsNiBDMS40ODY4NTQ0NCw2LjAwMDQ5MTk4IDEuNDYzMzU4OTcsNS45OTkzNDQxNCAxLjQzOTg5NjI3LDUuOTk2NDk5MjUgQzEuMzYwMzg0NTQsNS45ODY4NzA1OCAxLjI4NjYwNzQzLDUuOTU4NjY1NjMgMS4yMjMwNzYwNCw1LjkxNjMwNDg0IEMxLjA5OTMxODAxLDUuODM0MTc1NDcgMS4wMjE5NjcwOSw1LjcwMzQ3ODggMS4wMDQwMTY1Niw1LjU2Mjg2NjI5IEMxLjAwMTkxMjc3LDUuNTQ2MDk2MDIgMS4wMDA2Mzk1Niw1LjUyOTA2NzQgMS4wMDAyMzk0Miw1LjUxMTgyMjkyIEMwLjk5OTk1NjM3MSw1LjUwNDI3MzIxIDAuOTk5OTQyNjg0LDUuNDk2NzA0NiAxLjAwMDEwMjM4LDUuNDg5MTI2OTMgTDEuMDAwMTAyMzgsMC41IEMxLjAwMDEwMjM4LDAuMjIzODU3NjI1IDEuMjIzOTYwMDEsMCAxLjUwMDEwMjM4LDAgQzEuNzc2MjQ0NzYsMCAyLjAwMDEwMjM4LDAuMjIzODU3NjI1IDIuMDAwMTAyMzgsMC41IEwyLjAwMDEwMjM4LDMuNzc0NjkzMTYgQzMuMzY4NjQzMjgsMi4wMzk0MDM0MyA1LjMyOTE3Nzk4LDEgNy41MDAxMDIzOCwxIEMxMS42NDIyNDQ4LDEgMTUuMDAwMTAyNCw0LjM1Nzg1NzYzIDE1LjAwMDEwMjQsOC41IEMxNS4wMDAxMDI0LDEyLjY0MjE0MjQgMTEuNjQyMjQ0OCwxNiA3LjUwMDEwMjM4LDE2IEM3LjIyMzk2MDAxLDE2IDcuMDAwMTAyMzgsMTUuNzc2MTQyNCA3LjAwMDEwMjM4LDE1LjUgQzcuMDAwMTAyMzgsMTUuMjIzODU3NiA3LjIyMzk2MDAxLDE1IDcuNTAwMTAyMzgsMTUgQzExLjA4OTk2LDE1IDE0LjAwMDEwMjQsMTIuMDg5ODU3NiAxNC4wMDAxMDI0LDguNSBDMTQuMDAwMTAyNCw0LjkxMDE0MjM3IDExLjA4OTk2LDIgNy41MDAxMDIzOCwyIEM1LjQxNTg0ODkyLDIgMy41NDU2NTQwMiwzLjEzMDY0MDcgMi4zNTUzMjgsNSBaIiBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHRyYW5zZm9ybT0ibWF0cml4KC0xIDAgMCAxIDE2IDApIi8+PC9zdmc+');
--icon-Remove: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTYsNCBMNiwyLjUgQzYsMi4yMjM4NTc2MyA2LjIyMzg1NzYzLDIgNi41LDIgTDkuNSwyIEM5Ljc3NjE0MjM3LDIgMTAsMi4yMjM4NTc2MyAxMCwyLjUgTDEwLDQgTDEzLjUsNCBDMTMuNzc2MTQyNCw0IDE0LDQuMjIzODU3NjMgMTQsNC41IEMxNCw0Ljc3NjE0MjM3IDEzLjc3NjE0MjQsNSAxMy41LDUgTDIuNSw1IEMyLjIyMzg1NzYzLDUgMiw0Ljc3NjE0MjM3IDIsNC41IEMyLDQuMjIzODU3NjMgMi4yMjM4NTc2Myw0IDIuNSw0IEw2LDQgWiBNNyw0IEw5LDQgTDksMyBMNywzIEw3LDQgWiBNMTEsNi41IEMxMSw2LjIyMzg1NzYzIDExLjIyMzg1NzYsNiAxMS41LDYgQzExLjc3NjE0MjQsNiAxMiw2LjIyMzg1NzYzIDEyLDYuNSBMMTIsMTIuNSBDMTIsMTMuMzI4NDI3MSAxMS4zMjg0MjcxLDE0IDEwLjUsMTQgTDUuNSwxNCBDNC42NzE1NzI4OCwxNCA0LDEzLjMyODQyNzEgNCwxMi41IEw0LDYuNSBDNCw2LjIyMzg1NzYzIDQuMjIzODU3NjMsNiA0LjUsNiBDNC43NzYxNDIzNyw2IDUsNi4yMjM4NTc2MyA1LDYuNSBMNSwxMi41IEM1LDEyLjc3NjE0MjQgNS4yMjM4NTc2MywxMyA1LjUsMTMgTDEwLjUsMTMgQzEwLjc3NjE0MjQsMTMgMTEsMTIuNzc2MTQyNCAxMSwxMi41IEwxMSw2LjUgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');

@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.66647 15.3333H7.33314C7.33314 9.84797 4.4478 8.63063 4.41847 8.6193L3.7998 8.3713L4.29514 7.1333L4.91447 7.38063C5.02514 7.42597 6.9518 8.2353 7.9998 11.114C9.0478 8.23597 10.9745 7.42663 11.0851 7.38063L11.7045 7.1333L12.1998 8.3713L11.5845 8.6173C11.4398 8.67997 8.66647 9.94197 8.66647 15.3333Z" fill="white"/>
<path d="M10.4531 1.79054L8.75772 1.54454L7.99972 0.00854492L7.24172 1.54454L5.54639 1.79054L6.77305 2.98654L6.48372 4.67521L7.99972 3.87788L9.51572 4.67521L9.22639 2.98654L10.4531 1.79054Z" fill="white"/>
<path d="M5.29917 12.358L3.6985 12.1253L2.98317 10.6753L2.26717 12.1253L0.666504 12.358L1.8245 13.4866L1.55117 15.0806L2.98317 14.3286L4.4145 15.0806L4.14117 13.4866L5.29917 12.358Z" fill="white"/>
<path d="M15.3333 12.358L13.7327 12.1253L13.0167 10.6753L12.3013 12.1253L10.7007 12.358L11.8587 13.4866L11.5853 15.0806L13.0167 14.3286L14.4487 15.0806L14.1753 13.4866L15.3333 12.358Z" fill="white"/>
<path d="M8.66634 7.53313V5.3418H7.33301V7.52046C7.57621 7.76811 7.8025 8.03181 8.01034 8.3098C8.2122 8.03717 8.43132 7.77775 8.66634 7.53313Z" fill="white"/>
<path d="M1.6665 7.33325C2.21879 7.33325 2.6665 6.88554 2.6665 6.33325C2.6665 5.78097 2.21879 5.33325 1.6665 5.33325C1.11422 5.33325 0.666504 5.78097 0.666504 6.33325C0.666504 6.88554 1.11422 7.33325 1.6665 7.33325Z" fill="white"/>
<path d="M14.333 7.33325C14.8853 7.33325 15.333 6.88554 15.333 6.33325C15.333 5.78097 14.8853 5.33325 14.333 5.33325C13.7807 5.33325 13.333 5.78097 13.333 6.33325C13.333 6.88554 13.7807 7.33325 14.333 7.33325Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg4593"
version="1.1"
viewBox="0 0 16 14"
height="14px"
width="16px">
<metadata
id="metadata4599">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>1</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4597">
<linearGradient
osb:paint="solid"
id="linearGradient5335">
<stop
id="stop5333"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
</defs>
<!-- Generator: Sketch 55 (78076) - https://sketchapp.com -->
<title
id="title4581">1</title>
<desc
id="desc4583">Created with Sketch.</desc>
<g
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"
id="Onboarding-&amp;-Panel">
<g
transform="translate(-482,-145)"
id="Main-List-Copy">
<g
transform="translate(482,144)"
id="1">
<rect
height="16"
width="16"
y="0"
x="0"
id="Rectangle" />
<g
style="opacity:0.78299997;fill:none;fill-opacity:1;fill-rule:evenodd"
id="Group">
<path
style="fill:#e6a117;fill-opacity:1;fill-rule:evenodd"
id="Path"
d="M 15.275,10.293 13.087,9.668 C 12.726478,9.5649178 12.45392,9.2688105 12.381,8.901 L 12.247,8.226 C 13.31412,7.7383061 13.999002,6.6732817 14,5.5 V 4.126 C 14.025198,2.4730033 12.742506,1.0941534 11.092,1 9.8793709,0.96341082 8.7640655,1.6607727 8.266,2.767 8.7430478,3.4612785 8.9989198,4.2836247 9,5.126 V 6.5 C 8.9982077,6.8637706 8.9460456,7.2255404 8.845,7.575 9.1042325,7.8469423 9.4122395,8.0677711 9.753,8.226 L 9.619,8.9 C 9.5460796,9.2678105 9.2735219,9.5639178 8.913,9.667 L 8.07,9.908 9.55,10.331 c 0.856964,0.247554 1.447706,1.030999 1.45,1.923 V 14.5 c -0.0017,0.17072 -0.03278,0.339871 -0.092,0.5 H 15.5 c 0.276142,0 0.5,-0.223858 0.5,-0.5 v -3.246 c -1.98e-4,-0.446208 -0.295996,-0.838293 -0.725,-0.961 z" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
id="path4587"
d="M 9.275,11.293 7.087,10.668 C 6.7262023,10.564754 6.453583,10.268194 6.381,9.9 L 6.247,9.225 C 7.3137914,8.7374569 7.9986112,7.6729195 8,6.5 V 5.126 C 8.0251976,3.4730033 6.7425055,2.0941534 5.092,2 4.2805327,1.9751032 3.4936202,2.2801483 2.9109532,2.8454785 2.3282863,3.4108086 1.9996182,4.1881509 2,5 v 1.5 c 9.979e-4,1.1732817 0.6858797,2.2383062 1.753,2.726 L 3.619,9.9 C 3.54608,10.267811 3.2735219,10.563918 2.913,10.667 L 0.725,11.292 C 0.29563926,11.414809 -2.4817716e-4,11.807421 0,12.254 V 14.5 C 0,14.776142 0.22385763,15 0.5,15 h 9 C 9.7761424,15 10,14.776142 10,14.5 V 12.254 C 9.9998018,11.807792 9.7040043,11.415707 9.275,11.293 Z" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -6,6 +6,7 @@
import {isAffirmative} from 'app/common/gutil';
import {HomeDBManager} from 'app/gen-server/lib/HomeDBManager';
import {TEAM_FREE_PLAN} from 'app/common/Features';
const debugging = isAffirmative(process.env.DEBUG) || isAffirmative(process.env.VERBOSE);
@ -91,7 +92,7 @@ export async function main() {
}, {
setUserAsOwner: false,
useNewPlan: true,
planType: 'teamFree'
planType: TEAM_FREE_PLAN
});
}
}

@ -82,7 +82,9 @@ export function setupTestSuite(options?: TestSuiteOptions) {
checkForExtraWindows();
// After every suite, clear sessionStorage and localStorage to avoid affecting other tests.
after(clearCurrentWindowStorage);
if (!process.env.NO_CLEANUP) {
after(clearCurrentWindowStorage);
}
// Also, log out, to avoid logins interacting, unless NO_CLEANUP is requested (useful for
// debugging tests).
if (!process.env.NO_CLEANUP) {

Loading…
Cancel
Save