mirror of
https://github.com/Kong/insomnia.git
synced 2026-04-22 15:18:27 -04:00
Force refresh cleanup (#5184)
* remove forceRefreshCounter from app.tsx * simplify refresh counter for ws request pane * remove forceRefreshKey from remaining panes * remove unused nunjucks key * cleanup forceUpdate drills * undrill handleSetActiveResponse * put restore back in * more uniqueness Co-authored-by: jackkav <jackkav@gmail.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import { database as db } from '../common/database';
|
||||
import { database as db, Query } from '../common/database';
|
||||
import * as requestOperations from './helpers/request-operations';
|
||||
import type { BaseModel } from './index';
|
||||
import * as models from './index';
|
||||
@@ -144,6 +144,32 @@ export async function create(patch: Partial<WebSocketResponse> = {}, maxResponse
|
||||
return db.docCreate(type, patch);
|
||||
}
|
||||
|
||||
async function _findRecentForRequest(
|
||||
requestId: string,
|
||||
environmentId: string | null,
|
||||
limit: number,
|
||||
) {
|
||||
const query: Query = {
|
||||
parentId: requestId,
|
||||
};
|
||||
|
||||
// Filter responses by environment if setting is enabled
|
||||
if ((await models.settings.getOrCreate()).filterResponsesByEnv) {
|
||||
query.environmentId = environmentId;
|
||||
}
|
||||
|
||||
return db.findMostRecentlyModified<WebSocketResponse>(type, query, limit);
|
||||
}
|
||||
|
||||
export async function getLatestForRequest(
|
||||
requestId: string,
|
||||
environmentId: string | null,
|
||||
) {
|
||||
const responses = await _findRecentForRequest(requestId, environmentId, 1);
|
||||
const response = responses[0] as WebSocketResponse | null | undefined;
|
||||
return response || null;
|
||||
}
|
||||
|
||||
export function getLatestByParentId(parentId: string) {
|
||||
return db.getMostRecentlyModified<WebSocketResponse>(type, {
|
||||
parentId,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { decompressObject } from '../../../common/misc';
|
||||
import * as models from '../../../models/index';
|
||||
import { Response } from '../../../models/response';
|
||||
import { isWebSocketResponse, WebSocketResponse } from '../../../models/websocket-response';
|
||||
import { updateRequestMetaByParentId } from '../../hooks/create-request';
|
||||
import { selectActiveEnvironment, selectActiveRequest, selectActiveRequestResponses, selectRequestVersions } from '../../redux/selectors';
|
||||
import { type DropdownHandle, Dropdown } from '../base/dropdown/dropdown';
|
||||
import { DropdownButton } from '../base/dropdown/dropdown-button';
|
||||
@@ -23,14 +24,12 @@ import { TimeFromNow } from '../time-from-now';
|
||||
|
||||
interface Props<GenericResponse extends Response | WebSocketResponse> {
|
||||
activeResponse: GenericResponse;
|
||||
handleSetActiveResponse: (requestId: string, activeResponse: GenericResponse | null) => void;
|
||||
className?: string;
|
||||
requestId: string;
|
||||
}
|
||||
|
||||
export const ResponseHistoryDropdown = <GenericResponse extends Response | WebSocketResponse>({
|
||||
activeResponse,
|
||||
handleSetActiveResponse,
|
||||
className,
|
||||
requestId,
|
||||
}: Props<GenericResponse>) => {
|
||||
@@ -48,29 +47,53 @@ export const ResponseHistoryDropdown = <GenericResponse extends Response | WebSo
|
||||
other: [],
|
||||
};
|
||||
|
||||
const handleSetActiveResponse = useCallback(async (requestId: string, activeResponse: Response | WebSocketResponse) => {
|
||||
if (isWebSocketResponse(activeResponse)) {
|
||||
window.main.webSocket.close({ requestId });
|
||||
}
|
||||
|
||||
if (activeResponse.requestVersionId) {
|
||||
await models.requestVersion.restore(activeResponse.requestVersionId);
|
||||
}
|
||||
|
||||
await updateRequestMetaByParentId(requestId, { activeResponseId: activeResponse._id });
|
||||
}, []);
|
||||
|
||||
const handleDeleteResponses = useCallback(async () => {
|
||||
const environmentId = activeEnvironment ? activeEnvironment._id : null;
|
||||
if (isWebSocketResponse(activeResponse)) {
|
||||
window.main.webSocket.closeAll();
|
||||
await models.webSocketResponse.removeForRequest(requestId, environmentId);
|
||||
} else {
|
||||
await models.response.removeForRequest(requestId, environmentId);
|
||||
}
|
||||
|
||||
if (activeRequest && activeRequest._id === requestId) {
|
||||
handleSetActiveResponse(requestId, null);
|
||||
await updateRequestMetaByParentId(requestId, { activeResponseId: null });
|
||||
}
|
||||
}, [activeEnvironment, activeRequest, activeResponse, handleSetActiveResponse, requestId]);
|
||||
}, [activeEnvironment, activeRequest, activeResponse, requestId]);
|
||||
|
||||
const handleDeleteResponse = useCallback(async () => {
|
||||
let response: Response | WebSocketResponse | null = null;
|
||||
if (activeResponse) {
|
||||
if (isWebSocketResponse(activeResponse)) {
|
||||
window.main.webSocket.close({ requestId });
|
||||
await models.webSocketResponse.remove(activeResponse);
|
||||
const environmentId = activeEnvironment?._id || null;
|
||||
response = await models.webSocketResponse.getLatestForRequest(requestId, environmentId);
|
||||
} else {
|
||||
await models.response.remove(activeResponse);
|
||||
const environmentId = activeEnvironment?._id || null;
|
||||
response = await models.response.getLatestForRequest(requestId, environmentId);
|
||||
}
|
||||
|
||||
if (response?.requestVersionId) {
|
||||
// Deleting a response restores latest request body
|
||||
await models.requestVersion.restore(response.requestVersionId);
|
||||
}
|
||||
|
||||
await updateRequestMetaByParentId(requestId, { activeResponseId: response?._id || null });
|
||||
}
|
||||
handleSetActiveResponse(requestId, null);
|
||||
}, [activeResponse, handleSetActiveResponse, requestId]);
|
||||
}, [activeEnvironment?._id, activeResponse, requestId]);
|
||||
|
||||
responses.forEach(response => {
|
||||
const responseTime = new Date(response.created);
|
||||
@@ -103,6 +126,7 @@ export const ResponseHistoryDropdown = <GenericResponse extends Response | WebSo
|
||||
const active = response._id === activeResponseId;
|
||||
const requestVersion = requestVersions.find(({ _id }) => _id === response.requestVersionId);
|
||||
const request = requestVersion ? decompressObject(requestVersion.compressedRequest) : null;
|
||||
|
||||
return (
|
||||
<DropdownItem
|
||||
key={response._id}
|
||||
|
||||
@@ -12,11 +12,10 @@ import {
|
||||
} from '../../../../common/constants';
|
||||
import { documentationLinks } from '../../../../common/documentation';
|
||||
import { getContentTypeHeader } from '../../../../common/misc';
|
||||
import { update } from '../../../../models/helpers/request-operations';
|
||||
import * as models from '../../../../models';
|
||||
import type {
|
||||
Request,
|
||||
RequestBodyParameter,
|
||||
RequestHeader,
|
||||
} from '../../../../models/request';
|
||||
import {
|
||||
newBodyFile,
|
||||
@@ -37,7 +36,6 @@ import { RawEditor } from './raw-editor';
|
||||
import { UrlEncodedEditor } from './url-encoded-editor';
|
||||
|
||||
interface Props {
|
||||
onChangeHeaders: (r: Request, headers: RequestHeader[]) => Promise<Request>;
|
||||
request: Request;
|
||||
workspace: Workspace;
|
||||
settings: Settings;
|
||||
@@ -45,7 +43,6 @@ interface Props {
|
||||
}
|
||||
|
||||
export const BodyEditor: FC<Props> = ({
|
||||
onChangeHeaders,
|
||||
request,
|
||||
workspace,
|
||||
settings,
|
||||
@@ -54,28 +51,28 @@ export const BodyEditor: FC<Props> = ({
|
||||
const handleRawChange = useCallback((rawValue: string) => {
|
||||
const oldContentType = request.body.mimeType || '';
|
||||
const body = newBodyRaw(rawValue, oldContentType);
|
||||
update(request, { body });
|
||||
models.request.update(request, { body });
|
||||
}, [request]);
|
||||
|
||||
const handleGraphQLChange = useCallback((content: string) => {
|
||||
const body = newBodyRaw(content, CONTENT_TYPE_GRAPHQL);
|
||||
update(request, { body });
|
||||
models.request.update(request, { body });
|
||||
}, [request]);
|
||||
|
||||
const handleFormUrlEncodedChange = useCallback((parameters: RequestBodyParameter[]) => {
|
||||
const body = newBodyFormUrlEncoded(parameters);
|
||||
update(request, { body });
|
||||
models.request.update(request, { body });
|
||||
}, [request]);
|
||||
|
||||
const handleFormChange = useCallback((parameters: RequestBodyParameter[]) => {
|
||||
const body = newBodyForm(parameters);
|
||||
update(request, { body });
|
||||
models.request.update(request, { body });
|
||||
}, [request]);
|
||||
|
||||
const handleFileChange = async (path: string) => {
|
||||
const headers = clone(request.headers);
|
||||
const body = newBodyFile(path);
|
||||
const newRequest = await update(request, { body });
|
||||
const newRequest = await models.request.update(request, { body });
|
||||
let contentTypeHeader = getContentTypeHeader(headers);
|
||||
|
||||
if (!contentTypeHeader) {
|
||||
@@ -100,7 +97,7 @@ export const BodyEditor: FC<Props> = ({
|
||||
</p>,
|
||||
onDone: (saidYes: boolean) => {
|
||||
if (saidYes) {
|
||||
onChangeHeaders(newRequest, headers);
|
||||
models.request.update(newRequest, { headers });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -11,7 +11,6 @@ import { TagEditor } from '../templating/tag-editor';
|
||||
import { VariableEditor } from '../templating/variable-editor';
|
||||
|
||||
interface Props {
|
||||
uniqueKey: string;
|
||||
workspace: Workspace;
|
||||
}
|
||||
|
||||
@@ -66,7 +65,7 @@ export class NunjucksModal extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { uniqueKey, workspace } = this.props;
|
||||
const { workspace } = this.props;
|
||||
const { defaultTemplate } = this.state;
|
||||
let editor: JSX.Element | null = null;
|
||||
let title = '';
|
||||
@@ -80,7 +79,7 @@ export class NunjucksModal extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef} onHide={this._handleModalHide} key={uniqueKey}>
|
||||
<Modal ref={this._setModalRef} onHide={this._handleModalHide}>
|
||||
<ModalHeader>Edit {title}</ModalHeader>
|
||||
<ModalBody className="pad" key={defaultTemplate}>
|
||||
<form onSubmit={this._handleSubmit}>{editor}</form>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SvgIcon } from 'insomnia-components';
|
||||
import React, { FunctionComponent, useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@@ -10,6 +11,8 @@ import { executeHotKey } from '../../../../common/hotkeys-listener';
|
||||
import type { GrpcRequest } from '../../../../models/grpc-request';
|
||||
import type { Settings } from '../../../../models/settings';
|
||||
import { useGrpc } from '../../../context/grpc';
|
||||
import { useActiveRequestSyncVCSVersion, useGitVCSVersion } from '../../../hooks/use-vcs-version';
|
||||
import { selectActiveEnvironment } from '../../../redux/selectors';
|
||||
import { GrpcSendButton } from '../../buttons/grpc-send-button';
|
||||
import { OneLineEditor } from '../../codemirror/one-line-editor';
|
||||
import { GrpcMethodDropdown } from '../../dropdowns/grpc-method-dropdown/grpc-method-dropdown';
|
||||
@@ -26,7 +29,6 @@ import useProtoFileReload from './use-proto-file-reload';
|
||||
import useSelectedMethod from './use-selected-method';
|
||||
|
||||
interface Props {
|
||||
forceRefreshKey: number;
|
||||
activeRequest: GrpcRequest;
|
||||
environmentId: string;
|
||||
workspaceId: string;
|
||||
@@ -55,7 +57,6 @@ export const GrpcRequestPane: FunctionComponent<Props> = ({
|
||||
activeRequest,
|
||||
environmentId,
|
||||
workspaceId,
|
||||
forceRefreshKey,
|
||||
}) => {
|
||||
const [state, dispatch] = useGrpc(activeRequest._id);
|
||||
const { requestMessages, running, methods } = state;
|
||||
@@ -66,9 +67,11 @@ export const GrpcRequestPane: FunctionComponent<Props> = ({
|
||||
// @ts-expect-error -- TSCONVERSION methodType can be undefined
|
||||
const handleAction = useActionHandlers(activeRequest._id, environmentId, methodType, dispatch);
|
||||
const getExistingGrpcUrls = useExistingGrpcUrls(workspaceId, activeRequest._id);
|
||||
// Used to refresh input fields to their default value when switching between requests.
|
||||
// This is a common pattern in this codebase.
|
||||
const uniquenessKey = `${forceRefreshKey}::${activeRequest._id}`;
|
||||
const gitVersion = useGitVCSVersion();
|
||||
const activeRequestSyncVersion = useActiveRequestSyncVCSVersion();
|
||||
const activeEnvironment = useSelector(selectActiveEnvironment);
|
||||
// Reset the response pane state when we switch requests, the environment gets modified, or the (Git|Sync)VCS version changes
|
||||
const uniquenessKey = `${activeEnvironment?.modified}::${activeRequest?._id}::${gitVersion}::${activeRequestSyncVersion}`;
|
||||
|
||||
const { start } = handleAction;
|
||||
const _handleKeyDown = useCallback((event: KeyboardEvent) => {
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import type { GrpcRequest } from '../../../models/grpc-request';
|
||||
import { useGrpcRequestState } from '../../context/grpc';
|
||||
import { useActiveRequestSyncVCSVersion, useGitVCSVersion } from '../../hooks/use-vcs-version';
|
||||
import { selectActiveEnvironment } from '../../redux/selectors';
|
||||
import { GrpcSpinner } from '../grpc-spinner';
|
||||
import { GrpcStatusTag } from '../tags/grpc-status-tag';
|
||||
import { GrpcTabbedMessages } from '../viewers/grpc-tabbed-messages';
|
||||
import { Pane, PaneBody, PaneHeader } from './pane';
|
||||
|
||||
interface Props {
|
||||
forceRefreshKey: number;
|
||||
activeRequest: GrpcRequest;
|
||||
}
|
||||
|
||||
export const GrpcResponsePane: FunctionComponent<Props> = ({ activeRequest, forceRefreshKey }) => {
|
||||
// Used to refresh input fields to their default value when switching between requests.
|
||||
// This is a common pattern in this codebase.
|
||||
const uniquenessKey = `${forceRefreshKey}::${activeRequest._id}`;
|
||||
export const GrpcResponsePane: FunctionComponent<Props> = ({ activeRequest }) => {
|
||||
const gitVersion = useGitVCSVersion();
|
||||
const activeRequestSyncVersion = useActiveRequestSyncVCSVersion();
|
||||
const activeEnvironment = useSelector(selectActiveEnvironment);
|
||||
// Force re-render when we switch requests, the environment gets modified, or the (Git|Sync)VCS version changes
|
||||
const uniquenessKey = `${activeEnvironment?.modified}::${activeRequest?._id}::${gitVersion}::${activeRequestSyncVersion}`;
|
||||
|
||||
const { responseMessages, status, error } = useGrpcRequestState(activeRequest._id);
|
||||
return (
|
||||
<Pane type="response">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import { deconstructQueryStringToParams, extractQueryStringFromUrl } from 'insomnia-url';
|
||||
import React, { FC, useCallback, useEffect, useRef } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
import { useMount } from 'react-use';
|
||||
|
||||
@@ -8,12 +9,11 @@ import { getContentTypeFromHeaders } from '../../../common/constants';
|
||||
import * as models from '../../../models';
|
||||
import { queryAllWorkspaceUrls } from '../../../models/helpers/query-all-workspace-urls';
|
||||
import { update } from '../../../models/helpers/request-operations';
|
||||
import type {
|
||||
Request,
|
||||
RequestHeader,
|
||||
} from '../../../models/request';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { Settings } from '../../../models/settings';
|
||||
import type { Workspace } from '../../../models/workspace';
|
||||
import { useActiveRequestSyncVCSVersion, useGitVCSVersion } from '../../hooks/use-vcs-version';
|
||||
import { selectActiveEnvironment, selectActiveRequestMeta } from '../../redux/selectors';
|
||||
import { AuthDropdown } from '../dropdowns/auth-dropdown';
|
||||
import { ContentTypeDropdown } from '../dropdowns/content-type-dropdown';
|
||||
import { AuthWrapper } from '../editors/auth/auth-wrapper';
|
||||
@@ -31,9 +31,6 @@ import { PlaceholderRequestPane } from './placeholder-request-pane';
|
||||
|
||||
interface Props {
|
||||
environmentId: string;
|
||||
forceRefreshCounter: number;
|
||||
forceUpdateRequest: (r: Request, patch: Partial<Request>) => Promise<Request>;
|
||||
forceUpdateRequestHeaders: (r: Request, headers: RequestHeader[]) => Promise<Request>;
|
||||
handleImport: Function;
|
||||
request?: Request | null;
|
||||
settings: Settings;
|
||||
@@ -42,9 +39,6 @@ interface Props {
|
||||
|
||||
export const RequestPane: FC<Props> = ({
|
||||
environmentId,
|
||||
forceRefreshCounter,
|
||||
forceUpdateRequest,
|
||||
forceUpdateRequestHeaders,
|
||||
handleImport,
|
||||
request,
|
||||
settings,
|
||||
@@ -99,12 +93,12 @@ export const RequestPane: FC<Props> = ({
|
||||
|
||||
// Only update if url changed
|
||||
if (url !== request.url) {
|
||||
forceUpdateRequest(request, {
|
||||
models.request.update(request, {
|
||||
url,
|
||||
parameters,
|
||||
});
|
||||
}
|
||||
}, [request, forceUpdateRequest]);
|
||||
}, [request]);
|
||||
|
||||
const requestUrlBarRef = useRef<RequestUrlBarHandle>(null);
|
||||
useMount(() => {
|
||||
@@ -116,6 +110,13 @@ export const RequestPane: FC<Props> = ({
|
||||
request?._id, // happens when the user switches requests
|
||||
settings.hasPromptedAnalytics, // happens when the user dismisses the analytics modal
|
||||
]);
|
||||
const gitVersion = useGitVCSVersion();
|
||||
const activeRequestSyncVersion = useActiveRequestSyncVCSVersion();
|
||||
const activeEnvironment = useSelector(selectActiveEnvironment);
|
||||
// const activeResponse = useSelector(selectActiveResponse);
|
||||
const activeRequestMeta = useSelector(selectActiveRequestMeta);
|
||||
// Force re-render when we switch requests, the environment gets modified, or the (Git|Sync)VCS version changes
|
||||
const uniqueKey = `${activeEnvironment?.modified}::${request?._id}::${gitVersion}::${activeRequestSyncVersion}::${activeRequestMeta?.activeResponseId}`;
|
||||
|
||||
if (!request) {
|
||||
return (
|
||||
@@ -139,7 +140,6 @@ export const RequestPane: FC<Props> = ({
|
||||
const numParameters = request.parameters.filter(p => !p.disabled).length;
|
||||
const numHeaders = request.headers.filter(h => !h.disabled).length;
|
||||
const urlHasQueryParameters = request.url.indexOf('?') >= 0;
|
||||
const uniqueKey = `${forceRefreshCounter}::${request._id}`;
|
||||
const contentType = getContentTypeFromHeaders(request.headers) || request.body.mimeType;
|
||||
return (
|
||||
<Pane type="request">
|
||||
@@ -195,7 +195,6 @@ export const RequestPane: FC<Props> = ({
|
||||
workspace={workspace}
|
||||
environmentId={environmentId}
|
||||
settings={settings}
|
||||
onChangeHeaders={forceUpdateRequestHeaders}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel scrollable-container">
|
||||
|
||||
@@ -33,12 +33,10 @@ import { PlaceholderResponsePane } from './placeholder-response-pane';
|
||||
|
||||
interface Props {
|
||||
handleSetFilter: (filter: string) => void;
|
||||
handleSetActiveResponse: (requestId: string, activeResponse: Response | null) => void;
|
||||
request?: Request | null;
|
||||
}
|
||||
export const ResponsePane: FC<Props> = ({
|
||||
handleSetFilter,
|
||||
handleSetActiveResponse,
|
||||
request,
|
||||
}) => {
|
||||
const response = useSelector(selectActiveResponse) as Response | null;
|
||||
@@ -135,7 +133,6 @@ export const ResponsePane: FC<Props> = ({
|
||||
</div>
|
||||
<ResponseHistoryDropdown
|
||||
activeResponse={response}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
requestId={request._id}
|
||||
className="tall pane__header__right"
|
||||
/>
|
||||
|
||||
@@ -6,9 +6,11 @@ import styled from 'styled-components';
|
||||
import { AuthType, CONTENT_TYPE_JSON } from '../../../common/constants';
|
||||
import { getRenderContext, render, RENDER_PURPOSE_SEND } from '../../../common/render';
|
||||
import * as models from '../../../models';
|
||||
import { Environment } from '../../../models/environment';
|
||||
import { WebSocketRequest } from '../../../models/websocket-request';
|
||||
import { ReadyState, useWSReadyState } from '../../context/websocket-client/use-ws-ready-state';
|
||||
import { selectSettings } from '../../redux/selectors';
|
||||
import { useActiveRequestSyncVCSVersion, useGitVCSVersion } from '../../hooks/use-vcs-version';
|
||||
import { selectActiveRequestMeta, selectSettings } from '../../redux/selectors';
|
||||
import { CodeEditor, UnconnectedCodeEditor } from '../codemirror/code-editor';
|
||||
import { AuthDropdown } from '../dropdowns/auth-dropdown';
|
||||
import { WebSocketPreviewModeDropdown } from '../dropdowns/websocket-preview-mode';
|
||||
@@ -152,15 +154,14 @@ const WebSocketRequestForm: FC<FormProps> = ({
|
||||
interface Props {
|
||||
request: WebSocketRequest;
|
||||
workspaceId: string;
|
||||
environmentId: string;
|
||||
forceRefreshKey: number;
|
||||
environment: Environment | null;
|
||||
}
|
||||
|
||||
// requestId is something we can read from the router params in the future.
|
||||
// essentially we can lift up the states and merge request pane and response pane into a single page and divide the UI there.
|
||||
// currently this is blocked by the way page layout divide the panes with dragging functionality
|
||||
// TODO: @gatzjames discuss above assertion in light of request and settings drills
|
||||
export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environmentId, forceRefreshKey }) => {
|
||||
export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environment }) => {
|
||||
const readyState = useWSReadyState(request._id);
|
||||
const { useBulkParametersEditor } = useSelector(selectSettings);
|
||||
|
||||
@@ -205,7 +206,12 @@ export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environm
|
||||
}
|
||||
};
|
||||
|
||||
const uniqueKey = `${forceRefreshKey}::${request._id}`;
|
||||
const gitVersion = useGitVCSVersion();
|
||||
const activeRequestSyncVersion = useActiveRequestSyncVCSVersion();
|
||||
const activeRequestMeta = useSelector(selectActiveRequestMeta);
|
||||
|
||||
// Reset the response pane state when we switch requests, the environment gets modified, or the (Git|Sync)VCS version changes
|
||||
const uniqueKey = `${environment?.modified}::${request?._id}::${gitVersion}::${activeRequestSyncVersion}::${activeRequestMeta?.activeResponseId}`;
|
||||
|
||||
return (
|
||||
<Pane type="request">
|
||||
@@ -214,7 +220,7 @@ export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environm
|
||||
key={uniqueKey}
|
||||
request={request}
|
||||
workspaceId={workspaceId}
|
||||
environmentId={environmentId}
|
||||
environmentId={environment?._id || ''}
|
||||
defaultValue={request.url}
|
||||
readyState={readyState}
|
||||
onChange={handleOnChange}
|
||||
@@ -249,12 +255,12 @@ export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environm
|
||||
key={uniqueKey}
|
||||
request={request}
|
||||
previewMode={previewMode}
|
||||
environmentId={environmentId}
|
||||
environmentId={environment?._id || ''}
|
||||
/>
|
||||
</PayloadTabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel">
|
||||
<AuthWrapper
|
||||
key={`${uniqueKey}-${request.authentication.type}-auth-header`}
|
||||
key={uniqueKey}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</TabPanel>
|
||||
@@ -285,7 +291,7 @@ export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environm
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel header-editor">
|
||||
<RequestHeadersEditor
|
||||
key={`${uniqueKey}-${readyState}-header-editor`}
|
||||
key={uniqueKey}
|
||||
request={request}
|
||||
bulk={false}
|
||||
isDisabled={readyState === ReadyState.OPEN}
|
||||
|
||||
@@ -48,10 +48,9 @@ const PaneBodyContent = styled.div({
|
||||
gridTemplateRows: 'repeat(auto-fit, minmax(0, 1fr))',
|
||||
});
|
||||
|
||||
export const WebSocketResponsePane: FC<{ requestId: string; handleSetActiveResponse: (requestId: string, activeResponse: WebSocketResponse | null) => void }> =
|
||||
export const WebSocketResponsePane: FC<{ requestId: string }> =
|
||||
({
|
||||
requestId,
|
||||
handleSetActiveResponse,
|
||||
}) => {
|
||||
const response = useSelector(selectActiveResponse) as WebSocketResponse | null;
|
||||
if (!response) {
|
||||
@@ -72,13 +71,12 @@ export const WebSocketResponsePane: FC<{ requestId: string; handleSetActiveRespo
|
||||
</Pane>
|
||||
);
|
||||
}
|
||||
return <WebSocketActiveResponsePane requestId={requestId} response={response} handleSetActiveResponse={handleSetActiveResponse} />;
|
||||
return <WebSocketActiveResponsePane requestId={requestId} response={response} />;
|
||||
};
|
||||
|
||||
const WebSocketActiveResponsePane: FC<{ requestId: string; response: WebSocketResponse; handleSetActiveResponse: (requestId: string, activeResponse: WebSocketResponse | null) => void }> = ({
|
||||
const WebSocketActiveResponsePane: FC<{ requestId: string; response: WebSocketResponse }> = ({
|
||||
requestId,
|
||||
response,
|
||||
handleSetActiveResponse,
|
||||
}) => {
|
||||
const [selectedEvent, setSelectedEvent] = useState<WebSocketEvent | null>(null);
|
||||
const [timeline, setTimeline] = useState<ResponseTimelineEntry[]>([]);
|
||||
@@ -87,11 +85,6 @@ const WebSocketActiveResponsePane: FC<{ requestId: string; response: WebSocketRe
|
||||
setSelectedEvent((selected: WebSocketEvent | null) => selected?._id === event._id ? null : event);
|
||||
};
|
||||
|
||||
const setActiveResponseAndDisconnect = (requestId: string, response: WebSocketResponse | null) => {
|
||||
handleSetActiveResponse(requestId, response);
|
||||
window.main.webSocket.close({ requestId });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedEvent(null);
|
||||
}, [response._id]);
|
||||
@@ -123,7 +116,6 @@ const WebSocketActiveResponsePane: FC<{ requestId: string; response: WebSocketRe
|
||||
</div>
|
||||
<ResponseHistoryDropdown
|
||||
activeResponse={response}
|
||||
handleSetActiveResponse={setActiveResponseAndDisconnect}
|
||||
requestId={requestId}
|
||||
className="tall pane__header__right"
|
||||
/>
|
||||
|
||||
@@ -3,10 +3,7 @@ import { useSelector } from 'react-redux';
|
||||
|
||||
import { isGrpcRequest } from '../../models/grpc-request';
|
||||
import { isRemoteProject } from '../../models/project';
|
||||
import { Request, RequestHeader } from '../../models/request';
|
||||
import type { Response } from '../../models/response';
|
||||
import { isWebSocketRequest } from '../../models/websocket-request';
|
||||
import { WebSocketResponse } from '../../models/websocket-response';
|
||||
import { isCollection, isDesign } from '../../models/workspace';
|
||||
import { VCS } from '../../sync/vcs/vcs';
|
||||
import {
|
||||
@@ -35,25 +32,17 @@ import { WorkspacePageHeader } from './workspace-page-header';
|
||||
import type { HandleActivityChange } from './wrapper';
|
||||
|
||||
interface Props {
|
||||
forceRefreshKey: number;
|
||||
gitSyncDropdown: ReactNode;
|
||||
handleActivityChange: HandleActivityChange;
|
||||
handleSetActiveEnvironment: (id: string | null) => void;
|
||||
handleSetActiveResponse: (requestId: string, activeResponse: Response | WebSocketResponse | null) => void;
|
||||
handleForceUpdateRequest: (r: Request, patch: Partial<Request>) => Promise<Request>;
|
||||
handleForceUpdateRequestHeaders: (r: Request, headers: RequestHeader[]) => Promise<Request>;
|
||||
handleImport: Function;
|
||||
handleSetResponseFilter: (filter: string) => void;
|
||||
vcs: VCS | null;
|
||||
}
|
||||
export const WrapperDebug: FC<Props> = ({
|
||||
forceRefreshKey,
|
||||
gitSyncDropdown,
|
||||
handleActivityChange,
|
||||
handleSetActiveEnvironment,
|
||||
handleSetActiveResponse,
|
||||
handleForceUpdateRequest,
|
||||
handleForceUpdateRequestHeaders,
|
||||
handleImport,
|
||||
handleSetResponseFilter,
|
||||
vcs,
|
||||
@@ -121,24 +110,18 @@ export const WrapperDebug: FC<Props> = ({
|
||||
activeRequest={activeRequest}
|
||||
environmentId={activeEnvironment ? activeEnvironment._id : ''}
|
||||
workspaceId={activeWorkspace._id}
|
||||
forceRefreshKey={forceRefreshKey}
|
||||
settings={settings}
|
||||
/>
|
||||
) : (
|
||||
isWebSocketRequest(activeRequest) ? (
|
||||
<WebSocketRequestPane
|
||||
key={activeRequest._id}
|
||||
request={activeRequest}
|
||||
workspaceId={activeWorkspace._id}
|
||||
environmentId={activeEnvironment ? activeEnvironment._id : ''}
|
||||
forceRefreshKey={forceRefreshKey}
|
||||
environment={activeEnvironment}
|
||||
/>
|
||||
) : (
|
||||
<RequestPane
|
||||
environmentId={activeEnvironment ? activeEnvironment._id : ''}
|
||||
forceRefreshCounter={forceRefreshKey}
|
||||
forceUpdateRequest={handleForceUpdateRequest}
|
||||
forceUpdateRequestHeaders={handleForceUpdateRequestHeaders}
|
||||
handleImport={handleImport}
|
||||
request={activeRequest}
|
||||
settings={settings}
|
||||
@@ -155,19 +138,16 @@ export const WrapperDebug: FC<Props> = ({
|
||||
isGrpcRequest(activeRequest) ? (
|
||||
<GrpcResponsePane
|
||||
activeRequest={activeRequest}
|
||||
forceRefreshKey={forceRefreshKey}
|
||||
/>
|
||||
) : (
|
||||
isWebSocketRequest(activeRequest) ? (
|
||||
<WebSocketResponsePane
|
||||
requestId={activeRequest._id}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
/>
|
||||
) : (
|
||||
<ResponsePane
|
||||
handleSetFilter={handleSetResponseFilter}
|
||||
request={activeRequest}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
/>
|
||||
)
|
||||
)
|
||||
|
||||
@@ -15,20 +15,15 @@ import {
|
||||
} from '../../common/constants';
|
||||
import { importRaw } from '../../common/import';
|
||||
import { initializeSpectral, isLintError } from '../../common/spectral';
|
||||
import { update } from '../../models/helpers/request-operations';
|
||||
import * as requestOperations from '../../models/helpers/request-operations';
|
||||
import * as models from '../../models/index';
|
||||
import {
|
||||
isRequest,
|
||||
Request,
|
||||
RequestHeader,
|
||||
} from '../../models/request';
|
||||
import { Response } from '../../models/response';
|
||||
import { WebSocketResponse } from '../../models/websocket-response';
|
||||
import { GitVCS } from '../../sync/git/git-vcs';
|
||||
import { VCS } from '../../sync/vcs/vcs';
|
||||
import { CookieModifyModal } from '../components/modals/cookie-modify-modal';
|
||||
import { GrpcDispatchModalWrapper } from '../context/grpc';
|
||||
import { updateRequestMetaByParentId } from '../hooks/create-request';
|
||||
import { RootState } from '../redux/modules';
|
||||
import { setActiveActivity } from '../redux/modules/global';
|
||||
import { selectActiveActivity, selectActiveApiSpec, selectActiveCookieJar, selectActiveEnvironment, selectActiveGitRepository, selectActiveRequest, selectActiveResponse, selectActiveWorkspace, selectActiveWorkspaceMeta, selectSettings } from '../redux/selectors';
|
||||
@@ -131,29 +126,15 @@ export type HandleActivityChange = (options: {
|
||||
}) => Promise<void>;
|
||||
|
||||
interface State {
|
||||
forceRefreshKey: number;
|
||||
activeGitBranch: string;
|
||||
}
|
||||
|
||||
@autoBindMethodsForReact(AUTOBIND_CFG)
|
||||
export class WrapperClass extends PureComponent<Props, State> {
|
||||
state: State = {
|
||||
forceRefreshKey: Date.now(),
|
||||
activeGitBranch: 'no-vcs',
|
||||
};
|
||||
|
||||
// Request updaters
|
||||
async _handleForceUpdateRequest(r: Request, patch: Partial<Request>) {
|
||||
const newRequest = await update(r, patch);
|
||||
this._forceRequestPaneRefreshAfterDelay();
|
||||
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
_handleForceUpdateRequestHeaders(r: Request, headers: RequestHeader[]) {
|
||||
return this._handleForceUpdateRequest(r, { headers });
|
||||
}
|
||||
|
||||
async _handleImport(text: string) {
|
||||
const { activeRequest } = this.props;
|
||||
|
||||
@@ -166,7 +147,7 @@ export class WrapperClass extends PureComponent<Props, State> {
|
||||
|
||||
if (r && r._type === 'request' && activeRequest && isRequest(activeRequest)) {
|
||||
// Only pull fields that we want to update
|
||||
return this._handleForceUpdateRequest(activeRequest, {
|
||||
return requestOperations.update(activeRequest, {
|
||||
url: r.url,
|
||||
method: r.method,
|
||||
headers: r.headers,
|
||||
@@ -184,31 +165,6 @@ export class WrapperClass extends PureComponent<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
async handleSetActiveResponse(requestId: string, activeResponse: Response | WebSocketResponse | null = null) {
|
||||
const { activeEnvironment } = this.props;
|
||||
const activeResponseId = activeResponse ? activeResponse._id : null;
|
||||
await updateRequestMetaByParentId(requestId, {
|
||||
activeResponseId,
|
||||
});
|
||||
|
||||
let response: Response | null;
|
||||
if (activeResponseId) {
|
||||
response = await models.response.getById(activeResponseId);
|
||||
} else {
|
||||
const environmentId = activeEnvironment ? activeEnvironment._id : null;
|
||||
response = await models.response.getLatestForRequest(requestId, environmentId);
|
||||
}
|
||||
if (!response || !response.requestVersionId) {
|
||||
return;
|
||||
}
|
||||
const request = await models.requestVersion.restore(response.requestVersionId);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
// Refresh app to reflect changes. Using timeout because we need to
|
||||
// wait for the request update to propagate.
|
||||
setTimeout(() => this._forceRequestPaneRefresh(), 500);
|
||||
}
|
||||
async _handleWorkspaceActivityChange({ workspaceId, nextActivity }: Parameters<HandleActivityChange>[0]): ReturnType<HandleActivityChange> {
|
||||
const { activeActivity, activeApiSpec, handleSetActiveActivity } = this.props;
|
||||
|
||||
@@ -275,19 +231,6 @@ export class WrapperClass extends PureComponent<Props, State> {
|
||||
this.props.handleSetResponseFilter(activeRequestId, filter);
|
||||
}
|
||||
|
||||
_forceRequestPaneRefreshAfterDelay(): void {
|
||||
// Give it a second for the app to render first. If we don't wait, it will refresh
|
||||
// on the old request and won't catch the newest one.
|
||||
// TODO: Move this refresh key into redux store so we don't need timeout
|
||||
window.setTimeout(this._forceRequestPaneRefresh, 100);
|
||||
}
|
||||
|
||||
_forceRequestPaneRefresh() {
|
||||
this.setState({
|
||||
forceRefreshKey: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
_handleGitBranchChanged(branch: string) {
|
||||
this.setState({
|
||||
activeGitBranch: branch || 'no-vcs',
|
||||
@@ -298,10 +241,6 @@ export class WrapperClass extends PureComponent<Props, State> {
|
||||
if (this.props.activeWorkspaceMeta) {
|
||||
await models.workspaceMeta.update(this.props.activeWorkspaceMeta, { activeEnvironmentId });
|
||||
}
|
||||
// Give it time to update and re-render
|
||||
setTimeout(() => {
|
||||
this._forceRequestPaneRefresh();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -366,7 +305,6 @@ export class WrapperClass extends PureComponent<Props, State> {
|
||||
</> : null}
|
||||
|
||||
<NunjucksModal
|
||||
uniqueKey={`key::${this.state.forceRefreshKey}`}
|
||||
ref={registerModal}
|
||||
workspace={activeWorkspace}
|
||||
/>
|
||||
@@ -480,15 +418,11 @@ export class WrapperClass extends PureComponent<Props, State> {
|
||||
element={
|
||||
<Suspense fallback={<div />}>
|
||||
<WrapperDebug
|
||||
forceRefreshKey={this.state.forceRefreshKey}
|
||||
gitSyncDropdown={gitSyncDropdown}
|
||||
handleActivityChange={this._handleWorkspaceActivityChange}
|
||||
handleSetActiveEnvironment={this._handleSetActiveEnvironment}
|
||||
handleForceUpdateRequest={this._handleForceUpdateRequest}
|
||||
handleForceUpdateRequestHeaders={this._handleForceUpdateRequestHeaders}
|
||||
handleImport={this._handleImport}
|
||||
handleSetResponseFilter={this._handleSetResponseFilter}
|
||||
handleSetActiveResponse={this.handleSetActiveResponse}
|
||||
vcs={vcs}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
generateId,
|
||||
} from '../../common/misc';
|
||||
import * as models from '../../models';
|
||||
import { isEnvironment } from '../../models/environment';
|
||||
import { GrpcRequest, isGrpcRequest } from '../../models/grpc-request';
|
||||
import { getByParentId as getGrpcRequestMetaByParentId } from '../../models/grpc-request-meta';
|
||||
import * as requestOperations from '../../models/helpers/request-operations';
|
||||
@@ -55,7 +54,7 @@ import { SyncMergeModal } from '../components/modals/sync-merge-modal';
|
||||
import { WorkspaceEnvironmentsEditModal } from '../components/modals/workspace-environments-edit-modal';
|
||||
import { WorkspaceSettingsModal } from '../components/modals/workspace-settings-modal';
|
||||
import { Toast } from '../components/toast';
|
||||
import { type WrapperClass, Wrapper } from '../components/wrapper';
|
||||
import { Wrapper } from '../components/wrapper';
|
||||
import withDragDropContext from '../context/app/drag-drop-context';
|
||||
import { GrpcProvider } from '../context/grpc';
|
||||
import { NunjucksEnabledProvider } from '../context/nunjucks/nunjucks-enabled-context';
|
||||
@@ -89,7 +88,6 @@ export type AppProps = ReturnType<typeof mapStateToProps> & ReturnType<typeof ma
|
||||
interface State {
|
||||
vcs: VCS | null;
|
||||
gitVCS: GitVCS | null;
|
||||
forceRefreshCounter: number;
|
||||
isMigratingChildren: boolean;
|
||||
}
|
||||
|
||||
@@ -97,7 +95,6 @@ interface State {
|
||||
class App extends PureComponent<AppProps, State> {
|
||||
private _globalKeyMap: any;
|
||||
private _updateVCSLock: any;
|
||||
private _wrapper: WrapperClass | null = null;
|
||||
private _responseFilterHistorySaveTimeout: NodeJS.Timeout | null = null;
|
||||
|
||||
constructor(props: AppProps) {
|
||||
@@ -106,7 +103,6 @@ class App extends PureComponent<AppProps, State> {
|
||||
this.state = {
|
||||
vcs: null,
|
||||
gitVCS: null,
|
||||
forceRefreshCounter: 0,
|
||||
isMigratingChildren: false,
|
||||
};
|
||||
|
||||
@@ -356,10 +352,6 @@ class App extends PureComponent<AppProps, State> {
|
||||
showModal(SettingsModal, tabIndex);
|
||||
}
|
||||
|
||||
_setWrapperRef(wrapper: WrapperClass) {
|
||||
this._wrapper = wrapper;
|
||||
}
|
||||
|
||||
async _handleReloadPlugins() {
|
||||
const { settings } = this.props;
|
||||
await plugins.reloadPlugins();
|
||||
@@ -406,13 +398,6 @@ class App extends PureComponent<AppProps, State> {
|
||||
|
||||
this._ensureWorkspaceChildren();
|
||||
|
||||
// Force app refresh if login state changes
|
||||
if (prevProps.isLoggedIn !== this.props.isLoggedIn) {
|
||||
this.setState(state => ({
|
||||
forceRefreshCounter: state.forceRefreshCounter + 1,
|
||||
}));
|
||||
}
|
||||
|
||||
// Check on VCS things
|
||||
const { activeWorkspace, activeProject, activeGitRepository } = this.props;
|
||||
const changingWorkspace = prevProps.activeWorkspace?._id !== activeWorkspace?._id;
|
||||
@@ -540,38 +525,16 @@ class App extends PureComponent<AppProps, State> {
|
||||
}
|
||||
}
|
||||
|
||||
async _handleDbChange(changes: ChangeBufferEvent[]) {
|
||||
let needsRefresh = false;
|
||||
|
||||
async listenforWorkspaceDelete(changes: ChangeBufferEvent[]) {
|
||||
for (const change of changes) {
|
||||
const [type, doc, fromSync] = change;
|
||||
const [type, doc] = change;
|
||||
const { vcs } = this.state;
|
||||
const { activeRequest } = this.props;
|
||||
|
||||
// Force refresh if environment changes
|
||||
// TODO: Only do this for environments in this workspace (not easy because they're nested)
|
||||
if (isEnvironment(doc)) {
|
||||
console.log('[App] Forcing update from environment change', change);
|
||||
needsRefresh = true;
|
||||
}
|
||||
|
||||
// Force refresh if sync changes the active request
|
||||
if (fromSync && activeRequest && doc._id === activeRequest._id) {
|
||||
needsRefresh = true;
|
||||
console.log('[App] Forcing update from request change', change);
|
||||
}
|
||||
|
||||
// Delete VCS project if workspace deleted
|
||||
if (vcs && isWorkspace(doc) && type === db.CHANGE_REMOVE) {
|
||||
await vcs.removeBackendProjectsForRoot(doc._id);
|
||||
}
|
||||
}
|
||||
|
||||
if (needsRefresh) {
|
||||
setTimeout(() => {
|
||||
this._wrapper?._forceRequestPaneRefresh();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -584,7 +547,7 @@ class App extends PureComponent<AppProps, State> {
|
||||
// Update VCS
|
||||
await this._updateVCS();
|
||||
await this._updateGitVCS();
|
||||
db.onChange(this._handleDbChange);
|
||||
db.onChange(this.listenforWorkspaceDelete);
|
||||
ipcRenderer.on('toggle-preferences', () => {
|
||||
App._handleShowSettingsModal();
|
||||
});
|
||||
@@ -703,7 +666,7 @@ class App extends PureComponent<AppProps, State> {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
db.offChange(this._handleDbChange);
|
||||
db.offChange(this.listenforWorkspaceDelete);
|
||||
}
|
||||
|
||||
async _ensureWorkspaceChildren() {
|
||||
@@ -768,13 +731,12 @@ class App extends PureComponent<AppProps, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { activeWorkspace } = this.props;
|
||||
const { activeWorkspace, isLoggedIn } = this.props;
|
||||
const {
|
||||
gitVCS,
|
||||
vcs,
|
||||
forceRefreshCounter,
|
||||
} = this.state;
|
||||
const uniquenessKey = `${forceRefreshCounter}::${activeWorkspace?._id || 'n/a'}`;
|
||||
const uniquenessKey = `${isLoggedIn}::${activeWorkspace?._id || 'n/a'}`;
|
||||
return (
|
||||
<KeydownBinder onKeydown={this._handleKeyDown}>
|
||||
<GrpcProvider>
|
||||
@@ -784,7 +746,6 @@ class App extends PureComponent<AppProps, State> {
|
||||
<div className="app" key={uniquenessKey}>
|
||||
<ErrorBoundary showAlert>
|
||||
<Wrapper
|
||||
ref={this._setWrapperRef}
|
||||
handleSetResponseFilter={this._handleSetResponseFilter}
|
||||
vcs={vcs}
|
||||
gitVCS={gitVCS}
|
||||
|
||||
35
packages/insomnia/src/ui/hooks/use-vcs-version.ts
Normal file
35
packages/insomnia/src/ui/hooks/use-vcs-version.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { database } from '../../common/database';
|
||||
import { selectActiveRequest, selectActiveWorkspaceMeta } from '../redux/selectors';
|
||||
|
||||
// We use this hook to determine if the active request has been updated from the VCS
|
||||
// For example, by pulling a new version from the remote, switching branches, etc.
|
||||
export function useActiveRequestSyncVCSVersion() {
|
||||
const [version, setVersion] = useState(0);
|
||||
const activeRequest = useSelector(selectActiveRequest);
|
||||
|
||||
useEffect(() => {
|
||||
database.onChange(changes => {
|
||||
for (const change of changes) {
|
||||
const [, doc, fromSync] = change;
|
||||
|
||||
// Force refresh if sync changes the active request
|
||||
if (activeRequest?._id === doc._id && fromSync) {
|
||||
setVersion(v => v + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [activeRequest?._id]);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
// We use this hook to determine if the active workspace has been updated from the Git VCS
|
||||
// For example, by pulling a new version from the remote, switching branches, etc.
|
||||
export function useGitVCSVersion() {
|
||||
const activeWorkspaceMeta = useSelector(selectActiveWorkspaceMeta);
|
||||
|
||||
return ((activeWorkspaceMeta?.cachedGitLastCommitTime + '') + activeWorkspaceMeta?.cachedGitRepositoryBranch) + '';
|
||||
}
|
||||
Reference in New Issue
Block a user