Add option to disable migrating workspaces (#3108)

This commit is contained in:
Opender Singh authored and GitHub committed 2021-02-26 12:01:46 +13:00
1 parent 3b81808e1d
commit 6f3d2666f8
5 files changed
+100 -53

No files matched your search

@@ -58,7 +58,7 @@ type DBType = { [string]: Array<BaseModel> };
export type MigrationOptions = {
useDesignerSettings: boolean,
copyPlugins: boolean,
copyResponses: boolean,
copyWorkspaces: boolean,
designerDataDir: string,
coreDataDir: string,
};
@@ -149,13 +149,32 @@ export default async function migrateFromDesigner({
designerDataDir,
coreDataDir,
copyPlugins,
copyResponses,
copyWorkspaces,
}: MigrationOptions): Promise<MigrationResult> {
const modelTypesToIgnore = [
console.log(
`[db-merge] starting process for migrating from ${designerDataDir} to ${coreDataDir}`,
);
const nonWorkspaceModels = [
models.stats.type, // TODO: investigate further any implications that may invalidate collected stats
models.settings.type,
];
const modelTypesToMerge = difference(models.types(), modelTypesToIgnore);
// Every model except those to ignore and settings is a "workspace" model
const workspaceModels = difference(models.types(), nonWorkspaceModels);
const modelTypesToMerge = [];
if (useDesignerSettings) {
modelTypesToMerge.push(models.settings.type);
console.log(`[db-merge] keeping settings from Insomnia Designer`);
} else {
console.log(`[db-merge] keeping settings from Insomnia Core`);
}
if (copyWorkspaces) {
modelTypesToMerge.push(...workspaceModels);
}
let backupDir = '';
@@ -166,36 +185,23 @@ export default async function migrateFromDesigner({
// Load designer database
const designerDb: DBType = await loadDesignerDb(modelTypesToMerge, designerDataDir);
// Ensure user is not migrating an existing Insomnia Core repo
const designerSettings: Settings = designerDb[models.settings.type][0];
if (designerSettings.hasOwnProperty('hasPromptedToMigrateFromDesigner')) {
console.log('[db-merge] cannot merge database');
return;
}
// For each model, batch upsert entries into the Core database
for (const modelType of modelTypesToMerge) {
const entries = designerDb[modelType];
// Decide how to merge settings
// Persist some settings from core
if (modelType === models.settings.type) {
if (useDesignerSettings) {
console.log(`[db-merge] keeping settings from Insomnia Designer`);
const coreSettings = await models.settings.getOrCreate();
const propertiesToPersist = [
'_id',
'hasPromptedOnboarding',
'hasPromptedToMigrateFromDesigner',
];
propertiesToPersist.forEach(s => {
if (coreSettings.hasOwnProperty(s)) {
(entries[0]: Settings)[s] = coreSettings[s];
}
});
} else {
console.log(`[db-merge] keeping settings from Insomnia Core`);
continue;
}
const coreSettings = await models.settings.getOrCreate();
const propertiesToPersist = [
'_id',
'hasPromptedOnboarding',
'hasPromptedToMigrateFromDesigner',
];
propertiesToPersist.forEach(s => {
if (coreSettings.hasOwnProperty(s)) {
(entries[0]: Settings)[s] = coreSettings[s];
}
});
}
// For each workspace coming from Designer, mark workspace.scope as 'designer'
@@ -212,21 +218,17 @@ export default async function migrateFromDesigner({
await db.batchModifyDocs({ upsert: entries, remove: [] });
}
console.log(`[db-merge] migrating version control data from designer to core`);
await copyDirs(['version-control'], designerDataDir, coreDataDir);
if (copyWorkspaces) {
console.log(`[db-merge] migrating version control data from designer to core`);
await copyDirs(['version-control'], designerDataDir, coreDataDir);
if (copyResponses) {
console.log(`[db-merge] migrating response cache from designer to core`);
await copyDirs(['responses'], designerDataDir, coreDataDir);
} else {
console.log(`[db-merge] not migrating response cache`);
}
if (copyPlugins) {
console.log(`[db-merge] migrating plugins from designer to core`);
await migratePlugins(designerDataDir, coreDataDir);
} else {
console.log(`[db-merge] not migrating plugins`);
}
console.log('[db-merge] done!');
@@ -9,6 +9,7 @@ import { getDataDirectory, getDesignerDataDir } from '../../common/misc';
import { useDispatch } from 'react-redux';
import OnboardingContainer from './onboarding-container';
import { goToNextActivity } from '../redux/modules/global';
import HelpTooltip from './help-tooltip';
type Step = 'options' | 'migrating' | 'results';
@@ -16,7 +17,9 @@ type SettingProps = {
label: string,
name: $Keys<MigrationOptions>,
options: MigrationOptions,
help?: string,
};
type TextSettingProps = SettingProps & {
handleChange: (SyntheticEvent<HTMLInputElement>) => void,
};
@@ -38,17 +41,27 @@ const TextSetting = ({ handleChange, label, name, options }: TextSettingProps) =
type BooleanSettingProps = SettingProps & {
handleChange: (boolean, Object, string) => void,
};
const BooleanSetting = ({ handleChange, label, name, options }: BooleanSettingProps) => {
const BooleanSetting = ({ handleChange, label, name, options, help }: BooleanSettingProps) => {
if (!options.hasOwnProperty(name)) {
throw new Error(`Invalid text setting name ${name}`);
}
const labelNode = React.useMemo(
() => (
<>
{label}
{help && <HelpTooltip className="space-left">{help}</HelpTooltip>}
</>
),
[help, label],
);
return (
<ToggleSwitch
labelClassName="row margin-bottom wide"
checked={options[name]}
id={name}
label={label}
label={labelNode}
onChange={handleChange}
/>
);
@@ -58,8 +71,8 @@ type OptionsProps = { start: MigrationOptions => void, cancel: () => void };
const Options = ({ start, cancel }: OptionsProps) => {
const [options, setOptions] = React.useState<MigrationOptions>(() => ({
useDesignerSettings: false,
copyResponses: true,
copyPlugins: true,
copyWorkspaces: false,
copyPlugins: false,
designerDataDir: getDesignerDataDir(),
coreDataDir: getDataDirectory(),
}));
@@ -72,6 +85,8 @@ const Options = ({ start, cancel }: OptionsProps) => {
setOptions(prevOpts => ({ ...prevOpts, [id]: checked }));
}, []);
const canStart = options.useDesignerSettings || options.copyWorkspaces || options.copyPlugins;
return (
<>
<p>
@@ -83,22 +98,29 @@ const Options = ({ start, cancel }: OptionsProps) => {
</p>
<div className="text-left margin-top">
<BooleanSetting
label="Copy Designer Application Settings"
name="useDesignerSettings"
label="Copy Workspaces"
name="copyWorkspaces"
options={options}
handleChange={handleSwitchChange}
help={
'This includes all resources linked to a workspace (eg. requests, proto files, environments, etc)'
}
/>
<BooleanSetting
label="Copy Plugins"
name="copyPlugins"
options={options}
handleChange={handleSwitchChange}
help={
'Merge plugins between Designer and Insomnia, keeping the Designer version where a duplicate exists'
}
/>
<BooleanSetting
label="Copy Responses"
name="copyResponses"
label="Copy Designer Application Settings"
name="useDesignerSettings"
options={options}
handleChange={handleSwitchChange}
help={'Keep user preferences from Designer'}
/>
<details>
<summary className="margin-bottom">Advanced options</summary>
@@ -118,7 +140,11 @@ const Options = ({ start, cancel }: OptionsProps) => {
</div>
<div className="margin-top">
<button key="start" className="btn btn--clicky" onClick={() => start(options)}>
<button
key="start"
className="btn btn--clicky"
onClick={() => start(options)}
disabled={!canStart}>
Start Migration
</button>
<button key="cancel" className="btn btn--super-compact" onClick={cancel}>
@@ -9,7 +9,7 @@ type Props = {
checked?: boolean,
disabled?: boolean,
onChange(checked: boolean, Event, string): void | Promise<void>,
label?: string,
label?: React.Node,
};
const ThemedSwitch: React.ComponentType<{ checked: boolean }> = styled(Switch)`
@@ -41,7 +41,13 @@ describe('Migration', function() {
await client.correctlyLaunched(app);
await migration.migrationMessageShown(app);
await migration.ensureStartNotClickable(app);
await migration.toggleOption(app, 'Copy Workspaces');
await migration.toggleOption(app, 'Copy Plugins');
await migration.toggleOption(app, 'Copy Designer Application Settings');
await migration.clickStart(app);
await migration.successMessageShown(app);
await migration.clickRestart(app);
@@ -6,21 +6,34 @@ export const migrationMessageShown = async app => {
};
export const clickSkip = async app => {
const button = await app.client
.$('.onboarding__content__body')
.then(e => e.$(`button=Skip for now`));
const button = await app.client.react$('MigrationBody').then(e => e.$(`button=Skip for now`));
await button.waitForClickable();
await button.click();
};
export const clickStart = async app => {
const button = await app.client
export const toggleOption = async (app, label) => {
const toggle = await app.client
.$('.onboarding__content__body')
.then(e => e.$(`button=Start Migration`));
.then(e => e.react$(`BooleanSetting`, { props: { label } }));
await toggle.waitForClickable();
await toggle.click();
};
const _getStartButton = async app => {
return await app.client.react$('MigrationBody').then(e => e.$(`button=Start Migration`));
};
export const clickStart = async app => {
const button = await _getStartButton(app);
await button.waitForClickable();
await button.click();
};
export const ensureStartNotClickable = async app => {
const button = await _getStartButton(app);
await button.waitForClickable({ reverse: true });
};
export const successMessageShown = async app => {
await app.client.waitUntilTextExists(
'.onboarding__content__body p strong',
@@ -31,7 +44,7 @@ export const successMessageShown = async app => {
export const clickRestart = async app => {
await app.client
.$('.onboarding__content__body')
.react$('MigrationBody')
.then(e => e.$(`button=Restart Now`))
.then(e => e.click());
};