mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Implement updated DocMenu UI: list/card mode and sort mode.
Summary: - Add org-wide currentSort and currentView, saved as user preferences. - Add per-workspace currentSort and currentView, backed by localStorage. - Move localStorage-based observables to a separate file. - Move hard-coded data about example docs to a separate file. - Add UI for toggling sort and view mode. - Removed unused features of buttonSelect to simplify it, and added support for light style of buttons. - Added `parse` helper method to StringUnion, and use it in a few places where it simplifies code. - Set `needRealOrg: true` in HomeDBManager.updateOrg() to fix saving prefs for mergedOrg. Test Plan: WIP: Fixed some affected tests. New tests not yet written. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2587
This commit is contained in:
		
							parent
							
								
									20d8124f45
								
							
						
					
					
						commit
						0a5afd1f98
					
				@ -1,3 +1,12 @@
 | 
			
		||||
import {StringUnion} from 'app/common/StringUnion';
 | 
			
		||||
 | 
			
		||||
export const SortPref = StringUnion("name", "date");
 | 
			
		||||
export type SortPref = typeof SortPref.type;
 | 
			
		||||
 | 
			
		||||
export const ViewPref = StringUnion("list", "icons");
 | 
			
		||||
export type ViewPref = typeof ViewPref.type;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// A collection of preferences related to a user or org (or combination).
 | 
			
		||||
export interface Prefs {
 | 
			
		||||
  // TODO replace this with real preferences.
 | 
			
		||||
@ -5,5 +14,10 @@ export interface Prefs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type UserPrefs = Prefs;
 | 
			
		||||
export type UserOrgPrefs = Prefs;
 | 
			
		||||
 | 
			
		||||
export interface UserOrgPrefs extends Prefs {
 | 
			
		||||
  docMenuSort?: SortPref;
 | 
			
		||||
  docMenuView?: ViewPref;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type OrgPrefs = Prefs;
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,13 @@ export const StringUnion = <UnionType extends string>(...values: UnionType[]) =>
 | 
			
		||||
    return value;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const unionNamespace = {guard, check, values};
 | 
			
		||||
  /**
 | 
			
		||||
   * StringUnion.parse(value) returns value when it's valid, and undefined otherwise.
 | 
			
		||||
   */
 | 
			
