chore: move all components into Components dir with pascal case (#934)

This commit is contained in:
Mo
2022-03-17 11:38:45 -05:00
committed by GitHub
parent 42b84ef9b1
commit c29e45795d
89 changed files with 370 additions and 259 deletions

View File

@@ -0,0 +1,75 @@
import { displayStringForContentType, SNComponent } from '@standardnotes/snjs';
import { Button } from '@/components/Button';
import { FunctionComponent } from 'preact';
import { Title, Text, Subtitle, PreferencesSegment } from '../../components';
export const ConfirmCustomExtension: FunctionComponent<{
component: SNComponent;
callback: (confirmed: boolean) => void;
}> = ({ component, callback }) => {
const fields = [
{
label: 'Name',
value: component.package_info.name,
},
{
label: 'Description',
value: component.package_info.description,
},
{
label: 'Version',
value: component.package_info.version,
},
{
label: 'Hosted URL',
value: component.thirdPartyPackageInfo.url,
},
{
label: 'Download URL',
value: component.package_info.download_url,
},
{
label: 'Extension Type',
value: displayStringForContentType(component.content_type),
},
];
return (
<PreferencesSegment>
<Title>Confirm Extension</Title>
{fields.map((field) => {
if (!field.value) {
return undefined;
}
return (
<>
<Subtitle>{field.label}</Subtitle>
<Text className={'wrap'}>{field.value}</Text>
<div className="min-h-2" />
</>
);
})}
<div className="min-h-3" />
<div className="flex flex-row">
<Button
className="min-w-20"
type="normal"
label="Cancel"
onClick={() => callback(false)}
/>
<div className="min-w-3" />
<Button
className="min-w-20"
type="normal"
label="Install"
onClick={() => callback(true)}
/>
</div>
</PreferencesSegment>
);
};

View File

@@ -0,0 +1,115 @@
import { FunctionComponent } from 'preact';
import { SNComponent } from '@standardnotes/snjs';
import {
PreferencesSegment,
SubtitleLight,
Title,
} from '@/components/Preferences/components';
import { Switch } from '@/components/Switch';
import { WebApplication } from '@/ui_models/application';
import { useState } from 'preact/hooks';
import { Button } from '@/components/Button';
import { RenameExtension } from './RenameExtension';
const UseHosted: FunctionComponent<{
offlineOnly: boolean;
toggleOfllineOnly: () => void;
}> = ({ offlineOnly, toggleOfllineOnly }) => (
<div className="flex flex-row">
<SubtitleLight className="flex-grow">
Use hosted when local is unavailable
</SubtitleLight>
<Switch onChange={toggleOfllineOnly} checked={!offlineOnly} />
</div>
);
export interface ExtensionItemProps {
application: WebApplication;
extension: SNComponent;
first: boolean;
latestVersion: string | undefined;
uninstall: (extension: SNComponent) => void;
toggleActivate?: (extension: SNComponent) => void;
}
export const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({
application,
extension,
first,
uninstall,
}) => {
const [offlineOnly, setOfflineOnly] = useState(
extension.offlineOnly ?? false
);
const [extensionName, setExtensionName] = useState(extension.name);
const toggleOffllineOnly = () => {
const newOfflineOnly = !offlineOnly;
setOfflineOnly(newOfflineOnly);
application
.changeAndSaveItem(extension.uuid, (m: any) => {
if (m.content == undefined) m.content = {};
m.content.offlineOnly = newOfflineOnly;
})
.then((item) => {
const component = item as SNComponent;
setOfflineOnly(component.offlineOnly);
})
.catch((e) => {
console.error(e);
});
};
const changeExtensionName = (newName: string) => {
setExtensionName(newName);
application
.changeAndSaveItem(extension.uuid, (m: any) => {
if (m.content == undefined) m.content = {};
m.content.name = newName;
})
.then((item) => {
const component = item as SNComponent;
setExtensionName(component.name);
});
};
const localInstallable = extension.package_info.download_url;
const isThirParty = application.features.isThirdPartyFeature(
extension.identifier
);
return (
<PreferencesSegment classes={'mb-5'}>
{first && (
<>
<Title>Extensions</Title>
</>
)}
<RenameExtension
extensionName={extensionName}
changeName={changeExtensionName}
/>
<div className="min-h-2" />
{isThirParty && localInstallable && (
<UseHosted
offlineOnly={offlineOnly}
toggleOfllineOnly={toggleOffllineOnly}
/>
)}
<>
<div className="min-h-2" />
<div className="flex flex-row">
<Button
className="min-w-20"
type="normal"
label="Uninstall"
onClick={() => uninstall(extension)}
/>
</div>
</>
</PreferencesSegment>
);
};

View File

@@ -0,0 +1,52 @@
import { WebApplication } from '@/ui_models/application';
import { FeatureDescription } from '@standardnotes/features';
import { SNComponent, ClientDisplayableError } from '@standardnotes/snjs';
import { makeAutoObservable, observable } from 'mobx';
export class ExtensionsLatestVersions {
static async load(
application: WebApplication
): Promise<ExtensionsLatestVersions | undefined> {
const response = await application.getAvailableSubscriptions();
if (response instanceof ClientDisplayableError) {
return undefined;
}
const versionMap: Map<string, string> = new Map();
collectFeatures(
response.CORE_PLAN?.features as FeatureDescription[],
versionMap
);
collectFeatures(
response.PLUS_PLAN?.features as FeatureDescription[],
versionMap
);
collectFeatures(
response.PRO_PLAN?.features as FeatureDescription[],
versionMap
);
return new ExtensionsLatestVersions(versionMap);
}
constructor(private readonly latestVersionsMap: Map<string, string>) {
makeAutoObservable<ExtensionsLatestVersions, 'latestVersionsMap'>(this, {
latestVersionsMap: observable.ref,
});
}
getVersion(extension: SNComponent): string | undefined {
return this.latestVersionsMap.get(extension.package_info.identifier);
}
}
function collectFeatures(
features: FeatureDescription[] | undefined,
versionMap: Map<string, string>
) {
if (features == undefined) return;
for (const feature of features) {
versionMap.set(feature.identifier, feature.version!);
}
}

View File

@@ -0,0 +1,69 @@
import { FunctionComponent } from 'preact';
import { useState, useRef, useEffect } from 'preact/hooks';
export const RenameExtension: FunctionComponent<{
extensionName: string;
changeName: (newName: string) => void;
}> = ({ extensionName, changeName }) => {
const [isRenaming, setIsRenaming] = useState(false);
const [newExtensionName, setNewExtensionName] =
useState<string>(extensionName);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (isRenaming) {
inputRef.current!.focus();
}
}, [inputRef, isRenaming]);
const startRenaming = () => {
setNewExtensionName(extensionName);
setIsRenaming(true);
};
const cancelRename = () => {
setNewExtensionName(extensionName);
setIsRenaming(false);
};
const confirmRename = () => {
if (!newExtensionName) {
return;
}
changeName(newExtensionName);
setIsRenaming(false);
};
return (
<div className="flex flex-row mr-3 items-center">
<input
ref={inputRef}
disabled={!isRenaming}
autocomplete="off"
className="flex-grow text-base font-bold no-border bg-default px-0 color-text"
type="text"
value={newExtensionName}
onChange={({ target: input }) =>
setNewExtensionName((input as HTMLInputElement)?.value)
}
/>
<div className="min-w-3" />
{isRenaming ? (
<>
<a className="pt-1 cursor-pointer" onClick={confirmRename}>
Confirm
</a>
<div className="min-w-3" />
<a className="pt-1 cursor-pointer" onClick={cancelRename}>
Cancel
</a>
</>
) : (
<a className="pt-1 cursor-pointer" onClick={startRenaming}>
Rename
</a>
)}
</div>
);
};

View File

@@ -0,0 +1,3 @@
export * from './ConfirmCustomExtension';
export * from './ExtensionItem';
export * from './ExtensionsLatestVersions';