mirror of
https://github.com/urbit/shrub.git
synced 2024-12-19 08:32:39 +03:00
Merge pull request #5349 from urbit/hm/local-storage-versioning
userspace: updated local storage versioning schema
This commit is contained in:
commit
72a9d90ec1
2
pkg/grid/.env
Normal file
2
pkg/grid/.env
Normal file
@ -0,0 +1,2 @@
|
||||
# Change manually to clear local storage once
|
||||
VITE_LAST_WIPE=2021-10-20
|
1
pkg/grid/.gitignore
vendored
1
pkg/grid/.gitignore
vendored
@ -6,4 +6,3 @@ dist-ssr
|
||||
stats.html
|
||||
.eslintcache
|
||||
.vercel
|
||||
.env
|
@ -18,6 +18,7 @@
|
||||
</head>
|
||||
<body class="text-sm leading-6 font-sans text-gray-900 bg-white antialiased">
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/storage-wipe.ts"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
8
pkg/grid/src/env.d.ts
vendored
Normal file
8
pkg/grid/src/env.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
interface ImportMetaEnv extends Readonly<Record<string, string>> {
|
||||
readonly VITE_LAST_WIPE: string;
|
||||
readonly VITE_STORAGE_VERSION: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
@ -4,7 +4,7 @@ import { useProtocolHandling, setLocalState } from '../../state/local';
|
||||
|
||||
export function InterfacePrefs() {
|
||||
const protocolHandling = useProtocolHandling();
|
||||
const secure = window.location.protocol === 'https:';
|
||||
const secure = window.location.protocol === 'https:' || window.location.hostname === 'localhost';
|
||||
const linkHandlingAllowed = secure && 'registerProtocolHandler' in window.navigator;
|
||||
const toggleProtoHandling = async () => {
|
||||
if (!protocolHandling && window?.navigator?.registerProtocolHandler) {
|
||||
|
@ -24,7 +24,7 @@ async function toggleMentions() {
|
||||
export const NotificationPrefs = () => {
|
||||
const doNotDisturb = useSettingsState(selDnd);
|
||||
const mentions = useHarkStore(selMentions);
|
||||
const secure = window.location.protocol === 'https:';
|
||||
const secure = window.location.protocol === 'https:' || window.location.hostname === 'localhost';
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -11,7 +11,12 @@ import { AppLink } from '../../components/AppLink';
|
||||
import { ShipName } from '../../components/ShipName';
|
||||
import { ProviderLink } from '../../components/ProviderLink';
|
||||
import useDocketState, { ChargesWithDesks, useCharges } from '../../state/docket';
|
||||
import { getAppHref } from '../../state/util';
|
||||
import {
|
||||
clearStorageMigration,
|
||||
createStorageKey,
|
||||
getAppHref,
|
||||
storageVersion
|
||||
} from '../../state/util';
|
||||
import useContactState from '../../state/contact';
|
||||
|
||||
export interface RecentsStore {
|
||||
@ -61,8 +66,9 @@ export const useRecentsStore = create<RecentsStore>(
|
||||
}),
|
||||
{
|
||||
whitelist: ['recentApps', 'recentDevs'],
|
||||
name: `${window.ship}-recents-store`,
|
||||
version: import.meta.env.VITE_SHORTHASH as any
|
||||
name: createStorageKey('recents-store'),
|
||||
version: storageVersion,
|
||||
migrate: clearStorageMigration
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -7,7 +7,7 @@ import { persist } from 'zustand/middleware';
|
||||
import Urbit, { SubscriptionRequestInterface } from '@urbit/http-api';
|
||||
import { Poke } from '@urbit/api';
|
||||
import api from './api';
|
||||
import { useMockData } from './util';
|
||||
import { clearStorageMigration, createStorageKey, storageVersion, useMockData } from './util';
|
||||
|
||||
setAutoFreeze(false);
|
||||
enablePatches();
|
||||
@ -73,10 +73,10 @@ export const optReduceState = <S extends Record<string, unknown>, U>(
|
||||
/* eslint-disable-next-line import/no-mutable-exports */
|
||||
export let stateStorageKeys: string[] = [];
|
||||
|
||||
export const stateStorageKey = (stateName: string) => {
|
||||
stateName = `${window.ship}-Grid${stateName}State-${import.meta.env.VITE_SHORTHASH as any}`;
|
||||
stateStorageKeys = [...new Set([...stateStorageKeys, stateName])];
|
||||
return stateName;
|
||||
export const stateStorageKey = (stateName: string): string => {
|
||||
const key = createStorageKey(`${stateName}State`);
|
||||
stateStorageKeys = [...new Set([...stateStorageKeys, key])];
|
||||
return key;
|
||||
};
|
||||
|
||||
(window as any).clearStates = () => {
|
||||
@ -149,7 +149,9 @@ export const createState = <T extends Record<string, unknown>>(
|
||||
}),
|
||||
{
|
||||
blacklist,
|
||||
name: stateStorageKey(name)
|
||||
name: stateStorageKey(name),
|
||||
version: storageVersion,
|
||||
migrate: clearStorageMigration
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import create from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import produce from 'immer';
|
||||
import { clearStorageMigration, createStorageKey, storageVersion } from './util';
|
||||
|
||||
interface LocalState {
|
||||
protocolHandling: boolean;
|
||||
@ -16,7 +17,9 @@ export const useLocalState = create<LocalState>(
|
||||
protocolHandling: false
|
||||
}),
|
||||
{
|
||||
name: 'grid-local'
|
||||
name: createStorageKey('local'),
|
||||
version: storageVersion,
|
||||
migrate: clearStorageMigration
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -50,3 +50,14 @@ export function getDarkColor(color: string): string {
|
||||
const hslaColor = parseToHsla(color);
|
||||
return hsla(hslaColor[0], hslaColor[1], 1 - hslaColor[2], 1);
|
||||
}
|
||||
|
||||
export function createStorageKey(name: string): string {
|
||||
return `~${window.ship}/${window.desk}/${name}`;
|
||||
}
|
||||
|
||||
// for purging storage with version updates
|
||||
export function clearStorageMigration<T>() {
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
export const storageVersion = parseInt(import.meta.env.VITE_STORAGE_VERSION, 10);
|
||||
|
12
pkg/grid/src/storage-wipe.ts
Normal file
12
pkg/grid/src/storage-wipe.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { createStorageKey } from './state/util';
|
||||
|
||||
const key = createStorageKey(`storage-wipe-${import.meta.env.VITE_LAST_WIPE}`);
|
||||
const wiped = localStorage.getItem(key);
|
||||
|
||||
// Loaded before everything, this clears local storage just once.
|
||||
// Change VITE_LAST_WIPE in .env to date of wipe
|
||||
|
||||
if (!wiped) {
|
||||
localStorage.clear();
|
||||
localStorage.setItem(key, 'true');
|
||||
}
|
@ -7,13 +7,7 @@ import { execSync } from 'child_process';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default ({ mode }) => {
|
||||
if (mode !== 'mock') {
|
||||
// using current commit until release
|
||||
const GIT_DESC = execSync('git rev-parse --short HEAD', { encoding: 'utf8' }).trim();
|
||||
process.env.VITE_SHORTHASH = GIT_DESC;
|
||||
} else {
|
||||
process.env.VITE_SHORTHASH = '1';
|
||||
}
|
||||
process.env.VITE_STORAGE_VERSION = Date.now().toString();
|
||||
|
||||
Object.assign(process.env, loadEnv(mode, process.cwd()));
|
||||
const SHIP_URL = process.env.SHIP_URL || process.env.VITE_SHIP_URL || 'http://localhost:8080';
|
||||
|
@ -109,6 +109,8 @@ module.exports = {
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.LANDSCAPE_SHORTHASH': JSON.stringify(GIT_DESC),
|
||||
'process.env.LANDSCAPE_STORAGE_VERSION': JSON.stringify(Date.now()),
|
||||
'process.env.LANDSCAPE_LAST_WIPE': JSON.stringify('2021-10-20'),
|
||||
'process.env.TUTORIAL_HOST': JSON.stringify('~difmex-passed'),
|
||||
'process.env.TUTORIAL_GROUP': JSON.stringify('beginner-island'),
|
||||
'process.env.TUTORIAL_CHAT': JSON.stringify('introduce-yourself-7010'),
|
||||
|
@ -73,6 +73,8 @@ module.exports = {
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.LANDSCAPE_STREAM': JSON.stringify(process.env.LANDSCAPE_STREAM),
|
||||
'process.env.LANDSCAPE_SHORTHASH': JSON.stringify(GIT_DESC),
|
||||
'process.env.LANDSCAPE_STORAGE_VERSION': Date.now().toString(),
|
||||
'process.env.LANDSCAPE_LAST_WIPE': '2021-10-20',
|
||||
'process.env.TUTORIAL_HOST': JSON.stringify('~difmex-passed'),
|
||||
'process.env.TUTORIAL_GROUP': JSON.stringify('beginner-island'),
|
||||
'process.env.TUTORIAL_CHAT': JSON.stringify('introduce-yourself-7010'),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import './register-sw';
|
||||
import './storage-wipe';
|
||||
import App from './views/App';
|
||||
import './wdyr';
|
||||
|
||||
|
@ -568,3 +568,14 @@ export function toHarkPlace(graph: string, index = '') {
|
||||
path: toHarkPath(graph, index)
|
||||
};
|
||||
}
|
||||
|
||||
export function createStorageKey(name: string): string {
|
||||
return `~${window.ship}/${window.desk}/${name}`;
|
||||
}
|
||||
|
||||
// for purging storage with version updates
|
||||
export function clearStorageMigration<T>() {
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
export const storageVersion = parseInt(process.env.LANDSCAPE_STORAGE_VERSION, 10);
|
||||
|
@ -6,6 +6,7 @@ import { persist } from 'zustand/middleware';
|
||||
import Urbit, { SubscriptionRequestInterface, FatalError } from '@urbit/http-api';
|
||||
import { Poke } from '@urbit/api';
|
||||
import airlock from '~/logic/api';
|
||||
import { clearStorageMigration, createStorageKey, storageVersion } from '../lib/util';
|
||||
|
||||
setAutoFreeze(false);
|
||||
enablePatches();
|
||||
@ -73,9 +74,9 @@ export const optReduceState = <S, U>(
|
||||
export let stateStorageKeys: string[] = [];
|
||||
|
||||
export const stateStorageKey = (stateName: string) => {
|
||||
stateName = `Landscape${stateName}State-${process.env.LANDSCAPE_SHORTHASH}`;
|
||||
stateStorageKeys = [...new Set([...stateStorageKeys, stateName])];
|
||||
return stateName;
|
||||
const key = createStorageKey(`${stateName}State`);
|
||||
stateStorageKeys = [...new Set([...stateStorageKeys, key])];
|
||||
return key;
|
||||
};
|
||||
|
||||
(window as any).clearStates = () => {
|
||||
@ -147,7 +148,9 @@ export const createState = <T extends {}>(
|
||||
...(typeof properties === 'function' ? (properties as any)(set, get) : properties)
|
||||
}), {
|
||||
blacklist,
|
||||
name: stateStorageKey(name)
|
||||
name: stateStorageKey(name),
|
||||
version: storageVersion,
|
||||
migrate: clearStorageMigration
|
||||
}));
|
||||
|
||||
export async function doOptimistically<A, S extends {}>(state: UseStore<S & BaseState<S>>, action: A, call: (a: A) => Promise<any>, reduce: ((a: A, fn: S & BaseState<S>) => S & BaseState<S>)[]) {
|
||||
|
@ -6,7 +6,7 @@ import { persist } from 'zustand/middleware';
|
||||
import { BackgroundConfig, LeapCategories, RemoteContentPolicy, TutorialProgress, tutorialProgress } from '~/types/local-update';
|
||||
import airlock from '~/logic/api';
|
||||
import { bootstrapApi } from '../api/bootstrap';
|
||||
import { wait } from '~/logic/lib/util';
|
||||
import { clearStorageMigration, createStorageKey, storageVersion, wait } from '~/logic/lib/util';
|
||||
|
||||
export type SubscriptionStatus = 'connected' | 'disconnected' | 'reconnecting';
|
||||
|
||||
@ -136,7 +136,9 @@ const useLocalState = create<LocalStateZus>(persist((set, get) => ({
|
||||
'prevTutStep', 'nextTutStep', 'tutorialRef', 'setTutorialRef', 'subscription',
|
||||
'errorCount', 'breaks'
|
||||
],
|
||||
name: 'localReducer'
|
||||
name: createStorageKey('local'),
|
||||
version: storageVersion,
|
||||
migrate: clearStorageMigration
|
||||
}));
|
||||
|
||||
function withLocalState<P, S extends keyof LocalState, C extends React.ComponentType<P>>(Component: C, stateMemberKeys?: S[]) {
|
||||
|
12
pkg/interface/src/storage-wipe.ts
Normal file
12
pkg/interface/src/storage-wipe.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { createStorageKey } from './logic/lib/util';
|
||||
|
||||
const key = createStorageKey(`storage-wipe-${process.env.LANDSCAPE_LAST_WIPE}`);
|
||||
const wiped = localStorage.getItem(key);
|
||||
|
||||
// Loaded before everything, this clears local storage just once.
|
||||
// Change VITE_LAST_WIPE in .env to date of wipe
|
||||
|
||||
if (!wiped) {
|
||||
localStorage.clear();
|
||||
localStorage.setItem(key, 'true');
|
||||
}
|
@ -3,5 +3,6 @@ import { PatpNoSig } from '@urbit/api';
|
||||
declare global {
|
||||
interface Window {
|
||||
ship: PatpNoSig;
|
||||
desk: string;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import React, { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import create from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useFileUpload } from '~/logic/lib/useFileUpload';
|
||||
import { createStorageKey, storageVersion, clearStorageMigration } from '~/logic/lib/util';
|
||||
import { useOurContact } from '~/logic/state/contact';
|
||||
import { useGraphTimesent } from '~/logic/state/graph';
|
||||
import ShareProfile from '~/views/apps/chat/components/ShareProfile';
|
||||
@ -21,7 +22,6 @@ interface useChatStoreType {
|
||||
setMessage: (message: string) => void;
|
||||
}
|
||||
|
||||
const unsentKey = 'chat-unsent';
|
||||
export const useChatStore = create<useChatStoreType>(persist((set, get) => ({
|
||||
id: '',
|
||||
message: '',
|
||||
@ -41,8 +41,10 @@ export const useChatStore = create<useChatStoreType>(persist((set, get) => ({
|
||||
set({ message, messageStore: store });
|
||||
}
|
||||
}), {
|
||||
name: unsentKey,
|
||||
whitelist: ['messageStore']
|
||||
whitelist: ['messageStore'],
|
||||
name: createStorageKey('chat-unsent'),
|
||||
version: storageVersion,
|
||||
migrate: clearStorageMigration
|
||||
}));
|
||||
|
||||
interface ChatPaneProps {
|
||||
|
Loading…
Reference in New Issue
Block a user