		||||
  const parse = (value: string|null|undefined): UnionType|undefined => {
 | 
			
		||||
    return value != null && guard(value) ? value : undefined;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const unionNamespace = {guard, check, parse, values};
 | 
			
		||||
  return Object.freeze(unionNamespace as typeof unionNamespace & {type: UnionType});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -153,7 +153,7 @@ export function encodeUrl(gristConfig: Partial<GristLoadConfig>,
 | 
			
		||||
    } else {
 | 
			
		||||
      parts.push(`doc/${encodeURIComponent(state.doc)}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (state.mode && parseOpenDocMode(state.mode)) {
 | 
			
		||||
    if (state.mode && OpenDocMode.guard(state.mode)) {
 | 
			
		||||
      parts.push(`/m/${state.mode}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (state.docPage) {
 | 
			
		||||
@ -235,19 +235,19 @@ export function decodeUrl(gristConfig: Partial<GristLoadConfig>, location: Locat
 | 
			
		||||
  } else {
 | 
			
		||||
    if (map.has('p')) {
 | 
			
		||||
      const p = map.get('p')!;
 | 
			
		||||
      state.homePage = HomePage.guard(p) ? p : undefined;
 | 
			
		||||
      state.homePage = HomePage.parse(p);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (map.has('m')) { state.mode = parseOpenDocMode(map.get('m')!); }
 | 
			
		||||
  if (map.has('m')) { state.mode = OpenDocMode.parse(map.get('m')); }
 | 
			
		||||
  if (sp.has('newui')) { state.newui = useNewUI(sp.get('newui') ? sp.get('newui') === '1' : undefined); }
 | 
			
		||||
  if (map.has('billing')) { state.billing = parseBillingPage(map.get('billing')!); }
 | 
			
		||||
  if (map.has('welcome')) { state.welcome = parseWelcomePage(map.get('welcome')!); }
 | 
			
		||||
  if (map.has('billing')) { state.billing = BillingSubPage.parse(map.get('billing')) || 'billing'; }
 | 
			
		||||
  if (map.has('welcome')) { state.welcome = WelcomePage.parse(map.get('welcome')) || 'user'; }
 | 
			
		||||
  if (sp.has('billingPlan')) { state.params!.billingPlan = sp.get('billingPlan')!; }
 | 
			
		||||
  if (sp.has('billingTask')) {
 | 
			
		||||
    state.params!.billingTask = parseBillingTask(sp.get('billingTask')!);
 | 
			
		||||
    state.params!.billingTask = BillingTask.parse(sp.get('billingTask'));
 | 
			
		||||
  }
 | 
			
		||||
  if (sp.has('style')) {
 | 
			
		||||
    state.params!.style = parseInterfaceStyle(sp.get('style')!);
 | 
			
		||||
    state.params!.style = InterfaceStyle.parse(sp.get('style'));
 | 
			
		||||
  }
 | 
			
		||||
  if (sp.has('embed')) {
 | 
			
		||||
    const embed = state.params!.embed = isAffirmative(sp.get('embed'));
 | 
			
		||||
@ -289,41 +289,6 @@ function parseDocPage(p: string) {
 | 
			
		||||
  return parseInt(p, 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * parseBillingPage ensures that the billing page value is a valid BillingPageType.
 | 
			
		||||
 */
 | 
			
		||||
function parseBillingPage(p: string): BillingPage {
 | 
			
		||||
  return BillingSubPage.guard(p) ? p : 'billing';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * parseBillingTask ensures that the value is a valid BillingTask or undefined.
 | 
			
		||||
 */
 | 
			
		||||
function parseBillingTask(t: string): BillingTask|undefined {
 | 
			
		||||
  return BillingTask.guard(t) ? t : undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * parseOpenDocMode ensures that the value is a valid OpenDocMode or undefined.
 | 
			
		||||
 */
 | 
			
		||||
function parseOpenDocMode(p: string): OpenDocMode|undefined {
 | 
			
		||||
  return OpenDocMode.guard(p) ? p : undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * parse welcome page ensure that the value is a valid WelcomePage, default to 'user' if not.
 | 
			
		||||
 */
 | 
			
		||||
function parseWelcomePage(p: string): WelcomePage {
 | 
			
		||||
  return WelcomePage.guard(p) ? p : 'user';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Read interface style and make sure it is either valid or left undefined.
 | 
			
		||||
 */
 | 
			
		||||
function parseInterfaceStyle(t: string): InterfaceStyle|undefined {
 | 
			
		||||
  return InterfaceStyle.guard(t) ? t : undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parses the URL like "foo.bar.baz" into the pair {org: "foo", base: ".bar.baz"}.
 | 
			
		||||
 * Port is allowed and included into base.
 | 
			
		||||
 | 
			
		||||
@ -1216,6 +1216,7 @@ export class HomeDBManager extends EventEmitter {
 | 
			
		||||
      const orgQuery = this.org(scope, orgKey, {
 | 
			
		||||
        manager,
 | 
			
		||||
        markPermissions,
 | 
			
		||||
        needRealOrg: true
 | 
			
		||||
      });
 | 
			
		||||
      const queryResult = await verifyIsPermitted(orgQuery);
 | 
			
		||||
      if (queryResult.status !== 200) {
 | 
			
		||||
@ -3198,11 +3199,11 @@ export class HomeDBManager extends EventEmitter {
 | 
			
		||||
        const prefs = this._normalizeQueryResults(subValue, childOptions);
 | 
			
		||||
        for (const pref of prefs) {
 | 
			
		||||
          if (pref.orgId && pref.userId) {
 | 
			
		||||
            value['userOrgPrefs'] = pref.prefs;
 | 
			
		||||
            value.userOrgPrefs = pref.prefs;
 | 
			
		||||
          } else if (pref.orgId) {
 | 
			
		||||
            value['orgPrefs'] = pref.prefs;
 | 
			
		||||
            value.orgPrefs = pref.prefs;
 | 
			
		||||
          } else if (pref.userId) {
 | 
			
		||||
            value['userPrefs'] = pref.prefs;
 | 
			
		||||
            value.userPrefs = pref.prefs;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user