Skip to content

Commit

Permalink
feat: add migration pref pane (#825)
Browse files Browse the repository at this point in the history
* feat: add migration pane

* style: clean imports

* removeme: beta version

* fix: do no show dropzone when tag has no parent

* fix: hide the Folders toggle

* fix: hide migrations option when user has no folders

* fix: add delimiter on Folders mark

* removeme: bump beta

* fix: remove component viewer for tag folders

* removeme: bump beta

* chore(deps): snjs
  • Loading branch information
laurentsenta committed Feb 1, 2022
1 parent ed729ab commit 3c0bc79
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 145 deletions.
64 changes: 22 additions & 42 deletions app/assets/javascripts/components/Navigation.tsx
@@ -1,18 +1,11 @@
import { ComponentView } from '@/components/ComponentView';
import { SmartTagsSection } from '@/components/Tags/SmartTagsSection';
import { TagsSection } from '@/components/Tags/TagsSection';
import { WebApplication } from '@/ui_models/application';
import { PANEL_NAME_NAVIGATION } from '@/views/constants';
import { ApplicationEvent, PrefKey } from '@standardnotes/snjs';
import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'preact/hooks';
import { useCallback, useEffect, useMemo, useState } from 'preact/hooks';
import { PremiumModalProvider } from './Premium';
import {
PanelSide,
Expand All @@ -28,7 +21,6 @@ type Props = {
export const Navigation: FunctionComponent<Props> = observer(
({ application }) => {
const appState = useMemo(() => application.getAppState(), [application]);
const componentViewer = appState.foldersComponentViewer;
const enableNativeSmartTagsFeature =
appState.features.enableNativeSmartTagsFeature;
const [ref, setRef] = useState<HTMLDivElement | null>();
Expand Down Expand Up @@ -72,42 +64,30 @@ export const Navigation: FunctionComponent<Props> = observer(
data-aria-label="Navigation"
ref={setRef}
>
{componentViewer ? (
<div className="component-view-container">
<div className="component-view">
<ComponentView
componentViewer={componentViewer}
application={application}
appState={appState}
/>
</div>
</div>
) : (
<div id="navigation-content" className="content">
<div className="section-title-bar">
<div className="section-title-bar-header">
<div className="sk-h3 title">
<span className="sk-bold">Views</span>
</div>
{!enableNativeSmartTagsFeature && (
<div
className="sk-button sk-secondary-contrast wide"
onClick={onCreateNewTag}
title="Create a new tag"
>
<div className="sk-label">
<i className="icon ion-plus add-button" />
</div>
</div>
)}
<div id="navigation-content" className="content">
<div className="section-title-bar">
<div className="section-title-bar-header">
<div className="sk-h3 title">
<span className="sk-bold">Views</span>
</div>
</div>
<div className="scrollable">
<SmartTagsSection appState={appState} />
<TagsSection appState={appState} />
{!enableNativeSmartTagsFeature && (
<div
className="sk-button sk-secondary-contrast wide"
onClick={onCreateNewTag}
title="Create a new tag"
>
<div className="sk-label">
<i className="icon ion-plus add-button" />
</div>
</div>
)}
</div>
</div>
)}
<div className="scrollable">
<SmartTagsSection appState={appState} />
<TagsSection appState={appState} />
</div>
</div>
{ref && (
<PanelResizer
collapsable={true}
Expand Down
Expand Up @@ -8,6 +8,7 @@ import {
import {
ComponentArea,
ContentType,
FeatureIdentifier,
SNComponent,
SNTheme,
} from '@standardnotes/snjs';
Expand Down Expand Up @@ -107,10 +108,11 @@ export const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
const reloadToggleableComponents = useCallback(() => {
const toggleableComponents = (
application.getDisplayableItems(ContentType.Component) as SNComponent[]
).filter((component) =>
[ComponentArea.EditorStack, ComponentArea.TagsList].includes(
component.area
)
).filter(
(component) =>
[ComponentArea.EditorStack, ComponentArea.TagsList].includes(
component.area
) && component.identifier !== FeatureIdentifier.FoldersComponent
);
setToggleableComponents(toggleableComponents);
}, [application]);
Expand Down
9 changes: 3 additions & 6 deletions app/assets/javascripts/components/Tags/RootTagDropZone.tsx
@@ -1,9 +1,6 @@
import { Icon } from '@/components/Icon';
import { usePremiumModal } from '@/components/Premium';
import {
FeaturesState,
TAG_FOLDERS_FEATURE_NAME,
} from '@/ui_models/app_state/features_state';
import { FeaturesState } from '@/ui_models/app_state/features_state';
import { TagsState } from '@/ui_models/app_state/tags_state';
import { observer } from 'mobx-react-lite';
import { useDrop } from 'react-dnd';
Expand All @@ -22,8 +19,8 @@ export const RootTagDropZone: React.FC<Props> = observer(
const [{ isOver, canDrop }, dropRef] = useDrop<DropItem, void, DropProps>(
() => ({
accept: ItemTypes.TAG,
canDrop: () => {
return true;
canDrop: (item) => {
return tagsState.hasParent(item.uuid);
},
drop: (item) => {
tagsState.assignParent(item.uuid, undefined);
Expand Down
Expand Up @@ -52,7 +52,7 @@ export const TagsSectionTitle: FunctionComponent<Props> = observer(
className="ml-1 sk-bold color-grey-2 cursor-pointer"
onClick={showPremiumAlert}
>
Folders
&middot; Folders
</label>
</Tooltip>
</div>
Expand Down
41 changes: 23 additions & 18 deletions app/assets/javascripts/components/menu/MenuItem.tsx
Expand Up @@ -91,22 +91,27 @@ type ListElementProps = {
};

export const MenuItemListElement: FunctionComponent<ListElementProps> =
forwardRef(({ children, isFirstMenuItem }: ListElementProps, ref: Ref<HTMLLIElement>) => {
const child = children as VNode<unknown>;
forwardRef(
(
{ children, isFirstMenuItem }: ListElementProps,
ref: Ref<HTMLLIElement>
) => {
const child = children as VNode<unknown>;

return (
<li className="list-style-none" role="none" ref={ref}>
{{
...child,
props: {
...(child.props ? { ...child.props } : {}),
...(child.type === MenuItem
? {
tabIndex: isFirstMenuItem ? 0 : -1,
}
: {}),
},
}}
</li>
);
});
return (
<li className="list-style-none" role="none" ref={ref}>
{{
...child,
props: {
...(child.props ? { ...child.props } : {}),
...(child.type === MenuItem
? {
tabIndex: isFirstMenuItem ? 0 : -1,
}
: {}),
},
}}
</li>
);
}
);
4 changes: 3 additions & 1 deletion app/assets/javascripts/preferences/components/MenuItem.tsx
Expand Up @@ -16,7 +16,9 @@ export const MenuItem: FunctionComponent<Props> = ({
onClick,
}) => (
<div
className={`preferences-menu-item select-none ${selected ? 'selected' : ''}`}
className={`preferences-menu-item select-none ${
selected ? 'selected' : ''
}`}
onClick={(e) => {
e.preventDefault();
onClick();
Expand Down
16 changes: 9 additions & 7 deletions app/assets/javascripts/preferences/panes/General.tsx
Expand Up @@ -6,24 +6,26 @@ import { ErrorReporting, Tools, Defaults } from './general-segments';
import { ExtensionsLatestVersions } from '@/preferences/panes/extensions-segments';
import { Advanced } from '@/preferences/panes/account';
import { observer } from 'mobx-react-lite';
import { Migrations } from './general-segments/Migrations';

interface GeneralProps {
appState: AppState;
application: WebApplication;
extensionsLatestVersions: ExtensionsLatestVersions,
extensionsLatestVersions: ExtensionsLatestVersions;
}

export const General: FunctionComponent<GeneralProps> = observer(
({
appState,
application,
extensionsLatestVersions
}) => (
({ appState, application, extensionsLatestVersions }) => (
<PreferencesPane>
<Tools application={application} />
<Defaults application={application} />
<ErrorReporting appState={appState} />
<Advanced application={application} appState={appState} extensionsLatestVersions={extensionsLatestVersions} />
<Migrations application={application} appState={appState} />
<Advanced
application={application}
appState={appState}
extensionsLatestVersions={extensionsLatestVersions}
/>
</PreferencesPane>
)
);
@@ -0,0 +1,103 @@
import { Button } from '@/components/Button';
import { Icon } from '@/components/Icon';
import { WebApplication } from '@/ui_models/application';
import { AppState } from '@/ui_models/app_state';
import { FunctionComponent } from 'preact';
import { useCallback, useState } from 'preact/hooks';
import {
PreferencesGroup,
PreferencesSegment,
Subtitle,
Text,
Title,
} from '../../components';

type Props = {
application: WebApplication;
appState: AppState;
};

export const CheckIcon: React.FC = () => {
return <Icon className="success min-w-4 min-h-4" type="check-bold" />;
};

const Migration3dot0dot0: FunctionComponent<Props> = ({ application }) => {
const [loading, setLoading] = useState(false);
const [complete, setComplete] = useState(false);
const [error, setError] = useState<unknown | null>(null);

const trigger = useCallback(() => {
setLoading(true);
setError(null);
setComplete(false);
application
.migrateTagDotsToHierarchy()
.then(() => {
setLoading(false);
setError(null);
setComplete(true);
})
.catch((error: unknown) => {
setLoading(false);
setError(error);
setComplete(false);
});
}, [application, setLoading, setError]);

return (
<>
<Subtitle>(3.0.0) Folders Component to Native Folders</Subtitle>
<Text>
This migration transform tags with "." in their title into a hierarchy
of parents. This lets your transform tag hierarchies created with the
folder component into native tag folders.
</Text>
<div className="flex flex-row items-center mt-3">
<Button
type="normal"
onClick={trigger}
className="m-2"
disabled={loading}
label="Run Now"
/>
{complete && (
<div className="ml-3">
<Text>Migration successful.</Text>
</div>
)}
{error && (
<div className="ml-3">
<Text>Something wrong happened. Please contact support.</Text>
</div>
)}
</div>
</>
);
};

export const Migrations: FunctionComponent<Props> = ({
application,
appState,
}) => {
const hasNativeFoldersEnabled = appState.features.enableNativeFoldersFeature;

if (!hasNativeFoldersEnabled) {
return null;
}

const hasFoldersFeature = appState.features.hasFolders;

if (!hasFoldersFeature) {
return null;
}

return (
<PreferencesGroup>
<PreferencesSegment>
<Title>Migrations</Title>
<div className="h-2 w-full" />
<Migration3dot0dot0 application={application} appState={appState} />
</PreferencesSegment>
</PreferencesGroup>
);
};

0 comments on commit 3c0bc79

Please sign in to comment.