mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
Card order by date modified (#3170)
Co-authored-by: Dimitri Mitropoulos <dimitrimitropoulos@gmail.com> Co-authored-by: Opender Singh <opender.singh@konghq.com>
This commit is contained in:
parent
f1539e2b40
commit
84b9b84fdf
@ -1,6 +1,6 @@
|
||||
import * as misc from '../misc';
|
||||
import { globalBeforeEach } from '../../__jest__/before-each';
|
||||
import { diffPatchObj, pluralize, snapNumberToLimits } from '../misc';
|
||||
import { diffPatchObj, isNotNullOrUndefined, pluralize, snapNumberToLimits } from '../misc';
|
||||
|
||||
describe('hasAuthHeader()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
@ -271,3 +271,14 @@ describe('snapNumberToLimits()', () => {
|
||||
expect(snapNumberToLimits(5, NaN, 3)).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNotNullOrUndefined', () => {
|
||||
it('should return correctly', () => {
|
||||
expect(isNotNullOrUndefined(0)).toBe(true);
|
||||
expect(isNotNullOrUndefined('')).toBe(true);
|
||||
expect(isNotNullOrUndefined(false)).toBe(true);
|
||||
|
||||
expect(isNotNullOrUndefined(null)).toBe(false);
|
||||
expect(isNotNullOrUndefined(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { metaSortKeySort, sortMethodMap } from '../sorting';
|
||||
import {
|
||||
ascendingNumberSort,
|
||||
descendingNumberSort,
|
||||
metaSortKeySort,
|
||||
sortMethodMap,
|
||||
} from '../sorting';
|
||||
import { request, requestGroup, grpcRequest } from '../../models';
|
||||
import {
|
||||
METHOD_DELETE,
|
||||
@ -340,4 +345,16 @@ describe('Sorting methods', () => {
|
||||
expect(metaSortKeySort({ metaSortKey: 1, _id: 2 }, { metaSortKey: 1, _id: 1 })).toBe(-1);
|
||||
expect(metaSortKeySort({ metaSortKey: 1, _id: 1 }, { metaSortKey: 1, _id: 2 })).toBe(1);
|
||||
});
|
||||
|
||||
it('sorts by number', () => {
|
||||
expect(ascendingNumberSort(1, 2)).toBe(-1);
|
||||
expect(ascendingNumberSort(-2, 1)).toBe(-1);
|
||||
expect(ascendingNumberSort(2, 1)).toBe(1);
|
||||
expect(ascendingNumberSort(1, -2)).toBe(1);
|
||||
|
||||
expect(descendingNumberSort(1, 2)).toBe(1);
|
||||
expect(descendingNumberSort(-2, 1)).toBe(1);
|
||||
expect(descendingNumberSort(2, 1)).toBe(-1);
|
||||
expect(descendingNumberSort(1, -2)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
@ -453,3 +453,7 @@ export function snapNumberToLimits(value: number, min?: number, max?: number): n
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function isNotNullOrUndefined(obj: any): boolean {
|
||||
return obj !== null && obj !== undefined;
|
||||
}
|
||||
|
@ -97,6 +97,14 @@ export const metaSortKeySort: SortFunction = (a, b) => {
|
||||
return a.metaSortKey < b.metaSortKey ? -1 : 1;
|
||||
};
|
||||
|
||||
export const ascendingNumberSort = (a: number, b: number): number => {
|
||||
return a < b ? -1 : 1;
|
||||
};
|
||||
|
||||
export const descendingNumberSort = (a: number, b: number): number => {
|
||||
return ascendingNumberSort(b, a);
|
||||
};
|
||||
|
||||
export const sortMethodMap: { [SortOrder]: SortFunction } = {
|
||||
[SORT_NAME_ASC]: ascendingNameSort,
|
||||
[SORT_NAME_DESC]: descendingNameSort,
|
||||
|
@ -19,6 +19,7 @@ import HelpTooltip from '../help-tooltip';
|
||||
import Link from '../base/link';
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { docsGitSync } from '../../../common/documentation';
|
||||
import { isNotNullOrUndefined } from '../../../common/misc';
|
||||
|
||||
type Props = {|
|
||||
handleInitializeEntities: () => Promise<void>,
|
||||
@ -68,11 +69,20 @@ class GitSyncDropdown extends React.PureComponent<Props, State> {
|
||||
|
||||
// Clear cached items and return if no state
|
||||
if (!vcs.isInitialized() || !workspaceMeta.gitRepositoryId) {
|
||||
await models.workspaceMeta.updateByParentId(workspace._id, {
|
||||
cachedGitRepositoryBranch: null,
|
||||
cachedGitLastAuthor: null,
|
||||
cachedGitLastCommitTime: null,
|
||||
});
|
||||
// Don't update unnecessarily
|
||||
const needsUpdate = [
|
||||
workspaceMeta.cachedGitRepositoryBranch,
|
||||
workspaceMeta.cachedGitLastAuthor,
|
||||
workspaceMeta.cachedGitLastCommitTime,
|
||||
].some(isNotNullOrUndefined);
|
||||
|
||||
if (needsUpdate) {
|
||||
await models.workspaceMeta.updateByParentId(workspace._id, {
|
||||
cachedGitRepositoryBranch: null,
|
||||
cachedGitLastAuthor: null,
|
||||
cachedGitLastCommitTime: null,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ import TimeFromNow from './time-from-now';
|
||||
import Highlight from './base/highlight';
|
||||
import type { GlobalActivity } from '../../common/constants';
|
||||
|
||||
import { fuzzyMatchAll, pluralize } from '../../common/misc';
|
||||
import { fuzzyMatchAll, isNotNullOrUndefined, pluralize } from '../../common/misc';
|
||||
import type {
|
||||
HandleImportClipboardCallback,
|
||||
HandleImportFileCallback,
|
||||
@ -60,6 +60,8 @@ import RemoteWorkspacesDropdown from './dropdowns/remote-workspaces-dropdown';
|
||||
import SettingsButton from './buttons/settings-button';
|
||||
import AccountDropdown from './dropdowns/account-dropdown';
|
||||
import { strings } from '../../common/strings';
|
||||
import { WorkspaceScopeKeys } from '../../models/workspace';
|
||||
import { descendingNumberSort } from '../../common/sorting';
|
||||
|
||||
type Props = {|
|
||||
wrapperProps: WrapperProps,
|
||||
@ -316,7 +318,6 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
const { activeActivity } = await models.workspaceMeta.getOrCreateByParentId(id);
|
||||
|
||||
if (!activeActivity || !isWorkspaceActivity(activeActivity)) {
|
||||
// or migration or onboarding
|
||||
handleSetActiveActivity(defaultActivity);
|
||||
} else {
|
||||
handleSetActiveActivity(activeActivity);
|
||||
@ -324,7 +325,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
handleSetActiveWorkspace(id);
|
||||
}
|
||||
|
||||
renderCard(w: Workspace) {
|
||||
renderCard(workspace: Workspace): { card: React.Node, lastModifiedTimestamp: number } {
|
||||
const {
|
||||
apiSpecs,
|
||||
handleSetActiveWorkspace,
|
||||
@ -334,7 +335,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
|
||||
const { filter } = this.state;
|
||||
|
||||
const apiSpec = apiSpecs.find(s => s.parentId === w._id);
|
||||
const apiSpec = apiSpecs.find(s => s.parentId === workspace._id);
|
||||
|
||||
let spec = null;
|
||||
let specFormat = null;
|
||||
@ -350,18 +351,25 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
// Get cached branch from WorkspaceMeta
|
||||
const workspaceMeta = workspaceMetas.find(wm => wm.parentId === w._id);
|
||||
const workspaceMeta = workspaceMetas.find(wm => wm.parentId === workspace._id);
|
||||
const lastActiveBranch = workspaceMeta ? workspaceMeta.cachedGitRepositoryBranch : null;
|
||||
const lastCommitAuthor = workspaceMeta ? workspaceMeta.cachedGitLastAuthor : null;
|
||||
const lastCommitTime = workspaceMeta ? workspaceMeta.cachedGitLastCommitTime : null;
|
||||
|
||||
// WorkspaceMeta is a good proxy for last modified time
|
||||
const workspaceModified = workspaceMeta ? workspaceMeta.modified : w.modified;
|
||||
const modifiedLocally = apiSpec ? apiSpec.modified : workspaceModified;
|
||||
const workspaceModified = workspaceMeta ? workspaceMeta.modified : workspace.modified;
|
||||
const modifiedLocally =
|
||||
apiSpec && workspace.scope === WorkspaceScopeKeys.designer
|
||||
? apiSpec.modified
|
||||
: workspaceModified;
|
||||
|
||||
let log = <TimeFromNow timestamp={modifiedLocally} />;
|
||||
let branch = lastActiveBranch;
|
||||
if (w.scope === 'designer' && lastCommitTime && apiSpec?.modified > lastCommitTime) {
|
||||
if (
|
||||
workspace.scope === WorkspaceScopeKeys.designer &&
|
||||
lastCommitTime &&
|
||||
apiSpec?.modified > lastCommitTime
|
||||
) {
|
||||
// Show locally unsaved changes for spec
|
||||
// NOTE: this doesn't work for non-spec workspaces
|
||||
branch = lastActiveBranch + '*';
|
||||
@ -383,7 +391,7 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
const docMenu = (
|
||||
<DocumentCardDropdown
|
||||
apiSpec={apiSpec}
|
||||
workspace={w}
|
||||
workspace={workspace}
|
||||
handleSetActiveWorkspace={handleSetActiveWorkspace}
|
||||
isLastWorkspace={workspaces.length === 1}>
|
||||
<SvgIcon icon="ellipsis" />
|
||||
@ -394,9 +402,9 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
let format: string = '';
|
||||
let labelIcon = <i className="fa fa-bars" />;
|
||||
let defaultActivity = ACTIVITY_DEBUG;
|
||||
let title = w.name;
|
||||
let title = workspace.name;
|
||||
|
||||
if (w.scope === 'designer') {
|
||||
if (workspace.scope === WorkspaceScopeKeys.designer) {
|
||||
label = 'Document';
|
||||
labelIcon = <i className="fa fa-file-o" />;
|
||||
if (specFormat === 'openapi') {
|
||||
@ -421,7 +429,17 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
const lastModifiedFrom = [
|
||||
workspace?.modified,
|
||||
workspaceMeta?.modified,
|
||||
apiSpec?.modified,
|
||||
workspaceMeta?.cachedGitLastCommitTime,
|
||||
];
|
||||
const lastModifiedTimestamp = lastModifiedFrom
|
||||
.filter(isNotNullOrUndefined)
|
||||
.sort(descendingNumberSort)[0];
|
||||
|
||||
const card = (
|
||||
<Card
|
||||
key={apiSpec._id}
|
||||
docBranch={branch && <Highlight search={filter} text={branch} />}
|
||||
@ -438,9 +456,14 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
docLog={log}
|
||||
docMenu={docMenu}
|
||||
docFormat={format}
|
||||
onClick={() => this._handleClickCard(w._id, defaultActivity)}
|
||||
onClick={() => this._handleClickCard(workspace._id, defaultActivity)}
|
||||
/>
|
||||
);
|
||||
|
||||
return {
|
||||
card,
|
||||
lastModifiedTimestamp,
|
||||
};
|
||||
}
|
||||
|
||||
renderCreateMenu() {
|
||||
@ -508,7 +531,11 @@ class WrapperHome extends React.PureComponent<Props, State> {
|
||||
const { filter } = this.state;
|
||||
|
||||
// Render each card, removing all the ones that don't match the filter
|
||||
const cards = workspaces.map(this.renderCard).filter(c => c !== null);
|
||||
const cards = workspaces
|
||||
.map(this.renderCard)
|
||||
.filter(isNotNullOrUndefined)
|
||||
.sort((a, b) => descendingNumberSort(a.lastModifiedTimestamp, b.lastModifiedTimestamp))
|
||||
.map(c => c.card);
|
||||
|
||||
const countLabel = cards.length > 1 ? pluralize(strings.document) : strings.document;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user