mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-27 14:44:07 +00:00
sort folders by name first and then sequence (#5063)
* sort folders by name first and then sequence --------- Co-authored-by: lohit <lohit@usebruno.com>
This commit is contained in:
@@ -30,6 +30,7 @@ import { scrollToTheActiveTab } from 'utils/tabs';
|
|||||||
import { isTabForItemActive as isTabForItemActiveSelector, isTabForItemPresent as isTabForItemPresentSelector } from 'src/selectors/tab';
|
import { isTabForItemActive as isTabForItemActiveSelector, isTabForItemPresent as isTabForItemPresentSelector } from 'src/selectors/tab';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import { calculateDraggedItemNewPathname } from 'utils/collections/index';
|
import { calculateDraggedItemNewPathname } from 'utils/collections/index';
|
||||||
|
import { sortByNameThenSequence } from 'utils/common/index';
|
||||||
|
|
||||||
const CollectionItem = ({ item, collectionUid, collectionPathname, searchText }) => {
|
const CollectionItem = ({ item, collectionUid, collectionPathname, searchText }) => {
|
||||||
const _isTabForItemActiveSelector = isTabForItemActiveSelector({ itemUid: item.uid });
|
const _isTabForItemActiveSelector = isTabForItemActiveSelector({ itemUid: item.uid });
|
||||||
@@ -250,7 +251,7 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
|
|||||||
dispatch(makeTabPermanent({ uid: item.uid }));
|
dispatch(makeTabPermanent({ uid: item.uid }));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sort items by their "seq" property.
|
// Sort items by their "seq" property.
|
||||||
const sortItemsBySequence = (items = []) => {
|
const sortItemsBySequence = (items = []) => {
|
||||||
return items.sort((a, b) => a.seq - b.seq);
|
return items.sort((a, b) => a.seq - b.seq);
|
||||||
};
|
};
|
||||||
@@ -262,7 +263,7 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const folderItems = sortItemsBySequence(filter(item.items, (i) => isItemAFolder(i)));
|
const folderItems = sortByNameThenSequence(filter(item.items, (i) => isItemAFolder(i)));
|
||||||
const requestItems = sortItemsBySequence(filter(item.items, (i) => isItemARequest(i)));
|
const requestItems = sortItemsBySequence(filter(item.items, (i) => isItemARequest(i)));
|
||||||
|
|
||||||
const handleGenerateCode = (e) => {
|
const handleGenerateCode = (e) => {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { areItemsLoading } from 'utils/collections';
|
|||||||
import { scrollToTheActiveTab } from 'utils/tabs';
|
import { scrollToTheActiveTab } from 'utils/tabs';
|
||||||
import ShareCollection from 'components/ShareCollection/index';
|
import ShareCollection from 'components/ShareCollection/index';
|
||||||
import { CollectionItemDragPreview } from './CollectionItem/CollectionItemDragPreview/index';
|
import { CollectionItemDragPreview } from './CollectionItem/CollectionItemDragPreview/index';
|
||||||
|
import { sortByNameThenSequence } from 'utils/common/index';
|
||||||
|
|
||||||
const Collection = ({ collection, searchText }) => {
|
const Collection = ({ collection, searchText }) => {
|
||||||
const [showNewFolderModal, setShowNewFolderModal] = useState(false);
|
const [showNewFolderModal, setShowNewFolderModal] = useState(false);
|
||||||
@@ -185,7 +186,7 @@ const Collection = ({ collection, searchText }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const requestItems = sortItemsBySequence(filter(collection.items, (i) => isItemARequest(i)));
|
const requestItems = sortItemsBySequence(filter(collection.items, (i) => isItemARequest(i)));
|
||||||
const folderItems = sortItemsBySequence(filter(collection.items, (i) => isItemAFolder(i)));
|
const folderItems = sortByNameThenSequence(filter(collection.items, (i) => isItemAFolder(i)));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="flex flex-col">
|
<StyledWrapper className="flex flex-col">
|
||||||
|
|||||||
@@ -383,33 +383,26 @@ export const newFolder = (folderName, directoryName, collectionUid, itemUid) =>
|
|||||||
if (!folderWithSameNameExists) {
|
if (!folderWithSameNameExists) {
|
||||||
const fullName = path.join(collection.pathname, directoryName);
|
const fullName = path.join(collection.pathname, directoryName);
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
|
const folderBruJsonData = {
|
||||||
|
meta: {
|
||||||
|
name: folderName,
|
||||||
|
seq: items?.length + 1
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
auth: {
|
||||||
|
mode: 'inherit'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ipcRenderer
|
ipcRenderer
|
||||||
.invoke('renderer:new-folder', fullName)
|
.invoke('renderer:new-folder', { pathname: fullName, folderBruJsonData })
|
||||||
.then(async () => {
|
.then(resolve)
|
||||||
const folderData = {
|
.catch((error) => {
|
||||||
name: folderName,
|
toast.error('Failed to create a new folder!');
|
||||||
pathname: fullName,
|
reject(error)
|
||||||
root: {
|
});
|
||||||
meta: {
|
|
||||||
name: folderName,
|
|
||||||
seq: items?.length + 1
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
auth: {
|
|
||||||
mode: 'inherit'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ipcRenderer
|
|
||||||
.invoke('renderer:save-folder-root', folderData)
|
|
||||||
.then(resolve)
|
|
||||||
.catch((err) => {
|
|
||||||
toast.error('Failed to save folder settings!');
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => reject(error));
|
|
||||||
} else {
|
} else {
|
||||||
return reject(new Error('Duplicate folder names under same parent folder are not allowed'));
|
return reject(new Error('Duplicate folder names under same parent folder are not allowed'));
|
||||||
}
|
}
|
||||||
@@ -424,33 +417,25 @@ export const newFolder = (folderName, directoryName, collectionUid, itemUid) =>
|
|||||||
const fullName = path.join(currentItem.pathname, directoryName);
|
const fullName = path.join(currentItem.pathname, directoryName);
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
|
const folderBruJsonData = {
|
||||||
|
meta: {
|
||||||
|
name: folderName,
|
||||||
|
seq: items?.length + 1
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
auth: {
|
||||||
|
mode: 'inherit'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ipcRenderer
|
ipcRenderer
|
||||||
.invoke('renderer:new-folder', fullName)
|
.invoke('renderer:new-folder', { pathname: fullName, folderBruJsonData })
|
||||||
.then(async () => {
|
.then(resolve)
|
||||||
const folderData = {
|
.catch((error) => {
|
||||||
name: folderName,
|
toast.error('Failed to create a new folder!');
|
||||||
pathname: fullName,
|
reject(error)
|
||||||
root: {
|
});
|
||||||
meta: {
|
|
||||||
name: folderName,
|
|
||||||
seq: items?.length + 1
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
auth: {
|
|
||||||
mode: 'inherit'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ipcRenderer
|
|
||||||
.invoke('renderer:save-folder-root', folderData)
|
|
||||||
.then(resolve)
|
|
||||||
.catch((err) => {
|
|
||||||
toast.error('Failed to save folder settings!');
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => reject(error));
|
|
||||||
} else {
|
} else {
|
||||||
return reject(new Error('Duplicate folder names under same parent folder are not allowed'));
|
return reject(new Error('Duplicate folder names under same parent folder are not allowed'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1890,7 +1890,7 @@ export const collectionsSlice = createSlice({
|
|||||||
uid: dir?.meta?.uid || uuid(),
|
uid: dir?.meta?.uid || uuid(),
|
||||||
pathname: currentPath,
|
pathname: currentPath,
|
||||||
name: dir?.meta?.name || directoryName,
|
name: dir?.meta?.name || directoryName,
|
||||||
seq: dir?.meta?.seq || 1,
|
seq: dir?.meta?.seq,
|
||||||
filename: directoryName,
|
filename: directoryName,
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
type: 'folder',
|
type: 'folder',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {cloneDeep, isEqual, sortBy, filter, map, isString, findIndex, find, each, get } from 'lodash';
|
import {cloneDeep, isEqual, sortBy, filter, map, isString, findIndex, find, each, get } from 'lodash';
|
||||||
import { uuid } from 'utils/common';
|
import { uuid } from 'utils/common';
|
||||||
|
import { sortByNameThenSequence } from 'utils/common/index';
|
||||||
import path from 'utils/common/path';
|
import path from 'utils/common/path';
|
||||||
|
|
||||||
const replaceTabsWithSpaces = (str, numSpaces = 2) => {
|
const replaceTabsWithSpaces = (str, numSpaces = 2) => {
|
||||||
@@ -1036,7 +1037,7 @@ export const getFormattedCollectionOauth2Credentials = ({ oauth2Credentials = []
|
|||||||
|
|
||||||
export const resetSequencesInFolder = (folderItems) => {
|
export const resetSequencesInFolder = (folderItems) => {
|
||||||
const items = folderItems;
|
const items = folderItems;
|
||||||
const sortedItems = items.sort((a, b) => a.seq - b.seq);
|
const sortedItems = sortByNameThenSequence(items);
|
||||||
return sortedItems.map((item, index) => {
|
return sortedItems.map((item, index) => {
|
||||||
item.seq = index + 1;
|
item.seq = index + 1;
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -0,0 +1,374 @@
|
|||||||
|
const { describe, it, expect } = require('@jest/globals');
|
||||||
|
const { sortByNameThenSequence } = require('./index');
|
||||||
|
|
||||||
|
describe('sortByNameThenSequence', () => {
|
||||||
|
describe('Basic functionality', () => {
|
||||||
|
it('should return an empty array when given an empty array', () => {
|
||||||
|
const items = [];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not mutate the original array', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_1', seq: 1 }
|
||||||
|
];
|
||||||
|
const originalItems = JSON.parse(JSON.stringify(items));
|
||||||
|
sortByNameThenSequence(items);
|
||||||
|
expect(items).toEqual(originalItems);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a new array instance', () => {
|
||||||
|
const items = [{ name: 'folder_1' }];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).not.toBe(items);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Alphabetical sorting (no sequence numbers)', () => {
|
||||||
|
it('should sort items alphabetically by name when no sequence numbers are present', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3' },
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'folder_2' }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'folder_2' },
|
||||||
|
{ name: 'folder_3' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle case-sensitive sorting correctly', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'Folder_2' },
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'FOLDER_3' }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'Folder_2' },
|
||||||
|
{ name: 'FOLDER_3' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle special characters in names', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder-2' },
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'folder 3' }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder 3' },
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'folder-2' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Sequence-based sorting (valid sequence numbers)', () => {
|
||||||
|
it('should sort items by sequence when all items have valid sequence numbers', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: 3 },
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_2', seq: 2 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_3', seq: 3 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle duplicate sequence numbers by inserting them in alphabetical order', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: 1 },
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_2', seq: 2 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_3', seq: 1 },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle large sequence numbers correctly', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_1', seq: 100 },
|
||||||
|
{ name: 'folder_2', seq: 1 },
|
||||||
|
{ name: 'folder_3', seq: 50 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_2', seq: 1 },
|
||||||
|
{ name: 'folder_3', seq: 50 },
|
||||||
|
{ name: 'folder_1', seq: 100 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Invalid sequence numbers', () => {
|
||||||
|
it('should treat undefined sequence as invalid and sort alphabetically', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: undefined },
|
||||||
|
{ name: 'folder_1', seq: undefined },
|
||||||
|
{ name: 'folder_2', seq: undefined }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: undefined },
|
||||||
|
{ name: 'folder_2', seq: undefined },
|
||||||
|
{ name: 'folder_3', seq: undefined }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat null sequence as invalid and sort alphabetically', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: null },
|
||||||
|
{ name: 'folder_1', seq: null },
|
||||||
|
{ name: 'folder_2', seq: null }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: null },
|
||||||
|
{ name: 'folder_2', seq: null },
|
||||||
|
{ name: 'folder_3', seq: null }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat boolean values as invalid sequence numbers', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: true },
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_2', seq: true }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_2', seq: true },
|
||||||
|
{ name: 'folder_3', seq: true }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat string values as invalid sequence numbers', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: '3' },
|
||||||
|
{ name: 'folder_1', seq: '1' },
|
||||||
|
{ name: 'folder_2', seq: 'invalid' }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: '1' },
|
||||||
|
{ name: 'folder_2', seq: 'invalid' },
|
||||||
|
{ name: 'folder_3', seq: '3' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat non-integer numbers as invalid sequence numbers', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: 3.5 },
|
||||||
|
{ name: 'folder_1', seq: 1.2 },
|
||||||
|
{ name: 'folder_2', seq: 2.0 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: 1.2 },
|
||||||
|
{ name: 'folder_2', seq: 2.0 },
|
||||||
|
{ name: 'folder_3', seq: 3.5 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat zero and negative numbers as invalid sequence numbers', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: 0 },
|
||||||
|
{ name: 'folder_1', seq: -1 },
|
||||||
|
{ name: 'folder_2', seq: -5 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: -1 },
|
||||||
|
{ name: 'folder_2', seq: -5 },
|
||||||
|
{ name: 'folder_3', seq: 0 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat NaN and Infinity as invalid sequence numbers', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3', seq: NaN },
|
||||||
|
{ name: 'folder_1', seq: Infinity },
|
||||||
|
{ name: 'folder_2', seq: -Infinity }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: Infinity },
|
||||||
|
{ name: 'folder_2', seq: -Infinity },
|
||||||
|
{ name: 'folder_3', seq: NaN }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle invalid sequence numbers correctly', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_4', seq: undefined },
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_5', seq: 'invalid' },
|
||||||
|
{ name: 'folder_2', seq: true },
|
||||||
|
{ name: 'folder_3', seq: null }
|
||||||
|
];
|
||||||
|
const sorted = sortByNameThenSequence(items);
|
||||||
|
expect(sorted).toEqual([
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_2', seq: true },
|
||||||
|
{ name: 'folder_3', seq: null },
|
||||||
|
{ name: 'folder_4', seq: undefined },
|
||||||
|
{ name: 'folder_5', seq: 'invalid' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Mixed valid and invalid sequence numbers', () => {
|
||||||
|
it('should handle mixed valid and invalid sequence numbers correctly', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_4', seq: undefined },
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_5', seq: 3 },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_3', seq: null },
|
||||||
|
{ name: 'folder_6', seq: 9 },
|
||||||
|
{ name: 'folder_8', seq: 'invalid' },
|
||||||
|
{ name: 'folder_7', seq: 4 }
|
||||||
|
];
|
||||||
|
const sorted = sortByNameThenSequence(items);
|
||||||
|
expect(sorted).toEqual([
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_5', seq: 3 },
|
||||||
|
{ name: 'folder_7', seq: 4 },
|
||||||
|
{ name: 'folder_3', seq: null },
|
||||||
|
{ name: 'folder_4', seq: undefined },
|
||||||
|
{ name: 'folder_8', seq: 'invalid' },
|
||||||
|
{ name: 'folder_6', seq: 9 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should insert sequenced items at their positions among non-sequenced items', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_6' },
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_5' },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_4' },
|
||||||
|
{ name: 'folder_3', seq: 4 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_4' },
|
||||||
|
{ name: 'folder_3', seq: 4 },
|
||||||
|
{ name: 'folder_5' },
|
||||||
|
{ name: 'folder_6' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle sequence numbers beyond the array length', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_1', seq: 10 },
|
||||||
|
{ name: 'folder_2' },
|
||||||
|
{ name: 'folder_3', seq: 20 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_2' },
|
||||||
|
{ name: 'folder_1', seq: 10 },
|
||||||
|
{ name: 'folder_3', seq: 20 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Edge cases and boundary conditions', () => {
|
||||||
|
it('should handle items with missing name property without throwing errors', () => {
|
||||||
|
const items = [
|
||||||
|
{ seq: 1 },
|
||||||
|
{ name: 'folder_1' },
|
||||||
|
{ name: 'folder_2', seq: 2 }
|
||||||
|
];
|
||||||
|
// Note: This might cause issues in production, but we test the current behavior
|
||||||
|
expect(() => sortByNameThenSequence(items)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle items with no seq property (equivalent to undefined)', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_3' },
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_2' }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_1', seq: 1 },
|
||||||
|
{ name: 'folder_2' },
|
||||||
|
{ name: 'folder_3' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle single item arrays', () => {
|
||||||
|
const items = [{ name: 'folder_1', seq: 1 }];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([{ name: 'folder_1', seq: 1 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle items with identical names but different sequences', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder', seq: 2 },
|
||||||
|
{ name: 'folder', seq: 1 },
|
||||||
|
{ name: 'folder' }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder', seq: 1 },
|
||||||
|
{ name: 'folder', seq: 2 },
|
||||||
|
{ name: 'folder' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Complex scenarios', () => {
|
||||||
|
it('should handle a comprehensive mix of all scenarios', () => {
|
||||||
|
const items = [
|
||||||
|
{ name: 'folder_10', seq: 'invalid' },
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_11', seq: 3 },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_3', seq: null },
|
||||||
|
{ name: 'folder_12', seq: 9 },
|
||||||
|
{ name: 'folder_4', seq: undefined },
|
||||||
|
{ name: 'folder_5' },
|
||||||
|
{ name: 'folder_6', seq: 0 },
|
||||||
|
{ name: 'folder_7', seq: 4 },
|
||||||
|
{ name: 'folder_8', seq: 1 },
|
||||||
|
{ name: 'folder_9', seq: -1 }
|
||||||
|
];
|
||||||
|
const result = sortByNameThenSequence(items);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ name: 'folder_8', seq: 1 },
|
||||||
|
{ name: 'folder_2', seq: 2 },
|
||||||
|
{ name: 'folder_11', seq: 3 },
|
||||||
|
{ name: 'folder_7', seq: 4 },
|
||||||
|
{ name: 'folder_1', seq: false },
|
||||||
|
{ name: 'folder_10', seq: 'invalid' },
|
||||||
|
{ name: 'folder_3', seq: null },
|
||||||
|
{ name: 'folder_4', seq: undefined },
|
||||||
|
{ name: 'folder_12', seq: 9 },
|
||||||
|
{ name: 'folder_5' },
|
||||||
|
{ name: 'folder_6', seq: 0 },
|
||||||
|
{ name: 'folder_9', seq: -1 }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -220,3 +220,44 @@ export const formatSize = (bytes) => {
|
|||||||
|
|
||||||
return (bytes / (1024 * 1024 * 1024)).toFixed(1) + 'GB';
|
return (bytes / (1024 * 1024 * 1024)).toFixed(1) + 'GB';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sortByNameThenSequence = items => {
|
||||||
|
const isSeqValid = seq => Number.isFinite(seq) && Number.isInteger(seq) && seq > 0;
|
||||||
|
|
||||||
|
// Sort folders alphabetically by name
|
||||||
|
const alphabeticallySorted = [...items].sort((a, b) => a.name && b.name && a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
// Extract folders without 'seq'
|
||||||
|
const withoutSeq = alphabeticallySorted.filter(f => !isSeqValid(f['seq']));
|
||||||
|
|
||||||
|
// Extract folders with 'seq' and sort them by 'seq'
|
||||||
|
const withSeq = alphabeticallySorted.filter(f => isSeqValid(f['seq'])).sort((a, b) => a.seq - b.seq);
|
||||||
|
|
||||||
|
const sortedItems = withoutSeq;
|
||||||
|
|
||||||
|
// Insert folders with 'seq' at their specified positions
|
||||||
|
withSeq.forEach((item) => {
|
||||||
|
const position = item.seq - 1;
|
||||||
|
const existingItem = withoutSeq[position];
|
||||||
|
|
||||||
|
// Check if there's already an item with the same sequence number
|
||||||
|
const hasItemWithSameSeq = Array.isArray(existingItem)
|
||||||
|
? existingItem[0].seq === item.seq
|
||||||
|
: existingItem?.seq === item.seq;
|
||||||
|
|
||||||
|
if (hasItemWithSameSeq) {
|
||||||
|
// If there's a conflict, group items with same sequence together
|
||||||
|
const newGroup = Array.isArray(existingItem)
|
||||||
|
? [...existingItem, item]
|
||||||
|
: [existingItem, item];
|
||||||
|
|
||||||
|
withoutSeq.splice(position, 1, newGroup);
|
||||||
|
} else {
|
||||||
|
// Insert item at the specified position
|
||||||
|
withoutSeq.splice(position, 0, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// return flattened sortedItems
|
||||||
|
return sortedItems.flat();
|
||||||
|
};
|
||||||
@@ -22,8 +22,11 @@ const collectionBruToJson = (bru) => {
|
|||||||
if (json?.meta) {
|
if (json?.meta) {
|
||||||
transformedJson.meta = {
|
transformedJson.meta = {
|
||||||
name: json.meta.name,
|
name: json.meta.name,
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (sequence) {
|
||||||
|
transformedJson.meta.seq = Number(sequence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformedJson;
|
return transformedJson;
|
||||||
@@ -59,7 +62,7 @@ const bruToJson = (bru) => {
|
|||||||
const transformedJson = {
|
const transformedJson = {
|
||||||
type: requestType,
|
type: requestType,
|
||||||
name: _.get(json, 'meta.name'),
|
name: _.get(json, 'meta.name'),
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1,
|
seq: !_.isNaN(sequence) ? Number(sequence) : 1,
|
||||||
request: {
|
request: {
|
||||||
method: _.upperCase(_.get(json, 'http.method')),
|
method: _.upperCase(_.get(json, 'http.method')),
|
||||||
url: _.get(json, 'http.url'),
|
url: _.get(json, 'http.url'),
|
||||||
|
|||||||
@@ -326,14 +326,14 @@ const addDirectory = async (win, pathname, collectionUid, collectionPath) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let name = path.basename(pathname);
|
let name = path.basename(pathname);
|
||||||
let seq = 1;
|
let seq;
|
||||||
const folderBruFilePath = path.join(pathname, `folder.bru`);
|
const folderBruFilePath = path.join(pathname, `folder.bru`);
|
||||||
|
|
||||||
if (fs.existsSync(folderBruFilePath)) {
|
if (fs.existsSync(folderBruFilePath)) {
|
||||||
let folderBruFileContent = fs.readFileSync(folderBruFilePath, 'utf8');
|
let folderBruFileContent = fs.readFileSync(folderBruFilePath, 'utf8');
|
||||||
let folderBruData = await collectionBruToJson(folderBruFileContent);
|
let folderBruData = await collectionBruToJson(folderBruFileContent);
|
||||||
name = folderBruData?.meta?.name || name;
|
name = folderBruData?.meta?.name || name;
|
||||||
seq = folderBruData?.meta?.seq || seq;
|
seq = folderBruData?.meta?.seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
const directory = {
|
const directory = {
|
||||||
|
|||||||
@@ -33,8 +33,11 @@ const collectionBruToJson = async (data, parsed = false) => {
|
|||||||
if (json?.meta) {
|
if (json?.meta) {
|
||||||
transformedJson.meta = {
|
transformedJson.meta = {
|
||||||
name: json.meta.name,
|
name: json.meta.name,
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (sequence) {
|
||||||
|
transformedJson.meta.seq = Number(sequence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformedJson;
|
return transformedJson;
|
||||||
@@ -67,8 +70,11 @@ const jsonToCollectionBru = async (json, isFolder) => {
|
|||||||
if (json?.meta) {
|
if (json?.meta) {
|
||||||
collectionBruJson.meta = {
|
collectionBruJson.meta = {
|
||||||
name: json.meta.name,
|
name: json.meta.name,
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (sequence) {
|
||||||
|
collectionBruJson.meta.seq = Number(sequence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _jsonToCollectionBru(collectionBruJson);
|
return _jsonToCollectionBru(collectionBruJson);
|
||||||
@@ -129,7 +135,7 @@ const bruToJson = (data, parsed = false) => {
|
|||||||
const transformedJson = {
|
const transformedJson = {
|
||||||
type: requestType,
|
type: requestType,
|
||||||
name: _.get(json, 'meta.name'),
|
name: _.get(json, 'meta.name'),
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1,
|
seq: !_.isNaN(sequence) ? Number(sequence) : 1,
|
||||||
request: {
|
request: {
|
||||||
method: _.upperCase(_.get(json, 'http.method')),
|
method: _.upperCase(_.get(json, 'http.method')),
|
||||||
url: _.get(json, 'http.url'),
|
url: _.get(json, 'http.url'),
|
||||||
@@ -187,7 +193,7 @@ const jsonToBru = async (json) => {
|
|||||||
meta: {
|
meta: {
|
||||||
name: _.get(json, 'name'),
|
name: _.get(json, 'name'),
|
||||||
type: type,
|
type: type,
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
seq: !_.isNaN(sequence) ? Number(sequence) : 1
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
method: _.lowerCase(_.get(json, 'request.method')),
|
method: _.lowerCase(_.get(json, 'request.method')),
|
||||||
@@ -228,7 +234,7 @@ const jsonToBruViaWorker = async (json) => {
|
|||||||
meta: {
|
meta: {
|
||||||
name: _.get(json, 'name'),
|
name: _.get(json, 'name'),
|
||||||
type: type,
|
type: type,
|
||||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
seq: !_.isNaN(sequence) ? Number(sequence) : 1
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
method: _.lowerCase(_.get(json, 'request.method')),
|
method: _.lowerCase(_.get(json, 'request.method')),
|
||||||
|
|||||||
@@ -213,8 +213,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
|||||||
|
|
||||||
if (!folderRoot.meta) {
|
if (!folderRoot.meta) {
|
||||||
folderRoot.meta = {
|
folderRoot.meta = {
|
||||||
name: folderName,
|
name: folderName
|
||||||
seq: 1
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,8 +399,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
|||||||
} else {
|
} else {
|
||||||
folderBruFileJsonContent = {
|
folderBruFileJsonContent = {
|
||||||
meta: {
|
meta: {
|
||||||
name: newName,
|
name: newName
|
||||||
seq: 1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -451,8 +449,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
|||||||
} else {
|
} else {
|
||||||
folderBruFileJsonContent = {
|
folderBruFileJsonContent = {
|
||||||
meta: {
|
meta: {
|
||||||
name: newName,
|
name: newName
|
||||||
seq: 1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -526,20 +523,14 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
|||||||
});
|
});
|
||||||
|
|
||||||
// new folder
|
// new folder
|
||||||
ipcMain.handle('renderer:new-folder', async (event, pathname, folderName) => {
|
ipcMain.handle('renderer:new-folder', async (event, { pathname, folderBruJsonData }) => {
|
||||||
const resolvedFolderName = sanitizeName(path.basename(pathname));
|
const resolvedFolderName = sanitizeName(path.basename(pathname));
|
||||||
pathname = path.join(path.dirname(pathname), resolvedFolderName);
|
pathname = path.join(path.dirname(pathname), resolvedFolderName);
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(pathname)) {
|
if (!fs.existsSync(pathname)) {
|
||||||
fs.mkdirSync(pathname);
|
fs.mkdirSync(pathname);
|
||||||
const folderBruFilePath = path.join(pathname, 'folder.bru');
|
const folderBruFilePath = path.join(pathname, 'folder.bru');
|
||||||
let data = {
|
const content = await jsonToCollectionBru(folderBruJsonData, true); // isFolder flag
|
||||||
meta: {
|
|
||||||
name: folderName,
|
|
||||||
seq: 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const content = await jsonToCollectionBru(data, true); // isFolder flag
|
|
||||||
await writeFile(folderBruFilePath, content);
|
await writeFile(folderBruFilePath, content);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new Error('The directory already exists'));
|
return Promise.reject(new Error('The directory already exists'));
|
||||||
@@ -762,8 +753,8 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
|||||||
const folderRootPath = path.join(item.pathname, 'folder.bru');
|
const folderRootPath = path.join(item.pathname, 'folder.bru');
|
||||||
let folderBruJsonData = {
|
let folderBruJsonData = {
|
||||||
meta: {
|
meta: {
|
||||||
name: path.basename(item?.pathname),
|
name: path.basename(item.pathname),
|
||||||
seq: item?.seq || 1
|
seq: item.seq
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (fs.existsSync(folderRootPath)) {
|
if (fs.existsSync(folderRootPath)) {
|
||||||
@@ -771,8 +762,8 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
|||||||
folderBruJsonData = await collectionBruToJson(bru);
|
folderBruJsonData = await collectionBruToJson(bru);
|
||||||
if (!folderBruJsonData?.meta) {
|
if (!folderBruJsonData?.meta) {
|
||||||
folderBruJsonData.meta = {
|
folderBruJsonData.meta = {
|
||||||
name: path.basename(item?.pathname),
|
name: path.basename(item.pathname),
|
||||||
seq: item?.seq || 1
|
seq: item.seq
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (folderBruJsonData?.meta?.seq === item.seq) {
|
if (folderBruJsonData?.meta?.seq === item.seq) {
|
||||||
|
|||||||
@@ -24,9 +24,8 @@ const { uuid, safeStringifyJSON, safeParseJSON, parseDataFromResponse, parseData
|
|||||||
const { chooseFileToSave, writeBinaryFile, writeFile } = require('../../utils/filesystem');
|
const { chooseFileToSave, writeBinaryFile, writeFile } = require('../../utils/filesystem');
|
||||||
const { addCookieToJar, getDomainsWithCookies, getCookieStringForUrl } = require('../../utils/cookies');
|
const { addCookieToJar, getDomainsWithCookies, getCookieStringForUrl } = require('../../utils/cookies');
|
||||||
const { createFormData } = require('../../utils/form-data');
|
const { createFormData } = require('../../utils/form-data');
|
||||||
const { findItemInCollectionByPathname, sortFolder, getAllRequestsInFolderRecursively, getEnvVars, getTreePathFromCollectionToItem, mergeVars } = require('../../utils/collection');
|
const { findItemInCollectionByPathname, sortFolder, getAllRequestsInFolderRecursively, getEnvVars, getTreePathFromCollectionToItem, mergeVars, sortByNameThenSequence } = require('../../utils/collection');
|
||||||
const { getOAuth2TokenUsingAuthorizationCode, getOAuth2TokenUsingClientCredentials, getOAuth2TokenUsingPasswordCredentials, getOAuth2TokenUsingImplicitGrant } = require('../../utils/oauth2');
|
const { getOAuth2TokenUsingAuthorizationCode, getOAuth2TokenUsingClientCredentials, getOAuth2TokenUsingPasswordCredentials, getOAuth2TokenUsingImplicitGrant } = require('../../utils/oauth2');
|
||||||
const { setupProxyAgents } = require('../../utils/proxy-util');
|
|
||||||
const { preferencesUtil } = require('../../store/preferences');
|
const { preferencesUtil } = require('../../store/preferences');
|
||||||
const { getProcessEnvVars } = require('../../store/process-env');
|
const { getProcessEnvVars } = require('../../store/process-env');
|
||||||
const { getBrunoConfig } = require('../../store/bruno-config');
|
const { getBrunoConfig } = require('../../store/bruno-config');
|
||||||
@@ -1003,10 +1002,9 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// sort requests by seq property
|
// sort requests by seq property
|
||||||
folderRequests.sort((a, b) => {
|
folderRequests = sortByNameThenSequence(folderRequests)
|
||||||
return a.seq - b.seq;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentRequestIndex = 0;
|
let currentRequestIndex = 0;
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ const sortCollection = (collection) => {
|
|||||||
let folderItems = filter(items, (item) => item.type === 'folder');
|
let folderItems = filter(items, (item) => item.type === 'folder');
|
||||||
let requestItems = filter(items, (item) => item.type !== 'folder');
|
let requestItems = filter(items, (item) => item.type !== 'folder');
|
||||||
|
|
||||||
folderItems = folderItems.sort((a, b) => a.seq - b.seq);
|
folderItems = sortByNameThenSequence(folderItems);
|
||||||
requestItems = requestItems.sort((a, b) => a.seq - b.seq);
|
requestItems = requestItems.sort((a, b) => a.seq - b.seq);
|
||||||
|
|
||||||
collection.items = folderItems.concat(requestItems);
|
collection.items = folderItems.concat(requestItems);
|
||||||
@@ -361,7 +361,7 @@ const sortFolder = (folder = {}) => {
|
|||||||
let folderItems = filter(items, (item) => item.type === 'folder');
|
let folderItems = filter(items, (item) => item.type === 'folder');
|
||||||
let requestItems = filter(items, (item) => item.type !== 'folder');
|
let requestItems = filter(items, (item) => item.type !== 'folder');
|
||||||
|
|
||||||
folderItems = folderItems.sort((a, b) => a.seq - b.seq);
|
folderItems = sortByNameThenSequence(folderItems);
|
||||||
requestItems = requestItems.sort((a, b) => a.seq - b.seq);
|
requestItems = requestItems.sort((a, b) => a.seq - b.seq);
|
||||||
|
|
||||||
folder.items = folderItems.concat(requestItems);
|
folder.items = folderItems.concat(requestItems);
|
||||||
@@ -467,6 +467,47 @@ const mergeAuth = (collection, request, requestTreePath) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sortByNameThenSequence = items => {
|
||||||
|
const isSeqValid = seq => Number.isFinite(seq) && Number.isInteger(seq) && seq > 0;
|
||||||
|
|
||||||
|
// Sort folders alphabetically by name
|
||||||
|
const alphabeticallySorted = [...items].sort((a, b) => a.name && b.name && a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
// Extract folders without 'seq'
|
||||||
|
const withoutSeq = alphabeticallySorted.filter(f => !isSeqValid(f['seq']));
|
||||||
|
|
||||||
|
// Extract folders with 'seq' and sort them by 'seq'
|
||||||
|
const withSeq = alphabeticallySorted.filter(f => isSeqValid(f['seq'])).sort((a, b) => a.seq - b.seq);
|
||||||
|
|
||||||
|
const sortedItems = withoutSeq;
|
||||||
|
|
||||||
|
// Insert folders with 'seq' at their specified positions
|
||||||
|
withSeq.forEach((item) => {
|
||||||
|
const position = item.seq - 1;
|
||||||
|
const existingItem = withoutSeq[position];
|
||||||
|
|
||||||
|
// Check if there's already an item with the same sequence number
|
||||||
|
const hasItemWithSameSeq = Array.isArray(existingItem)
|
||||||
|
? existingItem[0].seq === item.seq
|
||||||
|
: existingItem?.seq === item.seq;
|
||||||
|
|
||||||
|
if (hasItemWithSameSeq) {
|
||||||
|
// If there's a conflict, group items with same sequence together
|
||||||
|
const newGroup = Array.isArray(existingItem)
|
||||||
|
? [...existingItem, item]
|
||||||
|
: [existingItem, item];
|
||||||
|
|
||||||
|
withoutSeq.splice(position, 1, newGroup);
|
||||||
|
} else {
|
||||||
|
// Insert item at the specified position
|
||||||
|
withoutSeq.splice(position, 0, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// return flattened sortedItems
|
||||||
|
return sortedItems.flat();
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mergeHeaders,
|
mergeHeaders,
|
||||||
mergeVars,
|
mergeVars,
|
||||||
@@ -487,5 +528,6 @@ module.exports = {
|
|||||||
sortFolder,
|
sortFolder,
|
||||||
getAllRequestsInFolderRecursively,
|
getAllRequestsInFolderRecursively,
|
||||||
getEnvVars,
|
getEnvVars,
|
||||||
getFormattedCollectionOauth2Credentials
|
getFormattedCollectionOauth2Credentials,
|
||||||
|
sortByNameThenSequence
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user