|
|
|
@ -1,13 +1,14 @@
|
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
|
|
|
import React, { memo, useState, useEffect } from 'react';
|
|
|
|
|
import { toPlural } from '@vizality/util/string';
|
|
|
|
|
import { FilterInput } from '@vizality/components';
|
|
|
|
|
import { toTitleCase, toSingular } from '@vizality/util/string';
|
|
|
|
|
import { useForceUpdate } from '@vizality/hooks';
|
|
|
|
|
import { contextMenu } from '@vizality/webpack';
|
|
|
|
|
import { error } from '@vizality/util/logger';
|
|
|
|
|
import { useFilter } from '@vizality/hooks';
|
|
|
|
|
import { Messages } from '@vizality/i18n';
|
|
|
|
|
|
|
|
|
|
import { ContextMenu, LazyImage, Button, Tooltip, TextBadge } from '..';
|
|
|
|
|
import { AddonContextMenu } from '../addon';
|
|
|
|
|
import { ContextMenu, LazyImage, TextBadge } from '..';
|
|
|
|
|
|
|
|
|
|
const { closeContextMenu } = contextMenu;
|
|
|
|
|
|
|
|
|
@ -31,8 +32,24 @@ const _error = (...message) => error({ labels: _labels, message });
|
|
|
|
|
*/
|
|
|
|
|
export default memo(() => {
|
|
|
|
|
const [ quickToggle, setQuickToggle ] = useState(false);
|
|
|
|
|
const [ quickToggleKeybind, setQuickToggleKeybind ] = useState(false);
|
|
|
|
|
const forceUpdate = useForceUpdate();
|
|
|
|
|
/**
|
|
|
|
|
* Creates a sorted array containing all installed plugins.
|
|
|
|
|
*/
|
|
|
|
|
const plugins = [ ...vizality.manager.plugins.values ];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a sorted array containing all installed themes.
|
|
|
|
|
*/
|
|
|
|
|
const themes = [ ...vizality.manager.themes.values ];
|
|
|
|
|
const [ pluginsQuery, setPluginsQuery, filteredPlugins ] = useFilter({
|
|
|
|
|
keys: [ 'manifest.name' ],
|
|
|
|
|
data: plugins
|
|
|
|
|
});
|
|
|
|
|
const [ themesQuery, setThemesQuery, filteredThemes ] = useFilter({
|
|
|
|
|
keys: [ 'manifest.name' ],
|
|
|
|
|
data: themes
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add some key event listeners on mount to allow users to hold shift to enter
|
|
|
|
@ -49,7 +66,6 @@ export default memo(() => {
|
|
|
|
|
*/
|
|
|
|
|
if (evt.keyCode === 16) {
|
|
|
|
|
setQuickToggle(true);
|
|
|
|
|
setQuickToggleKeybind(true);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -63,7 +79,6 @@ export default memo(() => {
|
|
|
|
|
*/
|
|
|
|
|
if (evt.keyCode === 16) {
|
|
|
|
|
setQuickToggle(false);
|
|
|
|
|
setQuickToggleKeybind(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -80,111 +95,15 @@ export default memo(() => {
|
|
|
|
|
}, [ quickToggle ]);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a sorted array containing all installed plugins.
|
|
|
|
|
*/
|
|
|
|
|
const plugins =
|
|
|
|
|
vizality.manager.plugins.keys
|
|
|
|
|
.sort((a, b) => a - b)
|
|
|
|
|
.map(plugin => vizality.manager.plugins.get(plugin));
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a sorted array containing all installed themes.
|
|
|
|
|
*/
|
|
|
|
|
const themes =
|
|
|
|
|
vizality.manager.themes.keys
|
|
|
|
|
.sort((a, b) => a - b)
|
|
|
|
|
.map(theme => vizality.manager.themes.get(theme));
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders a context menu item for an addon.
|
|
|
|
|
* @param {Addon#addonId} addonId Addon ID
|
|
|
|
|
* @param {AddonManifest#name} name Addon name
|
|
|
|
|
* @param {AddonManifest#icon} icon Addon icon
|
|
|
|
|
* @param {AddonType} type Addon type
|
|
|
|
|
*/
|
|
|
|
|
const renderContextItem = (addonId, name, icon, type) => {
|
|
|
|
|
const _AddonContextMenu = AddonContextMenu.type({ addonId, type }).props.children;
|
|
|
|
|
return (
|
|
|
|
|
quickToggle
|
|
|
|
|
? (
|
|
|
|
|
<ContextMenu.CheckboxItem
|
|
|
|
|
vz-addon-icon={icon}
|
|
|
|
|
id={addonId}
|
|
|
|
|
label={name}
|
|
|
|
|
checked={vizality.manager[toPlural(type)].isEnabled(addonId)}
|
|
|
|
|
action={async () => {
|
|
|
|
|
try {
|
|
|
|
|
vizality.manager[toPlural(type)].isEnabled(addonId)
|
|
|
|
|
? await vizality.manager[toPlural(type)].disable(addonId)
|
|
|
|
|
: await vizality.manager[toPlural(type)].enable(addonId);
|
|
|
|
|
forceUpdate();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
_error(err);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<LazyImage src={icon} />
|
|
|
|
|
</ContextMenu.CheckboxItem>
|
|
|
|
|
)
|
|
|
|
|
: (
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
vz-addon-icon={icon}
|
|
|
|
|
id={addonId}
|
|
|
|
|
label={name}
|
|
|
|
|
action={() => {
|
|
|
|
|
try {
|
|
|
|
|
if (vizality.manager[toPlural(type)].isCommunity(addonId)) {
|
|
|
|
|
return vizality.api.routes.navigateTo(`${toPlural(type)}/${addonId}`);
|
|
|
|
|
}
|
|
|
|
|
return vizality.api.routes.navigateTo(`${toPlural(type)}/local/${addonId}`);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
_error(err);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{_AddonContextMenu}
|
|
|
|
|
</ContextMenu.Item>
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders an array of addon context items.
|
|
|
|
|
* @param {Array<Addon>} addons Addons
|
|
|
|
|
* @param {AddonType} type Addon type
|
|
|
|
|
* @returns {Array<React.Component>}
|
|
|
|
|
* Handles updating the current search filter.
|
|
|
|
|
* @param {string} query Search query
|
|
|
|
|
* @param {('plugins|'themes')} type Addon type
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const renderAddonItems = (addons, type) => {
|
|
|
|
|
return addons.map(addon => renderContextItem(addon.addonId, addon.manifest.name, addon.manifest.icon, type));
|
|
|
|
|
const handleQueryChange = (query, type) => {
|
|
|
|
|
eval(`set${toTitleCase(type)}Query`)(typeof query === 'string' ? query : '');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders a group of addon context items.
|
|
|
|
|
* @param {Array<Addon>} addons Addons
|
|
|
|
|
* @param {AddonType} type Addon type
|
|
|
|
|
* @returns {React.Component}
|
|
|
|
|
*/
|
|
|
|
|
const renderAddonGroup = (addons, type) => (
|
|
|
|
|
<ContextMenu.Group
|
|
|
|
|
id='quick-toggle'
|
|
|
|
|
className='vz-settings-context-menu-quick-toggle'
|
|
|
|
|
label={
|
|
|
|
|
<Tooltip text='Or you can just hold shift!'>
|
|
|
|
|
<Button
|
|
|
|
|
disabled={quickToggleKeybind}
|
|
|
|
|
onClick={() => setQuickToggle(!quickToggle)}
|
|
|
|
|
size={Button.Sizes.SMALL}
|
|
|
|
|
color={quickToggle && !quickToggleKeybind ? Button.Colors.RED : Button.Colors.BRAND}
|
|
|
|
|
>
|
|
|
|
|
{quickToggle && !quickToggleKeybind ? 'Disable' : 'Enable'} Quick Toggle Mode
|
|
|
|
|
</Button>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{renderAddonItems(addons, type)}
|
|
|
|
|
</ContextMenu.Group>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ContextMenu.Menu navId='vizality-dashboard' onClose={closeContextMenu}>
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
@ -236,20 +155,147 @@ export default memo(() => {
|
|
|
|
|
action={() => vizality.api.routes.navigateTo('settings/advanced')}
|
|
|
|
|
/>
|
|
|
|
|
</ContextMenu.Item>
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='plugins'
|
|
|
|
|
label='Plugins'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo('plugins')}
|
|
|
|
|
>
|
|
|
|
|
{plugins.length && renderAddonGroup(plugins, 'plugin')}
|
|
|
|
|
</ContextMenu.Item>
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='themes'
|
|
|
|
|
label='Themes'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo('themes')}
|
|
|
|
|
>
|
|
|
|
|
{themes.length && renderAddonGroup(themes, 'theme')}
|
|
|
|
|
</ContextMenu.Item>
|
|
|
|
|
{[ plugins, themes ].map((_, index) => {
|
|
|
|
|
const type = index === 0 ? 'plugins' : 'themes';
|
|
|
|
|
return (
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id={type}
|
|
|
|
|
label={toTitleCase(type)}
|
|
|
|
|
action={() => vizality.api.routes.navigateTo(type)}
|
|
|
|
|
>
|
|
|
|
|
<ContextMenu.Group
|
|
|
|
|
id='search'
|
|
|
|
|
className='vz-settings-context-menu-search'
|
|
|
|
|
label={
|
|
|
|
|
<FilterInput
|
|
|
|
|
value={eval(`${type}Query`)}
|
|
|
|
|
onChange={query => handleQueryChange(query, type)}
|
|
|
|
|
autoFocus
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<ContextMenu.Separator />
|
|
|
|
|
{eval(`filtered${toTitleCase(type)}`).map(addon => {
|
|
|
|
|
const isEnabled = vizality.manager[type].isEnabled(addon.addonId);
|
|
|
|
|
const isInstalled = vizality.manager[type].isInstalled(addon.addonId);
|
|
|
|
|
const hasSettings = vizality.manager[type].hasSettings(addon.addonId);
|
|
|
|
|
const hasScreenshots = vizality.manager[type].hasScreenshots(addon.addonId);
|
|
|
|
|
const hasChangelog = vizality.manager[type].hasChangelog(addon.addonId);
|
|
|
|
|
return (
|
|
|
|
|
quickToggle
|
|
|
|
|
? (
|
|
|
|
|
<ContextMenu.CheckboxItem
|
|
|
|
|
vz-addon-icon={addon.manifest.icon}
|
|
|
|
|
vz-addon-type={toSingular(type)}
|
|
|
|
|
id={addon.addonId}
|
|
|
|
|
label={addon.manifest.name}
|
|
|
|
|
checked={vizality.manager[type].isEnabled(addon.addonId)}
|
|
|
|
|
action={async () => {
|
|
|
|
|
try {
|
|
|
|
|
vizality.manager[type].isEnabled(addon.addonId)
|
|
|
|
|
? await vizality.manager[type].disable(addon.addonId)
|
|
|
|
|
: await vizality.manager[type].enable(addon.addonId);
|
|
|
|
|
forceUpdate();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
_error(err);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<LazyImage src={addon.manifest.icon} />
|
|
|
|
|
</ContextMenu.CheckboxItem>
|
|
|
|
|
)
|
|
|
|
|
: (
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
vz-addon-icon={addon.manifest.icon}
|
|
|
|
|
id={addon.addonId}
|
|
|
|
|
label={addon.manifest.name}
|
|
|
|
|
action={() => {
|
|
|
|
|
try {
|
|
|
|
|
return vizality.api.routes.navigateTo(`/vizality/${toSingular(type)}/${addon.addonId}`);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
_error(err);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='overview'
|
|
|
|
|
label='Overview'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo(`/vizality/${toSingular(type)}/${addon.addonId}`)}
|
|
|
|
|
/>
|
|
|
|
|
{hasScreenshots && (
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='screenshots'
|
|
|
|
|
label='Screenshots'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo(`/vizality/${toSingular(type)}/${addon.addonId}/screenshots`)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{isInstalled && hasSettings && (
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='settings'
|
|
|
|
|
label='Settings'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo(`/vizality/${toSingular(type)}/${addon.addonId}/settings`)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='reviews'
|
|
|
|
|
label='Reviews'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo(`/vizality/${toSingular(type)}/${addon.addonId}/reviews`)}
|
|
|
|
|
disabled
|
|
|
|
|
/>
|
|
|
|
|
{hasChangelog && (
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='changelog'
|
|
|
|
|
label='Changelog'
|
|
|
|
|
action={() => vizality.api.routes.navigateTo(`/vizality/${toSingular(type)}/${addon.addonId}/changelog`)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
<ContextMenu.Separator />
|
|
|
|
|
{isInstalled && (
|
|
|
|
|
isEnabled
|
|
|
|
|
? <ContextMenu.Item
|
|
|
|
|
id='disable'
|
|
|
|
|
label='Disable'
|
|
|
|
|
action={async () => vizality.manager[type].disable(addon.addonId)}
|
|
|
|
|
/>
|
|
|
|
|
: <ContextMenu.Item
|
|
|
|
|
id='enable'
|
|
|
|
|
label='Enable'
|
|
|
|
|
action={async () => vizality.manager[type].enable(addon.addonId)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{isInstalled
|
|
|
|
|
? <ContextMenu.Item
|
|
|
|
|
id='uninstall'
|
|
|
|
|
label='Uninstall'
|
|
|
|
|
color={ContextMenu.Item.Colors.DANGER}
|
|
|
|
|
action={async () => vizality.manager[type].uninstall(addon.addonId)}
|
|
|
|
|
/>
|
|
|
|
|
: <ContextMenu.Item
|
|
|
|
|
id='install'
|
|
|
|
|
label='Install'
|
|
|
|
|
color={ContextMenu.Item.Colors.GREEN}
|
|
|
|
|
action={async () => vizality.manager[type].install(addon.addonId)}
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
<ContextMenu.Separator />
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='copy-link'
|
|
|
|
|
label='Copy Link'
|
|
|
|
|
action={() => void 0}
|
|
|
|
|
/>
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='copy-id'
|
|
|
|
|
label='Copy ID'
|
|
|
|
|
action={() => DiscordNative.clipboard.copy(addon.addonId)}
|
|
|
|
|
/>
|
|
|
|
|
</ContextMenu.Item>
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</ContextMenu.Group>
|
|
|
|
|
</ContextMenu.Item>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
<ContextMenu.Item
|
|
|
|
|
id='snippets'
|
|
|
|
|
label='Snippets'
|
|
|
|
|