mirror of https://github.com/vizality/vizality
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
12 KiB
357 lines
12 KiB
import { SwitchItem, TextInput, Category, FormTitle } from '@vizality/components/settings';
|
|
import { Confirm, Button, FormNotice } from '@vizality/components';
|
|
import { openModal, closeModal } from '@vizality/modal';
|
|
import { Repositories } from '@vizality/constants';
|
|
import React, { useEffect, memo } from 'react';
|
|
import { Messages } from '@vizality/i18n';
|
|
import { joinClassNames } from '@vizality/util/dom';
|
|
import { getModule } from '@vizality/webpack';
|
|
import moment from 'moment';
|
|
|
|
import Update from './Update';
|
|
import Icons from './Icons';
|
|
|
|
export default memo(({ getSetting, toggleSetting, updateSetting }) => {
|
|
useEffect(() => {
|
|
const updateToasts = [
|
|
'vizality-updater-update-complete',
|
|
'vizality-updater-update-available'
|
|
];
|
|
updateToasts.forEach(t => vizality.api.notifications.closeToast(t));
|
|
});
|
|
|
|
// eslint-disable-next-line consistent-this
|
|
const _this = vizality.manager.builtins.get('updater');
|
|
// @todo: Make this be in its own store
|
|
const awaitingReload = getSetting('awaitingReload', false);
|
|
const updating = getSetting('updating', false);
|
|
const checking = getSetting('checking', false);
|
|
const disabled = getSetting('disabled', false);
|
|
const paused = getSetting('paused', false);
|
|
const failed = getSetting('failed', false);
|
|
|
|
const updates = getSetting('updates', []);
|
|
const disabledAddons = getSetting('addonsDisabled', []);
|
|
const checkingProgress = getSetting('checkingProgress', [ 0, 0 ]);
|
|
const last = moment(getSetting('lastCheck', false)).calendar();
|
|
|
|
let icon, title;
|
|
if (disabled) {
|
|
icon = <Icons.Update color='#f04747'/>;
|
|
title = Messages.VIZALITY_UPDATES_DISABLED;
|
|
} else if (paused) {
|
|
icon = <Icons.Paused/>;
|
|
title = Messages.VIZALITY_UPDATES_PAUSED;
|
|
} else if (checking) {
|
|
icon = <Icons.Update color='#7289da' animated/>;
|
|
title = Messages.VIZALITY_UPDATES_CHECKING;
|
|
} else if (updating) {
|
|
icon = <Icons.Update color='#7289da' animated/>;
|
|
title = Messages.VIZALITY_UPDATES_UPDATING;
|
|
} else if (failed) {
|
|
icon = <Icons.Error/>;
|
|
title = Messages.VIZALITY_UPDATES_FAILED;
|
|
} else if (updates.length > 0) {
|
|
icon = <Icons.Update/>;
|
|
title = Messages.VIZALITY_UPDATES_AVAILABLE;
|
|
} else {
|
|
icon = <Icons.UpToDate/>;
|
|
title = Messages.VIZALITY_UPDATES_UP_TO_DATE;
|
|
}
|
|
|
|
/**
|
|
* Gets a valid interval value in minutes based on user's input.
|
|
* @param {number} minutes Interval value
|
|
* @returns {void}
|
|
*/
|
|
const _getValidInterval = minutes => {
|
|
if (Number(minutes)) {
|
|
if (Number(minutes) >= 10) {
|
|
/**
|
|
* This is to make sure the user doesn't input a value that goes over setInterval's
|
|
* max of 2,147,483,647, because if this happens, it will trigger the updates immediately
|
|
* and infinitely, using max computer resources and freezing the app.
|
|
*/
|
|
if (Number(minutes) >= 34000) {
|
|
return 34000;
|
|
}
|
|
return Math.ceil(Number(minutes));
|
|
}
|
|
/**
|
|
* If it's set to less than 10, set it to 10.
|
|
*/
|
|
return 10;
|
|
}
|
|
/**
|
|
* If all else fails, set it to the default 15 minutes.
|
|
*/
|
|
return 15;
|
|
};
|
|
|
|
/**
|
|
* Gets a valid concurrency limit based on user's input.
|
|
* @param {number} limit Concurrency limit
|
|
* @returns {void}
|
|
*/
|
|
const _getValidConcurrency = limit => {
|
|
if (Number(limit)) {
|
|
if (Number(limit) >= 1) {
|
|
return Math.ceil(Number(limit));
|
|
}
|
|
/**
|
|
* If it's set to less than 1, set it to 1.
|
|
*/
|
|
return 1;
|
|
}
|
|
/**
|
|
* If all else fails, set it to the default 2 concurrency limit.
|
|
*/
|
|
return 2;
|
|
};
|
|
|
|
const _renderFormNotice = (title, body) => {
|
|
const { marginBottom20 } = getModule('marginBottom20');
|
|
return <FormNotice
|
|
className={joinClassNames('vz-updater-form-notice', marginBottom20)}
|
|
imageData={{
|
|
width: 60,
|
|
height: 60,
|
|
src: '/assets/0694f38cb0b10cc3b5b89366a0893768.svg'
|
|
}}
|
|
type={FormNotice.Types.WARNING}
|
|
title={title}
|
|
body={body}
|
|
/>;
|
|
};
|
|
|
|
// --- PARTS
|
|
const renderReload = () => {
|
|
const body = <>
|
|
<p>{Messages.VIZALITY_UPDATES_AWAITING_RELOAD_DESC}</p>
|
|
<Button
|
|
size={Button.Sizes.SMALL}
|
|
color={Button.Colors.YELLOW}
|
|
look={Button.Looks.INVERTED}
|
|
onClick={() => location.reload()}
|
|
>
|
|
{Messages.ERRORS_RELOAD}
|
|
</Button>
|
|
</>;
|
|
return _renderFormNotice(Messages.VIZALITY_UPDATES_AWAITING_RELOAD_TITLE, body);
|
|
};
|
|
|
|
// @todo Add to modals AI
|
|
const _confirm = (title, content, confirm, callback) => {
|
|
const { colorStandard } = getModule('colorStandard');
|
|
const { spacing } = getModule('spacing', 'message');
|
|
const { size16 } = getModule('size16');
|
|
openModal(() => props => (
|
|
<Confirm
|
|
{...props}
|
|
header={title}
|
|
confirmText={confirm}
|
|
cancelText={Messages.CANCEL}
|
|
onConfirm={callback}
|
|
onCancel={closeModal}
|
|
>
|
|
<div className={joinClassNames(colorStandard, spacing, size16)}>
|
|
{content}
|
|
</div>
|
|
</Confirm>
|
|
));
|
|
};
|
|
|
|
// --- PROMPTS
|
|
const confirmSkipUpdate = callback => {
|
|
_confirm(
|
|
Messages.VIZALITY_UPDATES_SKIP_MODAL_TITLE,
|
|
Messages.VIZALITY_UPDATES_SKIP_MODAL,
|
|
Messages.VIZALITY_UPDATES_SKIP,
|
|
callback
|
|
);
|
|
};
|
|
|
|
const confirmPauseUpdates = () => {
|
|
_confirm(
|
|
Messages.VIZALITY_UPDATES_PAUSE,
|
|
Messages.VIZALITY_UPDATES_PAUSE_MODAL,
|
|
Messages.VIZALITY_UPDATES_PAUSE,
|
|
() => updateSetting('paused', true)
|
|
);
|
|
};
|
|
|
|
const confirmDisableUpdates = (all, callback) => {
|
|
_confirm(
|
|
Messages.VIZALITY_UPDATES_DISABLE,
|
|
all ? Messages.VIZALITY_UPDATES_DISABLE_MODAL_ALL : Messages.VIZALITY_UPDATES_DISABLE_MODAL,
|
|
Messages.VIZALITY_UPDATES_DISABLE,
|
|
callback
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{awaitingReload && renderReload()}
|
|
<div className='vz-updater-top-section'>
|
|
<div className='vz-updater-top-section-header'>
|
|
<div className='vz-updater-top-section-icon'>
|
|
{icon}
|
|
</div>
|
|
<div className='vz-updater-top-section-status'>
|
|
<h3 className='vz-updater-top-section-title'>
|
|
{title}
|
|
</h3>
|
|
{!disabled && !updating && (!checking || checkingProgress[1] > 0) && <div className='vz-updater-top-section-subtitle'>
|
|
{paused
|
|
? Messages.VIZALITY_UPDATES_PAUSED_RESUME
|
|
: checking
|
|
? Messages.VIZALITY_UPDATES_CHECKING_STATUS.format({
|
|
checked: checkingProgress[0],
|
|
total: checkingProgress[1]
|
|
})
|
|
: Messages.VIZALITY_UPDATES_LAST_CHECKED.format({ date: last })}
|
|
</div>}
|
|
</div>
|
|
<div className='vz-updater-top-section-about'>
|
|
<div className='vz-updater-top-section-about-column'>
|
|
<span className='vz-updater-top-section-about-title'>
|
|
{Messages.VIZALITY_UPDATES_UPSTREAM}
|
|
</span>
|
|
<span className='vz-updater-top-section-about-title'>
|
|
{Messages.VIZALITY_UPDATES_REVISION}
|
|
</span>
|
|
<span className='vz-updater-top-section-about-title'>
|
|
{Messages.VIZALITY_UPDATES_BRANCH}
|
|
</span>
|
|
</div>
|
|
<div className='vz-updater-top-section-about-column'>
|
|
<span className='vz-updater-top-section-about-value'>
|
|
{vizality.git.upstream.replace(Repositories.VIZALITY, Messages.VIZALITY_UPDATES_UPSTREAM_OFFICIAL)}
|
|
</span>
|
|
<span className='vz-updater-top-section-about-value'>
|
|
{vizality.git.revision.substring(0, 7)}
|
|
</span>
|
|
<span className='vz-updater-top-section-about-value'>
|
|
{vizality.git.branch}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className='vz-updater-top-section-footer'>
|
|
{disabled || paused
|
|
? <Button
|
|
size={Button.Sizes.SMALL}
|
|
color={Button.Colors.GREEN}
|
|
onClick={() => {
|
|
updateSetting('paused', false);
|
|
updateSetting('disabled', false);
|
|
}}
|
|
>
|
|
{disabled ? Messages.VIZALITY_UPDATES_ENABLE : Messages.VIZALITY_UPDATES_RESUME}
|
|
</Button>
|
|
: (!checking && !updating && <>
|
|
{updates.length > 0 && <Button
|
|
size={Button.Sizes.SMALL}
|
|
color={failed ? Button.Colors.RED : Button.Colors.GREEN}
|
|
onClick={() => failed ? _this.confirmForce() : _this.updateAll()}
|
|
>
|
|
{failed ? Messages.VIZALITY_UPDATES_FORCE : Messages.VIZALITY_UPDATES_UPDATE}
|
|
</Button>}
|
|
<Button
|
|
size={Button.Sizes.SMALL}
|
|
onClick={() => _this.checkForUpdates(true)}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_CHECK}
|
|
</Button>
|
|
<Button
|
|
size={Button.Sizes.SMALL}
|
|
color={Button.Colors.YELLOW}
|
|
onClick={() => confirmPauseUpdates()}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_PAUSE}
|
|
</Button>
|
|
<Button
|
|
size={Button.Sizes.SMALL}
|
|
color={Button.Colors.RED}
|
|
onClick={() => confirmDisableUpdates(true, () => updateSetting('disabled', true))}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_DISABLE}
|
|
</Button>
|
|
</>)}
|
|
</div>
|
|
</div>
|
|
{!disabled && !paused && !checking && updates.length > 0 && <div className='vz-updater-updates'>
|
|
<FormTitle className='vz-updater-updates-title'>
|
|
Pending Updates
|
|
</FormTitle>
|
|
{updates.map(update => {
|
|
return (
|
|
<Update
|
|
{...update}
|
|
key={update.updateId}
|
|
updating={updating}
|
|
onUpdate={() => _this.update(update)}
|
|
onSkip={() => confirmSkipUpdate(() => _this.skipUpdate(update, update.commits[0].id))}
|
|
onDisable={() => confirmDisableUpdates(false, () => _this.disableUpdates(update))}
|
|
/>
|
|
);
|
|
})}
|
|
</div>}
|
|
{disabledAddons.length > 0 && (
|
|
<Category title={Messages.VIZALITY_UPDATES_DISABLED_SECTION} description={Messages.VIZALITY_UPDATES_DISABLED_SECTION_DESC}>
|
|
{disabledAddons.map(update => {
|
|
return (
|
|
<Update
|
|
{...update}
|
|
disabled={true}
|
|
key={update.updateId}
|
|
updating={updating}
|
|
onEnableUpdates={() => _this.enableUpdates(update)}
|
|
/>
|
|
);
|
|
})}
|
|
</Category>
|
|
)}
|
|
<div className='vz-updater-options'>
|
|
<FormTitle className='vz-updater-options-title'>
|
|
{Messages.OPTIONS}
|
|
</FormTitle>
|
|
<SwitchItem
|
|
value={getSetting('automatic', false)}
|
|
disabled={disabled}
|
|
onChange={() => toggleSetting('automatic')}
|
|
note={Messages.VIZALITY_UPDATES_OPTS_AUTO_DESC}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_OPTS_AUTO}
|
|
</SwitchItem>
|
|
<SwitchItem
|
|
value={getSetting('checkForUpdatesOnStartup', false)}
|
|
disabled={disabled}
|
|
onChange={() => toggleSetting('checkForUpdatesOnStartup')}
|
|
note={Messages.VIZALITY_UPDATES_OPTS_STARTUP_CHECK_DESC}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_OPTS_STARTUP_CHECK}
|
|
</SwitchItem>
|
|
<TextInput
|
|
note={Messages.VIZALITY_UPDATES_OPTS_INTERVAL_DESC.format()}
|
|
disabled={disabled}
|
|
onChange={val => updateSetting('interval', _getValidInterval(val))}
|
|
defaultValue={getSetting('interval', 15)}
|
|
required={true}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_OPTS_INTERVAL}
|
|
</TextInput>
|
|
<TextInput
|
|
note={Messages.VIZALITY_UPDATES_OPTS_CONCURRENCY_DESC.format()}
|
|
disabled={disabled}
|
|
onChange={val => updateSetting('concurrency', _getValidConcurrency(val))}
|
|
defaultValue={getSetting('concurrency', 2)}
|
|
required={true}
|
|
>
|
|
{Messages.VIZALITY_UPDATES_OPTS_CONCURRENCY}
|
|
</TextInput>
|
|
</div>
|
|
</>
|
|
);
|
|
});
|