mirror of
https://github.com/Kong/insomnia
synced 2024-11-12 17:26:32 +00:00
0b38c68c1f
* fix: insomnia open dialog for proto directory can't select directories * uses a named export for selectFileOrFolder (also, removes original js file from rebase) * clears error by leveraging exhaustiveness check * fixes bug: the `name` field is actually for a file filter see the referenced pull request. As for the `extensions: ['*']`, there's no reason I can see to include a filter and then tell the filter to then accept everything. * update selectFileOrFolder mocks * use switch (for exhaustiveness checking) and type selectedFormat * removes unnecessary filters from _save_ dialog from the docs: > The filters specifies an array of file types that can be displayed As suspected, this is not needed. A user is free to save it wherever they want. * adds extension to saved file not sure why this was missing before, but it appears to have been a bug * formatting updates best to "ignore whitespace" for this commit. I did this with the hope of using the `ThunkAction` type from `redux-thunk`, but once I got them all looking good and started adding the type I quickly learned there's quite a bit more work to do in this area before we can have such a thing. I therefore opted to just call it a day at that and take the (no-op) formatting changes and typings. * removes remaining name filters from save dialogs same reason as the 2nd to prior commit - they cause the bug Co-authored-by: Dimitri Mitropoulos <dimitrimitropoulos@gmail.com> Co-authored-by: Opender Singh <opender.singh@konghq.com>
196 lines
5.4 KiB
TypeScript
196 lines
5.4 KiB
TypeScript
import type { ProtoFile } from '../../../models/proto-file';
|
|
import { showAlert, showError } from '../../../ui/components/modals';
|
|
import * as models from '../../../models';
|
|
import React from 'react';
|
|
import type { ProtoDirectory } from '../../../models/proto-directory';
|
|
import { database as db } from '../../../common/database';
|
|
import { selectFileOrFolder } from '../../../common/select-file-or-folder';
|
|
import ingestProtoDirectory from './ingest-proto-directory';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import * as protoLoader from '../proto-loader';
|
|
import { isProtoFile } from '../../../models/helpers/is-model';
|
|
|
|
export async function deleteFile(protoFile: ProtoFile, callback: (arg0: string) => void) {
|
|
showAlert({
|
|
title: `Delete ${protoFile.name}`,
|
|
message: (
|
|
<span>
|
|
Really delete <strong>{protoFile.name}</strong>? All requests that use this proto file will
|
|
stop working.
|
|
</span>
|
|
),
|
|
addCancel: true,
|
|
onConfirm: async () => {
|
|
await models.protoFile.remove(protoFile);
|
|
callback(protoFile._id);
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function deleteDirectory(protoDirectory: ProtoDirectory, callback: (arg0: string[]) => void) {
|
|
showAlert({
|
|
title: `Delete ${protoDirectory.name}`,
|
|
message: (
|
|
<span>
|
|
Really delete <strong>{protoDirectory.name}</strong> and all proto files contained within?
|
|
All requests that use these proto files will stop working.
|
|
</span>
|
|
),
|
|
addCancel: true,
|
|
onConfirm: async () => {
|
|
const descendant = await db.withDescendants(protoDirectory);
|
|
await models.protoDirectory.remove(protoDirectory);
|
|
callback(descendant.map(c => c._id));
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function addDirectory(workspaceId: string) {
|
|
let rollback = false;
|
|
let createdIds: string[];
|
|
const bufferId = await db.bufferChangesIndefinitely();
|
|
|
|
try {
|
|
// Select file
|
|
const { filePath, canceled } = await selectFileOrFolder({
|
|
itemTypes: ['directory'],
|
|
extensions: ['proto'],
|
|
});
|
|
|
|
// Exit if no file selected
|
|
if (canceled || !filePath) {
|
|
return;
|
|
}
|
|
|
|
const result = await ingestProtoDirectory(filePath, workspaceId);
|
|
createdIds = result.createdIds;
|
|
const { error, createdDir } = result;
|
|
|
|
if (error) {
|
|
showError({
|
|
title: 'Failed to import',
|
|
message: `An unexpected error occurred when reading ${filePath}`,
|
|
error,
|
|
});
|
|
rollback = true;
|
|
return;
|
|
}
|
|
|
|
// Show warning if no files found
|
|
if (!createdDir) {
|
|
showAlert({
|
|
title: 'No files found',
|
|
message: `No .proto files were found under ${filePath}.`,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Try parse all loaded proto files to make sure they are valid
|
|
const loadedEntities = await db.withDescendants(createdDir);
|
|
const loadedFiles = loadedEntities.filter(isProtoFile);
|
|
|
|
for (const file of loadedFiles) {
|
|
try {
|
|
await protoLoader.loadMethods(file);
|
|
} catch (e) {
|
|
showError({
|
|
title: 'Invalid Proto File',
|
|
message: `The file ${file.name} could not be parsed`,
|
|
error: e,
|
|
});
|
|
rollback = true;
|
|
return;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
rollback = true;
|
|
showError({
|
|
error: e,
|
|
});
|
|
} finally {
|
|
// Fake flushing changes (or, rollback) only prevents change notifications being sent to the UI
|
|
// It does NOT revert changes written to the database, as is typical of a db transaction rollback
|
|
// As such, if rolling back, the created directory needs to be deleted manually
|
|
await db.flushChanges(bufferId, rollback);
|
|
|
|
if (rollback) {
|
|
// @ts-expect-error -- TSCONVERSION
|
|
await models.protoDirectory.batchRemoveIds(createdIds);
|
|
// @ts-expect-error -- TSCONVERSION
|
|
await models.protoFile.batchRemoveIds(createdIds);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function _readFile() {
|
|
try {
|
|
// Select file
|
|
const { filePath, canceled } = await selectFileOrFolder({
|
|
itemTypes: ['file'],
|
|
extensions: ['proto'],
|
|
});
|
|
|
|
// Exit if no file selected
|
|
if (canceled || !filePath) {
|
|
return;
|
|
}
|
|
|
|
// Try parse proto file to make sure the file is valid
|
|
try {
|
|
await protoLoader.loadMethodsFromPath(filePath);
|
|
} catch (e) {
|
|
showError({
|
|
title: 'Invalid Proto File',
|
|
message: `The file ${filePath} and could not be parsed`,
|
|
error: e,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Read contents
|
|
const contents = await fs.promises.readFile(filePath, 'utf-8');
|
|
const name = path.basename(filePath);
|
|
return {
|
|
fileName: name,
|
|
fileContents: contents,
|
|
};
|
|
} catch (e) {
|
|
showError({
|
|
error: e,
|
|
});
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export async function addFile(workspaceId: string, callback: (arg0: string) => void) {
|
|
const result = await _readFile();
|
|
|
|
if (result) {
|
|
const newFile = await models.protoFile.create({
|
|
name: result.fileName,
|
|
parentId: workspaceId,
|
|
protoText: result.fileContents,
|
|
});
|
|
callback(newFile._id);
|
|
}
|
|
}
|
|
|
|
export async function updateFile(protoFile: ProtoFile, callback: (arg0: string) => void) {
|
|
const result = await _readFile();
|
|
|
|
if (result) {
|
|
const updatedFile = await models.protoFile.update(protoFile, {
|
|
name: result.fileName,
|
|
protoText: result.fileContents,
|
|
});
|
|
callback(updatedFile._id);
|
|
}
|
|
}
|
|
|
|
export async function renameFile(protoFile: ProtoFile, name: string) {
|
|
await models.protoFile.update(protoFile, {
|
|
name,
|
|
});
|
|
}
|