mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-24 01:28:35 +02:00
Start on plugin ctx API (#64)
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type GetHttpRequestByIdRequest = { id: string, };
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { HttpRequest } from "./HttpRequest";
|
||||||
|
|
||||||
|
export type GetHttpRequestByIdResponse = { httpRequest: HttpRequest | null, };
|
||||||
@@ -6,7 +6,11 @@ import type { ExportHttpRequestRequest } from "./ExportHttpRequestRequest";
|
|||||||
import type { ExportHttpRequestResponse } from "./ExportHttpRequestResponse";
|
import type { ExportHttpRequestResponse } from "./ExportHttpRequestResponse";
|
||||||
import type { FilterRequest } from "./FilterRequest";
|
import type { FilterRequest } from "./FilterRequest";
|
||||||
import type { FilterResponse } from "./FilterResponse";
|
import type { FilterResponse } from "./FilterResponse";
|
||||||
|
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
|
||||||
|
import type { GetHttpRequestByIdResponse } from "./GetHttpRequestByIdResponse";
|
||||||
import type { ImportRequest } from "./ImportRequest";
|
import type { ImportRequest } from "./ImportRequest";
|
||||||
import type { ImportResponse } from "./ImportResponse";
|
import type { ImportResponse } from "./ImportResponse";
|
||||||
|
import type { SendHttpRequestRequest } from "./SendHttpRequestRequest";
|
||||||
|
import type { SendHttpRequestResponse } from "./SendHttpRequestResponse";
|
||||||
|
|
||||||
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "empty_response" } & EmptyResponse;
|
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "empty_response" } & EmptyResponse;
|
||||||
|
|||||||
4
plugin-runtime-types/src/gen/SendHttpRequestRequest.ts
Normal file
4
plugin-runtime-types/src/gen/SendHttpRequestRequest.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { HttpRequest } from "./HttpRequest";
|
||||||
|
|
||||||
|
export type SendHttpRequestRequest = { httpRequest: HttpRequest, };
|
||||||
4
plugin-runtime-types/src/gen/SendHttpRequestResponse.ts
Normal file
4
plugin-runtime-types/src/gen/SendHttpRequestResponse.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { HttpResponse } from "./HttpResponse";
|
||||||
|
|
||||||
|
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };
|
||||||
@@ -31,5 +31,10 @@ export * from './gen/InternalEvent';
|
|||||||
export * from './gen/InternalEventPayload';
|
export * from './gen/InternalEventPayload';
|
||||||
export * from './gen/KeyValue';
|
export * from './gen/KeyValue';
|
||||||
export * from './gen/Model';
|
export * from './gen/Model';
|
||||||
|
export * from './gen/SendHttpRequestRequest';
|
||||||
|
export * from './gen/SendHttpRequestResponse';
|
||||||
|
export * from './gen/GetHttpRequestByIdRequest';
|
||||||
|
export * from './gen/GetHttpRequestByIdResponse';
|
||||||
|
export * from './gen/SendHttpRequestResponse';
|
||||||
export * from './gen/Settings';
|
export * from './gen/Settings';
|
||||||
export * from './gen/Workspace';
|
export * from './gen/Workspace';
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { HttpRequest } from '../gen/HttpRequest';
|
import { GetHttpRequestByIdRequest } from '../gen/GetHttpRequestByIdRequest';
|
||||||
import { HttpResponse } from '../gen/HttpResponse';
|
import { GetHttpRequestByIdResponse } from '../gen/GetHttpRequestByIdResponse';
|
||||||
|
import { SendHttpRequestRequest } from '../gen/SendHttpRequestRequest';
|
||||||
|
import { SendHttpRequestResponse } from '../gen/SendHttpRequestResponse';
|
||||||
|
|
||||||
export type YaakContext = {
|
export type YaakContext = {
|
||||||
metadata: {
|
|
||||||
getVersion(): Promise<string>;
|
|
||||||
};
|
|
||||||
httpRequest: {
|
httpRequest: {
|
||||||
send(id: string): Promise<HttpResponse>;
|
send(args: SendHttpRequestRequest): Promise<SendHttpRequestResponse['httpResponse']>;
|
||||||
getById(id: string): Promise<HttpRequest | null>;
|
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse['httpRequest']>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { FilterPlugin } from './filter';
|
|||||||
import { HttpRequestActionPlugin } from './httpRequestAction';
|
import { HttpRequestActionPlugin } from './httpRequestAction';
|
||||||
import { ImporterPlugin } from './import';
|
import { ImporterPlugin } from './import';
|
||||||
import { ThemePlugin } from './theme';
|
import { ThemePlugin } from './theme';
|
||||||
|
export { YaakContext } from './context';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The global structure of a Yaak plugin
|
* The global structure of a Yaak plugin
|
||||||
|
|||||||
@@ -10,369 +10,10 @@ import * as _m0 from "protobufjs/minimal";
|
|||||||
|
|
||||||
export const protobufPackage = "yaak.plugins.runtime";
|
export const protobufPackage = "yaak.plugins.runtime";
|
||||||
|
|
||||||
export interface PluginInfo {
|
|
||||||
plugin: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HookResponse {
|
|
||||||
info: PluginInfo | undefined;
|
|
||||||
data: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HookImportRequest {
|
|
||||||
data: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HookResponseFilterRequest {
|
|
||||||
filter: string;
|
|
||||||
body: string;
|
|
||||||
contentType: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HookExportRequest {
|
|
||||||
request: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EventStreamEvent {
|
export interface EventStreamEvent {
|
||||||
event: string;
|
event: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createBasePluginInfo(): PluginInfo {
|
|
||||||
return { plugin: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PluginInfo = {
|
|
||||||
encode(message: PluginInfo, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
|
|
||||||
if (message.plugin !== "") {
|
|
||||||
writer.uint32(10).string(message.plugin);
|
|
||||||
}
|
|
||||||
return writer;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(input: _m0.Reader | Uint8Array, length?: number): PluginInfo {
|
|
||||||
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
|
||||||
const message = createBasePluginInfo();
|
|
||||||
while (reader.pos < end) {
|
|
||||||
const tag = reader.uint32();
|
|
||||||
switch (tag >>> 3) {
|
|
||||||
case 1:
|
|
||||||
if (tag !== 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.plugin = reader.string();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((tag & 7) === 4 || tag === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reader.skipType(tag & 7);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
fromJSON(object: any): PluginInfo {
|
|
||||||
return { plugin: isSet(object.plugin) ? globalThis.String(object.plugin) : "" };
|
|
||||||
},
|
|
||||||
|
|
||||||
toJSON(message: PluginInfo): unknown {
|
|
||||||
const obj: any = {};
|
|
||||||
if (message.plugin !== "") {
|
|
||||||
obj.plugin = message.plugin;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
|
|
||||||
create(base?: DeepPartial<PluginInfo>): PluginInfo {
|
|
||||||
return PluginInfo.fromPartial(base ?? {});
|
|
||||||
},
|
|
||||||
fromPartial(object: DeepPartial<PluginInfo>): PluginInfo {
|
|
||||||
const message = createBasePluginInfo();
|
|
||||||
message.plugin = object.plugin ?? "";
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function createBaseHookResponse(): HookResponse {
|
|
||||||
return { info: undefined, data: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HookResponse = {
|
|
||||||
encode(message: HookResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
|
|
||||||
if (message.info !== undefined) {
|
|
||||||
PluginInfo.encode(message.info, writer.uint32(10).fork()).ldelim();
|
|
||||||
}
|
|
||||||
if (message.data !== "") {
|
|
||||||
writer.uint32(18).string(message.data);
|
|
||||||
}
|
|
||||||
return writer;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(input: _m0.Reader | Uint8Array, length?: number): HookResponse {
|
|
||||||
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
|
||||||
const message = createBaseHookResponse();
|
|
||||||
while (reader.pos < end) {
|
|
||||||
const tag = reader.uint32();
|
|
||||||
switch (tag >>> 3) {
|
|
||||||
case 1:
|
|
||||||
if (tag !== 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.info = PluginInfo.decode(reader, reader.uint32());
|
|
||||||
continue;
|
|
||||||
case 2:
|
|
||||||
if (tag !== 18) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.data = reader.string();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((tag & 7) === 4 || tag === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reader.skipType(tag & 7);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
fromJSON(object: any): HookResponse {
|
|
||||||
return {
|
|
||||||
info: isSet(object.info) ? PluginInfo.fromJSON(object.info) : undefined,
|
|
||||||
data: isSet(object.data) ? globalThis.String(object.data) : "",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
toJSON(message: HookResponse): unknown {
|
|
||||||
const obj: any = {};
|
|
||||||
if (message.info !== undefined) {
|
|
||||||
obj.info = PluginInfo.toJSON(message.info);
|
|
||||||
}
|
|
||||||
if (message.data !== "") {
|
|
||||||
obj.data = message.data;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
|
|
||||||
create(base?: DeepPartial<HookResponse>): HookResponse {
|
|
||||||
return HookResponse.fromPartial(base ?? {});
|
|
||||||
},
|
|
||||||
fromPartial(object: DeepPartial<HookResponse>): HookResponse {
|
|
||||||
const message = createBaseHookResponse();
|
|
||||||
message.info = (object.info !== undefined && object.info !== null)
|
|
||||||
? PluginInfo.fromPartial(object.info)
|
|
||||||
: undefined;
|
|
||||||
message.data = object.data ?? "";
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function createBaseHookImportRequest(): HookImportRequest {
|
|
||||||
return { data: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HookImportRequest = {
|
|
||||||
encode(message: HookImportRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
|
|
||||||
if (message.data !== "") {
|
|
||||||
writer.uint32(10).string(message.data);
|
|
||||||
}
|
|
||||||
return writer;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(input: _m0.Reader | Uint8Array, length?: number): HookImportRequest {
|
|
||||||
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
|
||||||
const message = createBaseHookImportRequest();
|
|
||||||
while (reader.pos < end) {
|
|
||||||
const tag = reader.uint32();
|
|
||||||
switch (tag >>> 3) {
|
|
||||||
case 1:
|
|
||||||
if (tag !== 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.data = reader.string();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((tag & 7) === 4 || tag === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reader.skipType(tag & 7);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
fromJSON(object: any): HookImportRequest {
|
|
||||||
return { data: isSet(object.data) ? globalThis.String(object.data) : "" };
|
|
||||||
},
|
|
||||||
|
|
||||||
toJSON(message: HookImportRequest): unknown {
|
|
||||||
const obj: any = {};
|
|
||||||
if (message.data !== "") {
|
|
||||||
obj.data = message.data;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
|
|
||||||
create(base?: DeepPartial<HookImportRequest>): HookImportRequest {
|
|
||||||
return HookImportRequest.fromPartial(base ?? {});
|
|
||||||
},
|
|
||||||
fromPartial(object: DeepPartial<HookImportRequest>): HookImportRequest {
|
|
||||||
const message = createBaseHookImportRequest();
|
|
||||||
message.data = object.data ?? "";
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function createBaseHookResponseFilterRequest(): HookResponseFilterRequest {
|
|
||||||
return { filter: "", body: "", contentType: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HookResponseFilterRequest = {
|
|
||||||
encode(message: HookResponseFilterRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
|
|
||||||
if (message.filter !== "") {
|
|
||||||
writer.uint32(10).string(message.filter);
|
|
||||||
}
|
|
||||||
if (message.body !== "") {
|
|
||||||
writer.uint32(18).string(message.body);
|
|
||||||
}
|
|
||||||
if (message.contentType !== "") {
|
|
||||||
writer.uint32(26).string(message.contentType);
|
|
||||||
}
|
|
||||||
return writer;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(input: _m0.Reader | Uint8Array, length?: number): HookResponseFilterRequest {
|
|
||||||
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
|
||||||
const message = createBaseHookResponseFilterRequest();
|
|
||||||
while (reader.pos < end) {
|
|
||||||
const tag = reader.uint32();
|
|
||||||
switch (tag >>> 3) {
|
|
||||||
case 1:
|
|
||||||
if (tag !== 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.filter = reader.string();
|
|
||||||
continue;
|
|
||||||
case 2:
|
|
||||||
if (tag !== 18) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.body = reader.string();
|
|
||||||
continue;
|
|
||||||
case 3:
|
|
||||||
if (tag !== 26) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.contentType = reader.string();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((tag & 7) === 4 || tag === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reader.skipType(tag & 7);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
fromJSON(object: any): HookResponseFilterRequest {
|
|
||||||
return {
|
|
||||||
filter: isSet(object.filter) ? globalThis.String(object.filter) : "",
|
|
||||||
body: isSet(object.body) ? globalThis.String(object.body) : "",
|
|
||||||
contentType: isSet(object.contentType) ? globalThis.String(object.contentType) : "",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
toJSON(message: HookResponseFilterRequest): unknown {
|
|
||||||
const obj: any = {};
|
|
||||||
if (message.filter !== "") {
|
|
||||||
obj.filter = message.filter;
|
|
||||||
}
|
|
||||||
if (message.body !== "") {
|
|
||||||
obj.body = message.body;
|
|
||||||
}
|
|
||||||
if (message.contentType !== "") {
|
|
||||||
obj.contentType = message.contentType;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
|
|
||||||
create(base?: DeepPartial<HookResponseFilterRequest>): HookResponseFilterRequest {
|
|
||||||
return HookResponseFilterRequest.fromPartial(base ?? {});
|
|
||||||
},
|
|
||||||
fromPartial(object: DeepPartial<HookResponseFilterRequest>): HookResponseFilterRequest {
|
|
||||||
const message = createBaseHookResponseFilterRequest();
|
|
||||||
message.filter = object.filter ?? "";
|
|
||||||
message.body = object.body ?? "";
|
|
||||||
message.contentType = object.contentType ?? "";
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function createBaseHookExportRequest(): HookExportRequest {
|
|
||||||
return { request: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HookExportRequest = {
|
|
||||||
encode(message: HookExportRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
|
|
||||||
if (message.request !== "") {
|
|
||||||
writer.uint32(10).string(message.request);
|
|
||||||
}
|
|
||||||
return writer;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(input: _m0.Reader | Uint8Array, length?: number): HookExportRequest {
|
|
||||||
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
|
||||||
const message = createBaseHookExportRequest();
|
|
||||||
while (reader.pos < end) {
|
|
||||||
const tag = reader.uint32();
|
|
||||||
switch (tag >>> 3) {
|
|
||||||
case 1:
|
|
||||||
if (tag !== 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.request = reader.string();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((tag & 7) === 4 || tag === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reader.skipType(tag & 7);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
fromJSON(object: any): HookExportRequest {
|
|
||||||
return { request: isSet(object.request) ? globalThis.String(object.request) : "" };
|
|
||||||
},
|
|
||||||
|
|
||||||
toJSON(message: HookExportRequest): unknown {
|
|
||||||
const obj: any = {};
|
|
||||||
if (message.request !== "") {
|
|
||||||
obj.request = message.request;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
|
|
||||||
create(base?: DeepPartial<HookExportRequest>): HookExportRequest {
|
|
||||||
return HookExportRequest.fromPartial(base ?? {});
|
|
||||||
},
|
|
||||||
fromPartial(object: DeepPartial<HookExportRequest>): HookExportRequest {
|
|
||||||
const message = createBaseHookExportRequest();
|
|
||||||
message.request = object.request ?? "";
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function createBaseEventStreamEvent(): EventStreamEvent {
|
function createBaseEventStreamEvent(): EventStreamEvent {
|
||||||
return { event: "" };
|
return { event: "" };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import { ImportResponse, InternalEvent, InternalEventPayload } from '@yaakapp/api';
|
import {
|
||||||
|
GetHttpRequestByIdResponse,
|
||||||
|
ImportResponse,
|
||||||
|
InternalEvent,
|
||||||
|
InternalEventPayload,
|
||||||
|
SendHttpRequestResponse,
|
||||||
|
} from '@yaakapp/api';
|
||||||
|
import { YaakContext } from '@yaakapp/api/lib/plugins/context';
|
||||||
import interceptStdout from 'intercept-stdout';
|
import interceptStdout from 'intercept-stdout';
|
||||||
import * as console from 'node:console';
|
import * as console from 'node:console';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
@@ -7,7 +14,7 @@ import * as util from 'node:util';
|
|||||||
import { parentPort, workerData } from 'node:worker_threads';
|
import { parentPort, workerData } from 'node:worker_threads';
|
||||||
|
|
||||||
new Promise<void>(async (resolve, reject) => {
|
new Promise<void>(async (resolve, reject) => {
|
||||||
const { pluginDir /*, pluginRefId*/ } = workerData;
|
const { pluginDir, pluginRefId } = workerData;
|
||||||
const pathPkg = path.join(pluginDir, 'package.json');
|
const pathPkg = path.join(pluginDir, 'package.json');
|
||||||
|
|
||||||
// NOTE: Use POSIX join because require() needs forward slash
|
// NOTE: Use POSIX join because require() needs forward slash
|
||||||
@@ -33,8 +40,64 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
|
|
||||||
console.log('Plugin initialized', pkg.name, capabilities, Object.keys(mod));
|
console.log('Plugin initialized', pkg.name, capabilities, Object.keys(mod));
|
||||||
|
|
||||||
|
function buildEventToSend(
|
||||||
|
payload: InternalEventPayload,
|
||||||
|
replyId: string | null = null,
|
||||||
|
): InternalEvent {
|
||||||
|
return { pluginRefId, id: genId(), replyId, payload };
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendPayload(payload: InternalEventPayload, replyId: string | null = null): string {
|
||||||
|
const event = buildEventToSend(payload, replyId);
|
||||||
|
sendEvent(event);
|
||||||
|
return event.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendEvent(event: InternalEvent) {
|
||||||
|
parentPort!.postMessage(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendAndWaitForReply<T extends Omit<InternalEventPayload, 'type'>>(
|
||||||
|
payload: InternalEventPayload,
|
||||||
|
): Promise<T> {
|
||||||
|
// 1. Build event to send
|
||||||
|
const eventToSend = buildEventToSend(payload, null);
|
||||||
|
|
||||||
|
// 2. Spawn listener in background
|
||||||
|
const promise = new Promise<InternalEventPayload>(async (resolve) => {
|
||||||
|
const cb = (event: InternalEvent) => {
|
||||||
|
if (event.replyId === eventToSend.id) {
|
||||||
|
resolve(event.payload); // Not type-safe but oh well
|
||||||
|
parentPort!.off('message', cb); // Unlisten, now that we're done
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parentPort!.on('message', cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. Send the event after we start listening (to prevent race)
|
||||||
|
sendEvent(eventToSend);
|
||||||
|
|
||||||
|
// 4. Return the listener promise
|
||||||
|
return promise as unknown as Promise<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx: YaakContext = {
|
||||||
|
httpRequest: {
|
||||||
|
async getById({ id }) {
|
||||||
|
const payload = { type: 'get_http_request_by_id_request', id } as const;
|
||||||
|
const { httpRequest } = await sendAndWaitForReply<GetHttpRequestByIdResponse>(payload);
|
||||||
|
return httpRequest;
|
||||||
|
},
|
||||||
|
async send({ httpRequest }) {
|
||||||
|
const payload = { type: 'send_http_request_request', httpRequest } as const;
|
||||||
|
const { httpResponse } = await sendAndWaitForReply<SendHttpRequestResponse>(payload);
|
||||||
|
return httpResponse;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Message comes into the plugin to be processed
|
// Message comes into the plugin to be processed
|
||||||
parentPort!.on('message', async ({ payload, pluginRefId, id: replyId }: InternalEvent) => {
|
parentPort!.on('message', async ({ payload, id: replyId }: InternalEvent) => {
|
||||||
console.log(`Received ${payload.type}`);
|
console.log(`Received ${payload.type}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -45,18 +108,18 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
version: pkg.version,
|
version: pkg.version,
|
||||||
capabilities,
|
capabilities,
|
||||||
};
|
};
|
||||||
sendToServer({ id: genId(), pluginRefId, replyId, payload });
|
sendPayload(payload, replyId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.type === 'import_request' && typeof mod.pluginHookImport === 'function') {
|
if (payload.type === 'import_request' && typeof mod.pluginHookImport === 'function') {
|
||||||
const reply: ImportResponse | null = await mod.pluginHookImport({}, payload.content);
|
const reply: ImportResponse | null = await mod.pluginHookImport(ctx, payload.content);
|
||||||
if (reply != null) {
|
if (reply != null) {
|
||||||
const replyPayload: InternalEventPayload = {
|
const replyPayload: InternalEventPayload = {
|
||||||
type: 'import_response',
|
type: 'import_response',
|
||||||
resources: reply?.resources,
|
resources: reply?.resources,
|
||||||
};
|
};
|
||||||
sendToServer({ id: genId(), pluginRefId, replyId, payload: replyPayload });
|
sendPayload(replyPayload, replyId);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Continue, to send back an empty reply
|
// Continue, to send back an empty reply
|
||||||
@@ -67,25 +130,25 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
payload.type === 'export_http_request_request' &&
|
payload.type === 'export_http_request_request' &&
|
||||||
typeof mod.pluginHookExport === 'function'
|
typeof mod.pluginHookExport === 'function'
|
||||||
) {
|
) {
|
||||||
const reply: string = await mod.pluginHookExport({}, payload.httpRequest);
|
const reply: string = await mod.pluginHookExport(ctx, payload.httpRequest);
|
||||||
const replyPayload: InternalEventPayload = {
|
const replyPayload: InternalEventPayload = {
|
||||||
type: 'export_http_request_response',
|
type: 'export_http_request_response',
|
||||||
content: reply,
|
content: reply,
|
||||||
};
|
};
|
||||||
sendToServer({ id: genId(), pluginRefId, replyId, payload: replyPayload });
|
sendPayload(replyPayload, replyId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.type === 'filter_request' && typeof mod.pluginHookResponseFilter === 'function') {
|
if (payload.type === 'filter_request' && typeof mod.pluginHookResponseFilter === 'function') {
|
||||||
const reply: string = await mod.pluginHookResponseFilter(
|
const reply: string = await mod.pluginHookResponseFilter(ctx, {
|
||||||
{},
|
filter: payload.filter,
|
||||||
{ filter: payload.filter, body: payload.content },
|
body: payload.content,
|
||||||
);
|
});
|
||||||
const replyPayload: InternalEventPayload = {
|
const replyPayload: InternalEventPayload = {
|
||||||
type: 'filter_response',
|
type: 'filter_response',
|
||||||
content: reply,
|
content: reply,
|
||||||
};
|
};
|
||||||
sendToServer({ id: genId(), pluginRefId, replyId, payload: replyPayload });
|
sendPayload(replyPayload, replyId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -94,9 +157,7 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No matches, so send back an empty response so the caller doesn't block forever
|
// No matches, so send back an empty response so the caller doesn't block forever
|
||||||
const id = genId();
|
sendPayload({ type: 'empty_response' }, replyId);
|
||||||
console.log('Sending nothing back to', id, { replyId });
|
|
||||||
sendToServer({ id, pluginRefId, replyId, payload: { type: 'empty_response' } });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
@@ -104,10 +165,6 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
console.log('failed to boot plugin', err);
|
console.log('failed to boot plugin', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
function sendToServer(e: InternalEvent) {
|
|
||||||
parentPort!.postMessage(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
function genId(len = 5): string {
|
function genId(len = 5): string {
|
||||||
const alphabet = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
const alphabet = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
let id = '';
|
let id = '';
|
||||||
|
|||||||
66
src-tauri/Cargo.lock
generated
66
src-tauri/Cargo.lock
generated
@@ -2052,30 +2052,6 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "grpc"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"dunce",
|
|
||||||
"hyper 0.14.30",
|
|
||||||
"hyper-rustls 0.24.2",
|
|
||||||
"log",
|
|
||||||
"md5",
|
|
||||||
"prost 0.12.6",
|
|
||||||
"prost-reflect",
|
|
||||||
"prost-types 0.12.6",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tauri",
|
|
||||||
"tauri-plugin-shell",
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
"tonic 0.10.2",
|
|
||||||
"tonic-reflection",
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk"
|
name = "gtk"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
@@ -6125,13 +6101,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "templates"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tendril"
|
name = "tendril"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -7573,7 +7542,6 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"cocoa",
|
"cocoa",
|
||||||
"datetime",
|
"datetime",
|
||||||
"grpc",
|
|
||||||
"hex_color",
|
"hex_color",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"log",
|
"log",
|
||||||
@@ -7597,13 +7565,38 @@ dependencies = [
|
|||||||
"tauri-plugin-shell",
|
"tauri-plugin-shell",
|
||||||
"tauri-plugin-updater",
|
"tauri-plugin-updater",
|
||||||
"tauri-plugin-window-state",
|
"tauri-plugin-window-state",
|
||||||
"templates",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"yaak_grpc",
|
||||||
"yaak_models",
|
"yaak_models",
|
||||||
"yaak_plugin_runtime",
|
"yaak_plugin_runtime",
|
||||||
|
"yaak_templates",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaak_grpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"dunce",
|
||||||
|
"hyper 0.14.30",
|
||||||
|
"hyper-rustls 0.24.2",
|
||||||
|
"log",
|
||||||
|
"md5",
|
||||||
|
"prost 0.12.6",
|
||||||
|
"prost-reflect",
|
||||||
|
"prost-types 0.12.6",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin-shell",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
"tonic 0.10.2",
|
||||||
|
"tonic-reflection",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7651,6 +7644,13 @@ dependencies = [
|
|||||||
"yaak_models",
|
"yaak_models",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaak_templates"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus"
|
name = "zbus"
|
||||||
version = "4.0.1"
|
version = "4.0.1"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["grpc", "templates", "yaak_plugin_runtime", "yaak_models"]
|
members = ["yaak_grpc", "yaak_templates", "yaak_plugin_runtime", "yaak_models"]
|
||||||
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
@@ -26,8 +26,8 @@ cocoa = "0.25.0"
|
|||||||
openssl-sys = { version = "0.9", features = ["vendored"] } # For Ubuntu installation to work
|
openssl-sys = { version = "0.9", features = ["vendored"] } # For Ubuntu installation to work
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
grpc = { path = "./grpc" }
|
yaak_grpc = { path = "yaak_grpc" }
|
||||||
templates = { path = "./templates" }
|
yaak_templates = { path = "yaak_templates" }
|
||||||
yaak_plugin_runtime = { path = "yaak_plugin_runtime" }
|
yaak_plugin_runtime = { path = "yaak_plugin_runtime" }
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
base64 = "0.22.0"
|
base64 = "0.22.0"
|
||||||
@@ -43,7 +43,7 @@ reqwest_cookie_store = "0.8.0"
|
|||||||
serde = { version = "1.0.198", features = ["derive"] }
|
serde = { version = "1.0.198", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.116", features = ["raw_value"] }
|
serde_json = { version = "1.0.116", features = ["raw_value"] }
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
tauri = { workspace = true }
|
tauri = { workspace = true, features = ["unstable"] }
|
||||||
tauri-plugin-shell = { workspace = true }
|
tauri-plugin-shell = { workspace = true }
|
||||||
tauri-plugin-clipboard-manager = "2.0.0-rc.0"
|
tauri-plugin-clipboard-manager = "2.0.0-rc.0"
|
||||||
tauri-plugin-dialog = "2.0.0-rc.0"
|
tauri-plugin-dialog = "2.0.0-rc.0"
|
||||||
|
|||||||
2
src-tauri/migrations/20240814013812_fix-env-model.sql
Normal file
2
src-tauri/migrations/20240814013812_fix-env-model.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE environments DROP COLUMN model;
|
||||||
|
ALTER TABLE environments ADD COLUMN model TEXT DEFAULT 'environment';
|
||||||
@@ -3,9 +3,11 @@ use std::fmt::Display;
|
|||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{Manager, Runtime, WebviewWindow};
|
||||||
|
|
||||||
use yaak_models::queries::{generate_id, get_key_value_int, get_key_value_string, set_key_value_int, set_key_value_string};
|
use yaak_models::queries::{
|
||||||
|
generate_id, get_key_value_int, get_key_value_string, set_key_value_int, set_key_value_string,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::is_dev;
|
use crate::is_dev;
|
||||||
|
|
||||||
@@ -36,7 +38,7 @@ pub enum AnalyticsResource {
|
|||||||
|
|
||||||
impl AnalyticsResource {
|
impl AnalyticsResource {
|
||||||
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsResource> {
|
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsResource> {
|
||||||
return serde_json::from_str(format!("\"{s}\"").as_str());
|
serde_json::from_str(format!("\"{s}\"").as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ pub enum AnalyticsAction {
|
|||||||
|
|
||||||
impl AnalyticsAction {
|
impl AnalyticsAction {
|
||||||
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsAction> {
|
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsAction> {
|
||||||
return serde_json::from_str(format!("\"{s}\"").as_str());
|
serde_json::from_str(format!("\"{s}\"").as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,19 +98,18 @@ pub struct LaunchEventInfo {
|
|||||||
pub num_launches: i32,
|
pub num_launches: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
pub async fn track_launch_event<R: Runtime>(w: &WebviewWindow<R>) -> LaunchEventInfo {
|
||||||
let last_tracked_version_key = "last_tracked_version";
|
let last_tracked_version_key = "last_tracked_version";
|
||||||
|
|
||||||
let mut info = LaunchEventInfo::default();
|
let mut info = LaunchEventInfo::default();
|
||||||
|
|
||||||
info.num_launches = get_num_launches(app).await + 1;
|
info.num_launches = get_num_launches(w).await + 1;
|
||||||
info.previous_version =
|
info.previous_version = get_key_value_string(w, NAMESPACE, last_tracked_version_key, "").await;
|
||||||
get_key_value_string(app, NAMESPACE, last_tracked_version_key, "").await;
|
info.current_version = w.package_info().version.to_string();
|
||||||
info.current_version = app.package_info().version.to_string();
|
|
||||||
|
|
||||||
if info.previous_version.is_empty() {
|
if info.previous_version.is_empty() {
|
||||||
track_event(
|
track_event(
|
||||||
app,
|
w,
|
||||||
AnalyticsResource::App,
|
AnalyticsResource::App,
|
||||||
AnalyticsAction::LaunchFirst,
|
AnalyticsAction::LaunchFirst,
|
||||||
None,
|
None,
|
||||||
@@ -118,7 +119,7 @@ pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
|||||||
info.launched_after_update = info.current_version != info.previous_version;
|
info.launched_after_update = info.current_version != info.previous_version;
|
||||||
if info.launched_after_update {
|
if info.launched_after_update {
|
||||||
track_event(
|
track_event(
|
||||||
app,
|
w,
|
||||||
AnalyticsResource::App,
|
AnalyticsResource::App,
|
||||||
AnalyticsAction::LaunchUpdate,
|
AnalyticsAction::LaunchUpdate,
|
||||||
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
||||||
@@ -129,7 +130,7 @@ pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
|||||||
|
|
||||||
// Track a launch event in all cases
|
// Track a launch event in all cases
|
||||||
track_event(
|
track_event(
|
||||||
app,
|
w,
|
||||||
AnalyticsResource::App,
|
AnalyticsResource::App,
|
||||||
AnalyticsAction::Launch,
|
AnalyticsAction::Launch,
|
||||||
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
||||||
@@ -139,27 +140,27 @@ pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
|||||||
// Update key values
|
// Update key values
|
||||||
|
|
||||||
set_key_value_string(
|
set_key_value_string(
|
||||||
app,
|
w,
|
||||||
NAMESPACE,
|
NAMESPACE,
|
||||||
last_tracked_version_key,
|
last_tracked_version_key,
|
||||||
info.current_version.as_str(),
|
info.current_version.as_str(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
set_key_value_int(app, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches).await;
|
set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches).await;
|
||||||
|
|
||||||
info
|
info
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn track_event(
|
pub async fn track_event<R: Runtime>(
|
||||||
app_handle: &AppHandle,
|
w: &WebviewWindow<R>,
|
||||||
resource: AnalyticsResource,
|
resource: AnalyticsResource,
|
||||||
action: AnalyticsAction,
|
action: AnalyticsAction,
|
||||||
attributes: Option<Value>,
|
attributes: Option<Value>,
|
||||||
) {
|
) {
|
||||||
let id = get_id(app_handle).await;
|
let id = get_id(w).await;
|
||||||
let event = format!("{}.{}", resource, action);
|
let event = format!("{}.{}", resource, action);
|
||||||
let attributes_json = attributes.unwrap_or("{}".to_string().into()).to_string();
|
let attributes_json = attributes.unwrap_or("{}".to_string().into()).to_string();
|
||||||
let info = app_handle.package_info();
|
let info = w.app_handle().package_info();
|
||||||
let tz = datetime::sys_timezone().unwrap_or("unknown".to_string());
|
let tz = datetime::sys_timezone().unwrap_or("unknown".to_string());
|
||||||
let site = match is_dev() {
|
let site = match is_dev() {
|
||||||
true => "site_TkHWjoXwZPq3HfhERb",
|
true => "site_TkHWjoXwZPq3HfhERb",
|
||||||
@@ -177,7 +178,7 @@ pub async fn track_event(
|
|||||||
("v", info.version.clone().to_string()),
|
("v", info.version.clone().to_string()),
|
||||||
("os", get_os().to_string()),
|
("os", get_os().to_string()),
|
||||||
("tz", tz),
|
("tz", tz),
|
||||||
("xy", get_window_size(app_handle)),
|
("xy", get_window_size(w)),
|
||||||
];
|
];
|
||||||
let req = reqwest::Client::builder()
|
let req = reqwest::Client::builder()
|
||||||
.build()
|
.build()
|
||||||
@@ -208,13 +209,8 @@ fn get_os() -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_window_size(app_handle: &AppHandle) -> String {
|
fn get_window_size<R: Runtime>(w: &WebviewWindow<R>) -> String {
|
||||||
let window = match app_handle.webview_windows().into_values().next() {
|
let current_monitor = match w.current_monitor() {
|
||||||
Some(w) => w,
|
|
||||||
None => return "unknown".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let current_monitor = match window.current_monitor() {
|
|
||||||
Ok(Some(m)) => m,
|
Ok(Some(m)) => m,
|
||||||
_ => return "unknown".to_string(),
|
_ => return "unknown".to_string(),
|
||||||
};
|
};
|
||||||
@@ -231,17 +227,17 @@ fn get_window_size(app_handle: &AppHandle) -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_id(app_handle: &AppHandle) -> String {
|
async fn get_id<R: Runtime>(w: &WebviewWindow<R>) -> String {
|
||||||
let id = get_key_value_string(app_handle, "analytics", "id", "").await;
|
let id = get_key_value_string(w, "analytics", "id", "").await;
|
||||||
if id.is_empty() {
|
if id.is_empty() {
|
||||||
let new_id = generate_id();
|
let new_id = generate_id();
|
||||||
set_key_value_string(app_handle, "analytics", "id", new_id.as_str()).await;
|
set_key_value_string(w, "analytics", "id", new_id.as_str()).await;
|
||||||
new_id
|
new_id
|
||||||
} else {
|
} else {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_num_launches(app: &AppHandle) -> i32 {
|
pub async fn get_num_launches<R: Runtime>(w: &WebviewWindow<R>) -> i32 {
|
||||||
get_key_value_int(app, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
get_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use KeyAndValueRef::{Ascii, Binary};
|
use KeyAndValueRef::{Ascii, Binary};
|
||||||
|
|
||||||
use grpc::{KeyAndValueRef, MetadataMap};
|
use yaak_grpc::{KeyAndValueRef, MetadataMap};
|
||||||
|
|
||||||
pub fn metadata_to_map(metadata: MetadataMap) -> HashMap<String, String> {
|
pub fn metadata_to_map(metadata: MetadataMap) -> HashMap<String, String> {
|
||||||
let mut entries = HashMap::new();
|
let mut entries = HashMap::new();
|
||||||
|
|||||||
@@ -11,24 +11,25 @@ use crate::{render, response_err};
|
|||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use http::header::{ACCEPT, USER_AGENT};
|
use http::header::{ACCEPT, USER_AGENT};
|
||||||
use http::{HeaderMap, HeaderName, HeaderValue};
|
use http::{HeaderMap, HeaderName, HeaderValue};
|
||||||
use log::{error, info, warn};
|
use log::{error, warn};
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use reqwest::redirect::Policy;
|
use reqwest::redirect::Policy;
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use reqwest::{multipart, Url};
|
use reqwest::{multipart, Url};
|
||||||
use tauri::{Manager, WebviewWindow};
|
use tauri::{Manager, Runtime, WebviewWindow};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tokio::sync::watch::Receiver;
|
use tokio::sync::watch::Receiver;
|
||||||
use yaak_models::models::{Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader};
|
use yaak_models::models::{
|
||||||
|
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader,
|
||||||
|
};
|
||||||
use yaak_models::queries::{get_workspace, update_response_if_id, upsert_cookie_jar};
|
use yaak_models::queries::{get_workspace, update_response_if_id, upsert_cookie_jar};
|
||||||
|
|
||||||
pub async fn send_http_request(
|
pub async fn send_http_request<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
response: &HttpResponse,
|
response: &HttpResponse,
|
||||||
environment: Option<Environment>,
|
environment: Option<Environment>,
|
||||||
cookie_jar: Option<CookieJar>,
|
cookie_jar: Option<CookieJar>,
|
||||||
download_path: Option<PathBuf>,
|
|
||||||
cancel_rx: &mut Receiver<bool>,
|
cancel_rx: &mut Receiver<bool>,
|
||||||
) -> Result<HttpResponse, String> {
|
) -> Result<HttpResponse, String> {
|
||||||
let environment_ref = environment.as_ref();
|
let environment_ref = environment.as_ref();
|
||||||
@@ -442,16 +443,6 @@ pub async fn send_http_request(
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to update response");
|
.expect("Failed to update response");
|
||||||
|
|
||||||
// Copy response to the download path, if specified
|
|
||||||
match (download_path, response.body_path.clone()) {
|
|
||||||
(Some(dl_path), Some(body_path)) => {
|
|
||||||
info!("Downloading response body to {}", dl_path.display());
|
|
||||||
fs::copy(body_path, dl_path)
|
|
||||||
.expect("Failed to copy file for response download");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add cookie store if specified
|
// Add cookie store if specified
|
||||||
if let Some((cookie_store, mut cookie_jar)) = maybe_cookie_manager {
|
if let Some((cookie_store, mut cookie_jar)) = maybe_cookie_manager {
|
||||||
// let cookies = response_headers.get_all(SET_COOKIE).iter().map(|h| {
|
// let cookies = response_headers.get_all(SET_COOKIE).iter().map(|h| {
|
||||||
@@ -466,7 +457,8 @@ pub async fn send_http_request(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.iter_any()
|
.iter_any()
|
||||||
.map(|c| {
|
.map(|c| {
|
||||||
let json_cookie = serde_json::to_value(&c).expect("Failed to serialize cookie");
|
let json_cookie =
|
||||||
|
serde_json::to_value(&c).expect("Failed to serialize cookie");
|
||||||
serde_json::from_value(json_cookie).expect("Failed to deserialize cookie")
|
serde_json::from_value(json_cookie).expect("Failed to deserialize cookie")
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ use fern::colors::ColoredLevelConfig;
|
|||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tauri::Listener;
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use tauri::TitleBarStyle;
|
use tauri::TitleBarStyle;
|
||||||
use tauri::{AppHandle, Emitter, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow};
|
use tauri::{AppHandle, Emitter, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow};
|
||||||
|
use tauri::{Listener, Runtime};
|
||||||
use tauri::{Manager, WindowEvent};
|
use tauri::{Manager, WindowEvent};
|
||||||
use tauri_plugin_log::{fern, Target, TargetKind};
|
use tauri_plugin_log::{fern, Target, TargetKind};
|
||||||
use tauri_plugin_shell::ShellExt;
|
use tauri_plugin_shell::ShellExt;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::{watch, Mutex};
|
||||||
|
|
||||||
use ::grpc::manager::{DynamicMessage, GrpcHandle};
|
use yaak_grpc::manager::{DynamicMessage, GrpcHandle};
|
||||||
use ::grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
use yaak_grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
||||||
use yaak_plugin_runtime::manager::PluginManager;
|
use yaak_plugin_runtime::manager::PluginManager;
|
||||||
|
|
||||||
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
||||||
@@ -42,7 +42,7 @@ use yaak_models::models::{
|
|||||||
GrpcRequest, HttpRequest, HttpResponse, KeyValue, ModelType, Settings, Workspace,
|
GrpcRequest, HttpRequest, HttpResponse, KeyValue, ModelType, Settings, Workspace,
|
||||||
};
|
};
|
||||||
use yaak_models::queries::{
|
use yaak_models::queries::{
|
||||||
cancel_pending_grpc_connections, cancel_pending_responses, create_http_response,
|
cancel_pending_grpc_connections, cancel_pending_responses, create_default_http_response,
|
||||||
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
||||||
delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request,
|
delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request,
|
||||||
delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request,
|
delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request,
|
||||||
@@ -54,7 +54,10 @@ use yaak_models::queries::{
|
|||||||
upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
||||||
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace,
|
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace,
|
||||||
};
|
};
|
||||||
use yaak_plugin_runtime::events::FilterResponse;
|
use yaak_plugin_runtime::events::{
|
||||||
|
FilterResponse, GetHttpRequestByIdResponse, InternalEvent, InternalEventPayload,
|
||||||
|
SendHttpRequestResponse,
|
||||||
|
};
|
||||||
|
|
||||||
mod analytics;
|
mod analytics;
|
||||||
mod export_resources;
|
mod export_resources;
|
||||||
@@ -96,11 +99,15 @@ async fn cmd_metadata(app_handle: AppHandle) -> Result<AppMetaData, ()> {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn cmd_dismiss_notification(
|
async fn cmd_dismiss_notification(
|
||||||
app: AppHandle,
|
window: WebviewWindow,
|
||||||
notification_id: &str,
|
notification_id: &str,
|
||||||
yaak_notifier: State<'_, Mutex<YaakNotifier>>,
|
yaak_notifier: State<'_, Mutex<YaakNotifier>>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
yaak_notifier.lock().await.seen(&app, notification_id).await
|
yaak_notifier
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.seen(&window, notification_id)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -135,17 +142,21 @@ async fn cmd_grpc_go(
|
|||||||
request_id: &str,
|
request_id: &str,
|
||||||
environment_id: Option<&str>,
|
environment_id: Option<&str>,
|
||||||
proto_files: Vec<String>,
|
proto_files: Vec<String>,
|
||||||
w: WebviewWindow,
|
window: WebviewWindow,
|
||||||
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let req = get_grpc_request(&w, request_id)
|
let req = get_grpc_request(&window, request_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let environment = match environment_id {
|
let environment = match environment_id {
|
||||||
Some(id) => Some(get_environment(&w, id).await.map_err(|e| e.to_string())?),
|
Some(id) => Some(
|
||||||
|
get_environment(&window, id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?,
|
||||||
|
),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let workspace = get_workspace(&w, &req.workspace_id)
|
let workspace = get_workspace(&window, &req.workspace_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let mut metadata = HashMap::new();
|
let mut metadata = HashMap::new();
|
||||||
@@ -199,7 +210,7 @@ async fn cmd_grpc_go(
|
|||||||
let conn = {
|
let conn = {
|
||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
upsert_grpc_connection(
|
upsert_grpc_connection(
|
||||||
&w,
|
&window,
|
||||||
&GrpcConnection {
|
&GrpcConnection {
|
||||||
workspace_id: req.workspace_id,
|
workspace_id: req.workspace_id,
|
||||||
request_id: req.id,
|
request_id: req.id,
|
||||||
@@ -256,7 +267,7 @@ async fn cmd_grpc_go(
|
|||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
upsert_grpc_connection(
|
upsert_grpc_connection(
|
||||||
&w,
|
&window,
|
||||||
&GrpcConnection {
|
&GrpcConnection {
|
||||||
elapsed: start.elapsed().as_millis() as i32,
|
elapsed: start.elapsed().as_millis() as i32,
|
||||||
error: Some(err.clone()),
|
error: Some(err.clone()),
|
||||||
@@ -282,7 +293,7 @@ async fn cmd_grpc_go(
|
|||||||
|
|
||||||
let cb = {
|
let cb = {
|
||||||
let cancelled_rx = cancelled_rx.clone();
|
let cancelled_rx = cancelled_rx.clone();
|
||||||
let w = w.clone();
|
let w = window.clone();
|
||||||
let base_msg = base_msg.clone();
|
let base_msg = base_msg.clone();
|
||||||
let method_desc = method_desc.clone();
|
let method_desc = method_desc.clone();
|
||||||
let vars = vars.clone();
|
let vars = vars.clone();
|
||||||
@@ -355,10 +366,10 @@ async fn cmd_grpc_go(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let event_handler = w.listen_any(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
|
let event_handler = window.listen_any(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
|
||||||
|
|
||||||
let grpc_listen = {
|
let grpc_listen = {
|
||||||
let w = w.clone();
|
let w = window.clone();
|
||||||
let base_event = base_msg.clone();
|
let base_event = base_msg.clone();
|
||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
let vars = vars.clone();
|
let vars = vars.clone();
|
||||||
@@ -603,7 +614,7 @@ async fn cmd_grpc_go(
|
|||||||
{
|
{
|
||||||
let conn_id = conn_id.clone();
|
let conn_id = conn_id.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let w = w.clone();
|
let w = window.clone();
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = grpc_listen => {
|
_ = grpc_listen => {
|
||||||
let events = list_grpc_events(&w, &conn_id)
|
let events = list_grpc_events(&w, &conn_id)
|
||||||
@@ -691,7 +702,6 @@ async fn cmd_send_ephemeral_request(
|
|||||||
&response,
|
&response,
|
||||||
environment,
|
environment,
|
||||||
cookie_jar,
|
cookie_jar,
|
||||||
None,
|
|
||||||
&mut cancel_rx,
|
&mut cancel_rx,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -701,7 +711,7 @@ async fn cmd_send_ephemeral_request(
|
|||||||
async fn cmd_filter_response(
|
async fn cmd_filter_response(
|
||||||
w: WebviewWindow,
|
w: WebviewWindow,
|
||||||
response_id: &str,
|
response_id: &str,
|
||||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
plugin_manager: State<'_, PluginManager>,
|
||||||
filter: &str,
|
filter: &str,
|
||||||
) -> Result<FilterResponse, String> {
|
) -> Result<FilterResponse, String> {
|
||||||
let response = get_http_response(&w, response_id)
|
let response = get_http_response(&w, response_id)
|
||||||
@@ -724,8 +734,6 @@ async fn cmd_filter_response(
|
|||||||
|
|
||||||
// TODO: Have plugins register their own content type (regex?)
|
// TODO: Have plugins register their own content type (regex?)
|
||||||
plugin_manager
|
plugin_manager
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.run_filter(filter, &body, &content_type)
|
.run_filter(filter, &body, &content_type)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
@@ -734,15 +742,13 @@ async fn cmd_filter_response(
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn cmd_import_data(
|
async fn cmd_import_data(
|
||||||
w: WebviewWindow,
|
w: WebviewWindow,
|
||||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
plugin_manager: State<'_, PluginManager>,
|
||||||
file_path: &str,
|
file_path: &str,
|
||||||
) -> Result<WorkspaceExportResources, String> {
|
) -> Result<WorkspaceExportResources, String> {
|
||||||
let file =
|
let file =
|
||||||
read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
||||||
let file_contents = file.as_str();
|
let file_contents = file.as_str();
|
||||||
let (import_result, plugin_name) = plugin_manager
|
let (import_result, plugin_name) = plugin_manager
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.run_import(file_contents)
|
.run_import(file_contents)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
@@ -853,7 +859,7 @@ async fn cmd_import_data(
|
|||||||
);
|
);
|
||||||
|
|
||||||
analytics::track_event(
|
analytics::track_event(
|
||||||
&w.app_handle(),
|
&w,
|
||||||
AnalyticsResource::App,
|
AnalyticsResource::App,
|
||||||
AnalyticsAction::Import,
|
AnalyticsAction::Import,
|
||||||
Some(json!({ "plugin": plugin_name })),
|
Some(json!({ "plugin": plugin_name })),
|
||||||
@@ -867,7 +873,7 @@ async fn cmd_import_data(
|
|||||||
async fn cmd_request_to_curl(
|
async fn cmd_request_to_curl(
|
||||||
app: AppHandle,
|
app: AppHandle,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
plugin_manager: State<'_, PluginManager>,
|
||||||
environment_id: Option<&str>,
|
environment_id: Option<&str>,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let request = get_http_request(&app, request_id)
|
let request = get_http_request(&app, request_id)
|
||||||
@@ -883,8 +889,6 @@ async fn cmd_request_to_curl(
|
|||||||
let rendered = render_request(&request, &workspace, environment.as_ref());
|
let rendered = render_request(&request, &workspace, environment.as_ref());
|
||||||
|
|
||||||
let import_response = plugin_manager
|
let import_response = plugin_manager
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.run_export_curl(&rendered)
|
.run_export_curl(&rendered)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
@@ -894,19 +898,19 @@ async fn cmd_request_to_curl(
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn cmd_curl_to_request(
|
async fn cmd_curl_to_request(
|
||||||
command: &str,
|
command: &str,
|
||||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
plugin_manager: State<'_, PluginManager>,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
w: WebviewWindow,
|
w: WebviewWindow,
|
||||||
) -> Result<HttpRequest, String> {
|
) -> Result<HttpRequest, String> {
|
||||||
let (import_result, plugin_name) = plugin_manager
|
let (import_result, plugin_name) = {
|
||||||
.lock()
|
plugin_manager
|
||||||
.await
|
.run_import(command)
|
||||||
.run_import(command)
|
.await
|
||||||
.await
|
.map_err(|e| e.to_string())?
|
||||||
.map_err(|e| e.to_string())?;
|
};
|
||||||
|
|
||||||
analytics::track_event(
|
analytics::track_event(
|
||||||
&w.app_handle(),
|
&w,
|
||||||
AnalyticsResource::App,
|
AnalyticsResource::App,
|
||||||
AnalyticsAction::Import,
|
AnalyticsAction::Import,
|
||||||
Some(json!({ "plugin": plugin_name })),
|
Some(json!({ "plugin": plugin_name })),
|
||||||
@@ -947,7 +951,7 @@ async fn cmd_export_data(
|
|||||||
f.sync_all().expect("Failed to sync");
|
f.sync_all().expect("Failed to sync");
|
||||||
|
|
||||||
analytics::track_event(
|
analytics::track_event(
|
||||||
&window.app_handle(),
|
&window,
|
||||||
AnalyticsResource::App,
|
AnalyticsResource::App,
|
||||||
AnalyticsAction::Export,
|
AnalyticsAction::Export,
|
||||||
None,
|
None,
|
||||||
@@ -984,7 +988,6 @@ async fn cmd_send_http_request(
|
|||||||
window: WebviewWindow,
|
window: WebviewWindow,
|
||||||
environment_id: Option<&str>,
|
environment_id: Option<&str>,
|
||||||
cookie_jar_id: Option<&str>,
|
cookie_jar_id: Option<&str>,
|
||||||
download_dir: Option<&str>,
|
|
||||||
// NOTE: We receive the entire request because to account for the race
|
// NOTE: We receive the entire request because to account for the race
|
||||||
// condition where the user may have just edited a field before sending
|
// condition where the user may have just edited a field before sending
|
||||||
// that has not yet been saved in the DB.
|
// that has not yet been saved in the DB.
|
||||||
@@ -1010,28 +1013,9 @@ async fn cmd_send_http_request(
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = create_http_response(
|
let response = create_default_http_response(&window, &request.id)
|
||||||
&window,
|
.await
|
||||||
&request.id,
|
.map_err(|e| e.to_string())?;
|
||||||
0,
|
|
||||||
0,
|
|
||||||
"",
|
|
||||||
0,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
vec![],
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("Failed to create response");
|
|
||||||
|
|
||||||
let download_path = if let Some(p) = download_dir {
|
|
||||||
Some(std::path::Path::new(p).to_path_buf())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
|
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
|
||||||
window.listen_any(
|
window.listen_any(
|
||||||
@@ -1047,16 +1031,15 @@ async fn cmd_send_http_request(
|
|||||||
&response,
|
&response,
|
||||||
environment,
|
environment,
|
||||||
cookie_jar,
|
cookie_jar,
|
||||||
download_path,
|
|
||||||
&mut cancel_rx,
|
&mut cancel_rx,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn response_err(
|
async fn response_err<R: Runtime>(
|
||||||
response: &HttpResponse,
|
response: &HttpResponse,
|
||||||
error: String,
|
error: String,
|
||||||
w: &WebviewWindow,
|
w: &WebviewWindow<R>,
|
||||||
) -> Result<HttpResponse, String> {
|
) -> Result<HttpResponse, String> {
|
||||||
warn!("Failed to send request: {}", error);
|
warn!("Failed to send request: {}", error);
|
||||||
let mut response = response.clone();
|
let mut response = response.clone();
|
||||||
@@ -1080,7 +1063,7 @@ async fn cmd_track_event(
|
|||||||
AnalyticsAction::from_str(action),
|
AnalyticsAction::from_str(action),
|
||||||
) {
|
) {
|
||||||
(Ok(resource), Ok(action)) => {
|
(Ok(resource), Ok(action)) => {
|
||||||
analytics::track_event(&window.app_handle(), resource, action, attributes).await;
|
analytics::track_event(&window, resource, action, attributes).await;
|
||||||
}
|
}
|
||||||
(r, a) => {
|
(r, a) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -1635,9 +1618,8 @@ pub fn run() {
|
|||||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
||||||
app.manage(Mutex::new(grpc_handle));
|
app.manage(Mutex::new(grpc_handle));
|
||||||
|
|
||||||
// Add plugin manager
|
let app_handle = app.app_handle().clone();
|
||||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
monitor_plugin_events(&app_handle);
|
||||||
app.manage(Mutex::new(grpc_handle));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
@@ -1715,10 +1697,9 @@ pub fn run() {
|
|||||||
.run(|app_handle, event| {
|
.run(|app_handle, event| {
|
||||||
match event {
|
match event {
|
||||||
RunEvent::Ready => {
|
RunEvent::Ready => {
|
||||||
create_window(app_handle, "/");
|
let w = create_window(app_handle, "/");
|
||||||
let h = app_handle.clone();
|
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let info = analytics::track_launch_event(&h).await;
|
let info = analytics::track_launch_event(&w).await;
|
||||||
debug!("Launched Yaak {:?}", info);
|
debug!("Launched Yaak {:?}", info);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1743,10 +1724,12 @@ pub fn run() {
|
|||||||
|
|
||||||
let h = app_handle.clone();
|
let h = app_handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
|
let windows = h.webview_windows();
|
||||||
|
let w = windows.values().next().unwrap();
|
||||||
tokio::time::sleep(Duration::from_millis(4000)).await;
|
tokio::time::sleep(Duration::from_millis(4000)).await;
|
||||||
let val: State<'_, Mutex<YaakNotifier>> = h.state();
|
let val: State<'_, Mutex<YaakNotifier>> = w.state();
|
||||||
let mut n = val.lock().await;
|
let mut n = val.lock().await;
|
||||||
if let Err(e) = n.check(&h).await {
|
if let Err(e) = n.check(&w).await {
|
||||||
warn!("Failed to check for notifications {}", e)
|
warn!("Failed to check for notifications {}", e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1905,3 +1888,86 @@ fn safe_uri(endpoint: &str) -> String {
|
|||||||
format!("http://{}", endpoint)
|
format!("http://{}", endpoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn monitor_plugin_events<R: Runtime>(app_handle: &AppHandle<R>) {
|
||||||
|
let app_handle = app_handle.clone();
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
let plugin_manager: State<'_, PluginManager> = app_handle.state();
|
||||||
|
let (_rx_id, mut rx) = plugin_manager.subscribe().await;
|
||||||
|
|
||||||
|
let app_handle = app_handle.clone();
|
||||||
|
while let Some(event) = rx.recv().await {
|
||||||
|
let payload = match handle_plugin_event(&app_handle, &event).await {
|
||||||
|
Some(e) => e,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
if let Err(e) = plugin_manager.reply(&event, &payload).await {
|
||||||
|
warn!("Failed to reply to plugin manager: {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_plugin_event<R: Runtime>(
|
||||||
|
app_handle: &AppHandle<R>,
|
||||||
|
event: &InternalEvent,
|
||||||
|
) -> Option<InternalEventPayload> {
|
||||||
|
let event = match event.clone().payload {
|
||||||
|
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
|
||||||
|
let http_request = get_http_request(app_handle, req.id.as_str()).await.ok();
|
||||||
|
InternalEventPayload::GetHttpRequestByIdResponse(GetHttpRequestByIdResponse {
|
||||||
|
http_request,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
InternalEventPayload::SendHttpRequestRequest(req) => {
|
||||||
|
let webview_windows = app_handle.get_focused_window()?.webview_windows();
|
||||||
|
let w = match webview_windows.iter().next() {
|
||||||
|
None => return None,
|
||||||
|
Some((_, w)) => w,
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = w.url().unwrap();
|
||||||
|
let mut query_pairs = url.query_pairs();
|
||||||
|
|
||||||
|
let cookie_jar_id = query_pairs
|
||||||
|
.find(|(k, _v)| k == "cookie_jar_id")
|
||||||
|
.map(|(_k, v)| v.to_string());
|
||||||
|
let cookie_jar = match cookie_jar_id {
|
||||||
|
None => None,
|
||||||
|
Some(id) => get_cookie_jar(w, id.as_str()).await.ok(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let environment_id = query_pairs
|
||||||
|
.find(|(k, _v)| k == "environment_id")
|
||||||
|
.map(|(_k, v)| v.to_string());
|
||||||
|
let environment = match environment_id {
|
||||||
|
None => None,
|
||||||
|
Some(id) => get_environment(w, id.as_str()).await.ok(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let resp = create_default_http_response(w, req.http_request.id.as_str())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result = send_http_request(
|
||||||
|
&w,
|
||||||
|
req.http_request,
|
||||||
|
&resp,
|
||||||
|
environment,
|
||||||
|
cookie_jar,
|
||||||
|
&mut watch::channel(false).1, // No-op cancel channel
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let http_response = match result {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(_e) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
InternalEventPayload::SendHttpRequestResponse(SendHttpRequestResponse { http_response })
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(event)
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use chrono::{DateTime, Duration, Utc};
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{AppHandle, Emitter};
|
use tauri::{Emitter, Manager, Runtime, WebviewWindow};
|
||||||
use yaak_models::queries::{get_key_value_raw, set_key_value_raw};
|
use yaak_models::queries::{get_key_value_raw, set_key_value_raw};
|
||||||
|
|
||||||
// Check for updates every hour
|
// Check for updates every hour
|
||||||
@@ -42,16 +42,16 @@ impl YaakNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn seen(&mut self, app: &AppHandle, id: &str) -> Result<(), String> {
|
pub async fn seen<R: Runtime>(&mut self, w: &WebviewWindow<R>, id: &str) -> Result<(), String> {
|
||||||
let mut seen = get_kv(app).await?;
|
let mut seen = get_kv(w).await?;
|
||||||
seen.push(id.to_string());
|
seen.push(id.to_string());
|
||||||
debug!("Marked notification as seen {}", id);
|
debug!("Marked notification as seen {}", id);
|
||||||
let seen_json = serde_json::to_string(&seen).map_err(|e| e.to_string())?;
|
let seen_json = serde_json::to_string(&seen).map_err(|e| e.to_string())?;
|
||||||
set_key_value_raw(app, KV_NAMESPACE, KV_KEY, seen_json.as_str()).await;
|
set_key_value_raw(w, KV_NAMESPACE, KV_KEY, seen_json.as_str()).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check(&mut self, app: &AppHandle) -> Result<(), String> {
|
pub async fn check<R: Runtime>(&mut self, w: &WebviewWindow<R>) -> Result<(), String> {
|
||||||
let ignore_check = self.last_check.elapsed().unwrap().as_secs() < MAX_UPDATE_CHECK_SECONDS;
|
let ignore_check = self.last_check.elapsed().unwrap().as_secs() < MAX_UPDATE_CHECK_SECONDS;
|
||||||
|
|
||||||
if ignore_check {
|
if ignore_check {
|
||||||
@@ -60,8 +60,8 @@ impl YaakNotifier {
|
|||||||
|
|
||||||
self.last_check = SystemTime::now();
|
self.last_check = SystemTime::now();
|
||||||
|
|
||||||
let num_launches = get_num_launches(app).await;
|
let num_launches = get_num_launches(w).await;
|
||||||
let info = app.package_info().clone();
|
let info = w.app_handle().package_info().clone();
|
||||||
let req = reqwest::Client::default()
|
let req = reqwest::Client::default()
|
||||||
.request(Method::GET, "https://notify.yaak.app/notifications")
|
.request(Method::GET, "https://notify.yaak.app/notifications")
|
||||||
.query(&[
|
.query(&[
|
||||||
@@ -80,21 +80,21 @@ impl YaakNotifier {
|
|||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let age = notification.timestamp.signed_duration_since(Utc::now());
|
let age = notification.timestamp.signed_duration_since(Utc::now());
|
||||||
let seen = get_kv(app).await?;
|
let seen = get_kv(w).await?;
|
||||||
if seen.contains(¬ification.id) || (age > Duration::days(2)) {
|
if seen.contains(¬ification.id) || (age > Duration::days(2)) {
|
||||||
debug!("Already seen notification {}", notification.id);
|
debug!("Already seen notification {}", notification.id);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
debug!("Got notification {:?}", notification);
|
debug!("Got notification {:?}", notification);
|
||||||
|
|
||||||
let _ = app.emit("notification", notification.clone());
|
let _ = w.emit("notification", notification.clone());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_kv(app: &AppHandle) -> Result<Vec<String>, String> {
|
async fn get_kv<R: Runtime>(w: &WebviewWindow<R>) -> Result<Vec<String>, String> {
|
||||||
match get_key_value_raw(app, "notifications", "seen").await {
|
match get_key_value_raw(w, "notifications", "seen").await {
|
||||||
None => Ok(Vec::new()),
|
None => Ok(Vec::new()),
|
||||||
Some(v) => serde_json::from_str(&v.value).map_err(|e| e.to_string()),
|
Some(v) => serde_json::from_str(&v.value).map_err(|e| e.to_string()),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use crate::template_fns::timestamp;
|
use crate::template_fns::timestamp;
|
||||||
use templates::parse_and_render;
|
use yaak_templates::parse_and_render;
|
||||||
use yaak_models::models::{
|
use yaak_models::models::{
|
||||||
Environment, EnvironmentVariable, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace,
|
Environment, EnvironmentVariable, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grpc"
|
name = "yaak_grpc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -15,10 +15,10 @@ use sea_query::Keyword::CurrentTimestamp;
|
|||||||
use sea_query::{Cond, Expr, OnConflict, Order, Query, SqliteQueryBuilder};
|
use sea_query::{Cond, Expr, OnConflict, Order, Query, SqliteQueryBuilder};
|
||||||
use sea_query_rusqlite::RusqliteBinder;
|
use sea_query_rusqlite::RusqliteBinder;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{AppHandle, Emitter, Manager, WebviewWindow, Wry};
|
use tauri::{AppHandle, Emitter, Manager, Runtime, WebviewWindow};
|
||||||
|
|
||||||
pub async fn set_key_value_string(
|
pub async fn set_key_value_string<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &WebviewWindow<R>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
key: &str,
|
key: &str,
|
||||||
value: &str,
|
value: &str,
|
||||||
@@ -27,8 +27,8 @@ pub async fn set_key_value_string(
|
|||||||
set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await
|
set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_key_value_int(
|
pub async fn set_key_value_int<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &WebviewWindow<R>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
key: &str,
|
key: &str,
|
||||||
value: i32,
|
value: i32,
|
||||||
@@ -37,8 +37,8 @@ pub async fn set_key_value_int(
|
|||||||
set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await
|
set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_key_value_string(
|
pub async fn get_key_value_string<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
key: &str,
|
key: &str,
|
||||||
default: &str,
|
default: &str,
|
||||||
@@ -58,8 +58,8 @@ pub async fn get_key_value_string(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_key_value_int(
|
pub async fn get_key_value_int<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
key: &str,
|
key: &str,
|
||||||
default: i32,
|
default: i32,
|
||||||
@@ -79,15 +79,15 @@ pub async fn get_key_value_int(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_key_value_raw(
|
pub async fn set_key_value_raw<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
w: &WebviewWindow<R>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
key: &str,
|
key: &str,
|
||||||
value: &str,
|
value: &str,
|
||||||
) -> (KeyValue, bool) {
|
) -> (KeyValue, bool) {
|
||||||
let existing = get_key_value_raw(mgr, namespace, key).await;
|
let existing = get_key_value_raw(w, namespace, key).await;
|
||||||
|
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*w.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
let (sql, params) = Query::insert()
|
let (sql, params) = Query::insert()
|
||||||
.into_table(KeyValueIden::Table)
|
.into_table(KeyValueIden::Table)
|
||||||
@@ -119,11 +119,11 @@ pub async fn set_key_value_raw(
|
|||||||
let kv = stmt
|
let kv = stmt
|
||||||
.query_row(&*params.as_params(), |row| row.try_into())
|
.query_row(&*params.as_params(), |row| row.try_into())
|
||||||
.expect("Failed to upsert KeyValue");
|
.expect("Failed to upsert KeyValue");
|
||||||
(kv, existing.is_none())
|
(emit_upserted_model(w, kv), existing.is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_key_value_raw(
|
pub async fn get_key_value_raw<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
key: &str,
|
key: &str,
|
||||||
) -> Option<KeyValue> {
|
) -> Option<KeyValue> {
|
||||||
@@ -143,7 +143,7 @@ pub async fn get_key_value_raw(
|
|||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_workspaces(mgr: &impl Manager<Wry>) -> Result<Vec<Workspace>> {
|
pub async fn list_workspaces<R: Runtime>(mgr: &impl Manager<R>) -> Result<Vec<Workspace>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
let (sql, params) = Query::select()
|
let (sql, params) = Query::select()
|
||||||
@@ -155,7 +155,7 @@ pub async fn list_workspaces(mgr: &impl Manager<Wry>) -> Result<Vec<Workspace>>
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_workspace(mgr: &impl Manager<Wry>, id: &str) -> Result<Workspace> {
|
pub async fn get_workspace<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Workspace> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
let (sql, params) = Query::select()
|
let (sql, params) = Query::select()
|
||||||
@@ -167,7 +167,10 @@ pub async fn get_workspace(mgr: &impl Manager<Wry>, id: &str) -> Result<Workspac
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_workspace(window: &WebviewWindow, workspace: Workspace) -> Result<Workspace> {
|
pub async fn upsert_workspace<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
workspace: Workspace,
|
||||||
|
) -> Result<Workspace> {
|
||||||
let id = match workspace.id.as_str() {
|
let id = match workspace.id.as_str() {
|
||||||
"" => generate_model_id(ModelType::TypeWorkspace),
|
"" => generate_model_id(ModelType::TypeWorkspace),
|
||||||
_ => workspace.id.to_string(),
|
_ => workspace.id.to_string(),
|
||||||
@@ -222,7 +225,10 @@ pub async fn upsert_workspace(window: &WebviewWindow, workspace: Workspace) -> R
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_workspace(window: &WebviewWindow, id: &str) -> Result<Workspace> {
|
pub async fn delete_workspace<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<Workspace> {
|
||||||
let workspace = get_workspace(window, id).await?;
|
let workspace = get_workspace(window, id).await?;
|
||||||
|
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
@@ -241,7 +247,7 @@ pub async fn delete_workspace(window: &WebviewWindow, id: &str) -> Result<Worksp
|
|||||||
emit_deleted_model(window, workspace)
|
emit_deleted_model(window, workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_cookie_jar(mgr: &impl Manager<Wry>, id: &str) -> Result<CookieJar> {
|
pub async fn get_cookie_jar<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<CookieJar> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -254,8 +260,8 @@ pub async fn get_cookie_jar(mgr: &impl Manager<Wry>, id: &str) -> Result<CookieJ
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_cookie_jars(
|
pub async fn list_cookie_jars<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
) -> Result<Vec<CookieJar>> {
|
) -> Result<Vec<CookieJar>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -270,7 +276,10 @@ pub async fn list_cookie_jars(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_cookie_jar(window: &WebviewWindow, id: &str) -> Result<CookieJar> {
|
pub async fn delete_cookie_jar<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<CookieJar> {
|
||||||
let cookie_jar = get_cookie_jar(window, id).await?;
|
let cookie_jar = get_cookie_jar(window, id).await?;
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
@@ -284,13 +293,19 @@ pub async fn delete_cookie_jar(window: &WebviewWindow, id: &str) -> Result<Cooki
|
|||||||
emit_deleted_model(window, cookie_jar)
|
emit_deleted_model(window, cookie_jar)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn duplicate_grpc_request(window: &WebviewWindow, id: &str) -> Result<GrpcRequest> {
|
pub async fn duplicate_grpc_request<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<GrpcRequest> {
|
||||||
let mut request = get_grpc_request(window, id).await?.clone();
|
let mut request = get_grpc_request(window, id).await?.clone();
|
||||||
request.id = "".to_string();
|
request.id = "".to_string();
|
||||||
upsert_grpc_request(window, &request).await
|
upsert_grpc_request(window, &request).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_grpc_request(window: &WebviewWindow, id: &str) -> Result<GrpcRequest> {
|
pub async fn delete_grpc_request<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<GrpcRequest> {
|
||||||
let req = get_grpc_request(window, id).await?;
|
let req = get_grpc_request(window, id).await?;
|
||||||
|
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
@@ -304,8 +319,8 @@ pub async fn delete_grpc_request(window: &WebviewWindow, id: &str) -> Result<Grp
|
|||||||
emit_deleted_model(window, req)
|
emit_deleted_model(window, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_grpc_request(
|
pub async fn upsert_grpc_request<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
request: &GrpcRequest,
|
request: &GrpcRequest,
|
||||||
) -> Result<GrpcRequest> {
|
) -> Result<GrpcRequest> {
|
||||||
let id = match request.id.as_str() {
|
let id = match request.id.as_str() {
|
||||||
@@ -346,7 +361,11 @@ pub async fn upsert_grpc_request(
|
|||||||
request.service.as_ref().map(|s| s.as_str()).into(),
|
request.service.as_ref().map(|s| s.as_str()).into(),
|
||||||
request.method.as_ref().map(|s| s.as_str()).into(),
|
request.method.as_ref().map(|s| s.as_str()).into(),
|
||||||
request.message.as_str().into(),
|
request.message.as_str().into(),
|
||||||
request .authentication_type .as_ref() .map(|s| s.as_str()) .into(),
|
request
|
||||||
|
.authentication_type
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.into(),
|
||||||
serde_json::to_string(&request.authentication)?.into(),
|
serde_json::to_string(&request.authentication)?.into(),
|
||||||
serde_json::to_string(&request.metadata)?.into(),
|
serde_json::to_string(&request.metadata)?.into(),
|
||||||
])
|
])
|
||||||
@@ -376,7 +395,7 @@ pub async fn upsert_grpc_request(
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_grpc_request(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcRequest> {
|
pub async fn get_grpc_request<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<GrpcRequest> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -389,8 +408,8 @@ pub async fn get_grpc_request(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcR
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_grpc_requests(
|
pub async fn list_grpc_requests<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
) -> Result<Vec<GrpcRequest>> {
|
) -> Result<Vec<GrpcRequest>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -405,8 +424,8 @@ pub async fn list_grpc_requests(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_grpc_connection(
|
pub async fn upsert_grpc_connection<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
connection: &GrpcConnection,
|
connection: &GrpcConnection,
|
||||||
) -> Result<GrpcConnection> {
|
) -> Result<GrpcConnection> {
|
||||||
let id = match connection.id.as_str() {
|
let id = match connection.id.as_str() {
|
||||||
@@ -467,7 +486,10 @@ pub async fn upsert_grpc_connection(
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_grpc_connection(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcConnection> {
|
pub async fn get_grpc_connection<R: Runtime>(
|
||||||
|
mgr: &impl Manager<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<GrpcConnection> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
let (sql, params) = Query::select()
|
let (sql, params) = Query::select()
|
||||||
@@ -479,8 +501,8 @@ pub async fn get_grpc_connection(mgr: &impl Manager<Wry>, id: &str) -> Result<Gr
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_grpc_connections(
|
pub async fn list_grpc_connections<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
) -> Result<Vec<GrpcConnection>> {
|
) -> Result<Vec<GrpcConnection>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -497,7 +519,10 @@ pub async fn list_grpc_connections(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_grpc_connection(window: &WebviewWindow, id: &str) -> Result<GrpcConnection> {
|
pub async fn delete_grpc_connection<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<GrpcConnection> {
|
||||||
let resp = get_grpc_connection(window, id).await?;
|
let resp = get_grpc_connection(window, id).await?;
|
||||||
|
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
@@ -512,14 +537,20 @@ pub async fn delete_grpc_connection(window: &WebviewWindow, id: &str) -> Result<
|
|||||||
emit_deleted_model(window, resp)
|
emit_deleted_model(window, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_all_grpc_connections(window: &WebviewWindow, request_id: &str) -> Result<()> {
|
pub async fn delete_all_grpc_connections<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
request_id: &str,
|
||||||
|
) -> Result<()> {
|
||||||
for r in list_grpc_connections(window, request_id).await? {
|
for r in list_grpc_connections(window, request_id).await? {
|
||||||
delete_grpc_connection(window, &r.id).await?;
|
delete_grpc_connection(window, &r.id).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_grpc_event(window: &WebviewWindow, event: &GrpcEvent) -> Result<GrpcEvent> {
|
pub async fn upsert_grpc_event<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
event: &GrpcEvent,
|
||||||
|
) -> Result<GrpcEvent> {
|
||||||
let id = match event.id.as_str() {
|
let id = match event.id.as_str() {
|
||||||
"" => generate_model_id(ModelType::TypeGrpcEvent),
|
"" => generate_model_id(ModelType::TypeGrpcEvent),
|
||||||
_ => event.id.to_string(),
|
_ => event.id.to_string(),
|
||||||
@@ -575,7 +606,7 @@ pub async fn upsert_grpc_event(window: &WebviewWindow, event: &GrpcEvent) -> Res
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_grpc_event(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcEvent> {
|
pub async fn get_grpc_event<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<GrpcEvent> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
let (sql, params) = Query::select()
|
let (sql, params) = Query::select()
|
||||||
@@ -587,8 +618,8 @@ pub async fn get_grpc_event(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcEve
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_grpc_events(
|
pub async fn list_grpc_events<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
connection_id: &str,
|
connection_id: &str,
|
||||||
) -> Result<Vec<GrpcEvent>> {
|
) -> Result<Vec<GrpcEvent>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -605,8 +636,8 @@ pub async fn list_grpc_events(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_cookie_jar(
|
pub async fn upsert_cookie_jar<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
cookie_jar: &CookieJar,
|
cookie_jar: &CookieJar,
|
||||||
) -> Result<CookieJar> {
|
) -> Result<CookieJar> {
|
||||||
let id = match cookie_jar.id.as_str() {
|
let id = match cookie_jar.id.as_str() {
|
||||||
@@ -653,8 +684,8 @@ pub async fn upsert_cookie_jar(
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_environments(
|
pub async fn list_environments<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
) -> Result<Vec<Environment>> {
|
) -> Result<Vec<Environment>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -671,7 +702,10 @@ pub async fn list_environments(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_environment(window: &WebviewWindow, id: &str) -> Result<Environment> {
|
pub async fn delete_environment<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<Environment> {
|
||||||
let env = get_environment(window, id).await?;
|
let env = get_environment(window, id).await?;
|
||||||
|
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
@@ -686,7 +720,7 @@ pub async fn delete_environment(window: &WebviewWindow, id: &str) -> Result<Envi
|
|||||||
emit_deleted_model(window, env)
|
emit_deleted_model(window, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_settings(mgr: &impl Manager<Wry>) -> Result<Settings> {
|
async fn get_settings<R: Runtime>(mgr: &impl Manager<R>) -> Result<Settings> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -699,7 +733,7 @@ async fn get_settings(mgr: &impl Manager<Wry>) -> Result<Settings> {
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_or_create_settings(mgr: &impl Manager<Wry>) -> Settings {
|
pub async fn get_or_create_settings<R: Runtime>(mgr: &impl Manager<R>) -> Settings {
|
||||||
if let Ok(settings) = get_settings(mgr).await {
|
if let Ok(settings) = get_settings(mgr).await {
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
@@ -721,7 +755,10 @@ pub async fn get_or_create_settings(mgr: &impl Manager<Wry>) -> Settings {
|
|||||||
.expect("Failed to insert Settings")
|
.expect("Failed to insert Settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_settings(window: &WebviewWindow, settings: Settings) -> Result<Settings> {
|
pub async fn update_settings<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
settings: Settings,
|
||||||
|
) -> Result<Settings> {
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -773,8 +810,8 @@ pub async fn update_settings(window: &WebviewWindow, settings: Settings) -> Resu
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_environment(
|
pub async fn upsert_environment<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
environment: Environment,
|
environment: Environment,
|
||||||
) -> Result<Environment> {
|
) -> Result<Environment> {
|
||||||
let id = match environment.id.as_str() {
|
let id = match environment.id.as_str() {
|
||||||
@@ -821,7 +858,7 @@ pub async fn upsert_environment(
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_environment(mgr: &impl Manager<Wry>, id: &str) -> Result<Environment> {
|
pub async fn get_environment<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Environment> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -834,7 +871,7 @@ pub async fn get_environment(mgr: &impl Manager<Wry>, id: &str) -> Result<Enviro
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_folder(mgr: &impl Manager<Wry>, id: &str) -> Result<Folder> {
|
pub async fn get_folder<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Folder> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -847,7 +884,10 @@ pub async fn get_folder(mgr: &impl Manager<Wry>, id: &str) -> Result<Folder> {
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_folders(mgr: &impl Manager<Wry>, workspace_id: &str) -> Result<Vec<Folder>> {
|
pub async fn list_folders<R: Runtime>(
|
||||||
|
mgr: &impl Manager<R>,
|
||||||
|
workspace_id: &str,
|
||||||
|
) -> Result<Vec<Folder>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -862,7 +902,7 @@ pub async fn list_folders(mgr: &impl Manager<Wry>, workspace_id: &str) -> Result
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_folder(window: &WebviewWindow, id: &str) -> Result<Folder> {
|
pub async fn delete_folder<R: Runtime>(window: &WebviewWindow<R>, id: &str) -> Result<Folder> {
|
||||||
let folder = get_folder(window, id).await?;
|
let folder = get_folder(window, id).await?;
|
||||||
|
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
@@ -877,7 +917,7 @@ pub async fn delete_folder(window: &WebviewWindow, id: &str) -> Result<Folder> {
|
|||||||
emit_deleted_model(window, folder)
|
emit_deleted_model(window, folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_folder(window: &WebviewWindow, r: Folder) -> Result<Folder> {
|
pub async fn upsert_folder<R: Runtime>(window: &WebviewWindow<R>, r: Folder) -> Result<Folder> {
|
||||||
let id = match r.id.as_str() {
|
let id = match r.id.as_str() {
|
||||||
"" => generate_model_id(ModelType::TypeFolder),
|
"" => generate_model_id(ModelType::TypeFolder),
|
||||||
_ => r.id.to_string(),
|
_ => r.id.to_string(),
|
||||||
@@ -925,13 +965,19 @@ pub async fn upsert_folder(window: &WebviewWindow, r: Folder) -> Result<Folder>
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn duplicate_http_request(window: &WebviewWindow, id: &str) -> Result<HttpRequest> {
|
pub async fn duplicate_http_request<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<HttpRequest> {
|
||||||
let mut request = get_http_request(window, id).await?.clone();
|
let mut request = get_http_request(window, id).await?.clone();
|
||||||
request.id = "".to_string();
|
request.id = "".to_string();
|
||||||
upsert_http_request(window, request).await
|
upsert_http_request(window, request).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert_http_request(window: &WebviewWindow, r: HttpRequest) -> Result<HttpRequest> {
|
pub async fn upsert_http_request<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
r: HttpRequest,
|
||||||
|
) -> Result<HttpRequest> {
|
||||||
let id = match r.id.as_str() {
|
let id = match r.id.as_str() {
|
||||||
"" => generate_model_id(ModelType::TypeHttpRequest),
|
"" => generate_model_id(ModelType::TypeHttpRequest),
|
||||||
_ => r.id.to_string(),
|
_ => r.id.to_string(),
|
||||||
@@ -1004,8 +1050,8 @@ pub async fn upsert_http_request(window: &WebviewWindow, r: HttpRequest) -> Resu
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_http_requests(
|
pub async fn list_http_requests<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
) -> Result<Vec<HttpRequest>> {
|
) -> Result<Vec<HttpRequest>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -1021,7 +1067,7 @@ pub async fn list_http_requests(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_http_request(mgr: &impl Manager<Wry>, id: &str) -> Result<HttpRequest> {
|
pub async fn get_http_request<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<HttpRequest> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
|
|
||||||
@@ -1034,7 +1080,10 @@ pub async fn get_http_request(mgr: &impl Manager<Wry>, id: &str) -> Result<HttpR
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_http_request(window: &WebviewWindow, id: &str) -> Result<HttpRequest> {
|
pub async fn delete_http_request<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<HttpRequest> {
|
||||||
let req = get_http_request(window, id).await?;
|
let req = get_http_request(window, id).await?;
|
||||||
|
|
||||||
// DB deletes will cascade but this will delete the files
|
// DB deletes will cascade but this will delete the files
|
||||||
@@ -1051,9 +1100,30 @@ pub async fn delete_http_request(window: &WebviewWindow, id: &str) -> Result<Htt
|
|||||||
emit_deleted_model(window, req)
|
emit_deleted_model(window, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_default_http_response<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
request_id: &str,
|
||||||
|
) -> Result<HttpResponse> {
|
||||||
|
create_http_response(
|
||||||
|
&window,
|
||||||
|
request_id,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
vec![],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn create_http_response(
|
pub async fn create_http_response<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
elapsed: i64,
|
elapsed: i64,
|
||||||
elapsed_headers: i64,
|
elapsed_headers: i64,
|
||||||
@@ -1146,8 +1216,8 @@ pub async fn cancel_pending_responses(app: &AppHandle) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_response_if_id(
|
pub async fn update_response_if_id<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
response: &HttpResponse,
|
response: &HttpResponse,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
if response.id.is_empty() {
|
if response.id.is_empty() {
|
||||||
@@ -1157,8 +1227,8 @@ pub async fn update_response_if_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_response(
|
pub async fn update_response<R: Runtime>(
|
||||||
window: &WebviewWindow,
|
window: &WebviewWindow<R>,
|
||||||
response: &HttpResponse,
|
response: &HttpResponse,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||||
@@ -1211,7 +1281,10 @@ pub async fn update_response(
|
|||||||
Ok(emit_upserted_model(window, m))
|
Ok(emit_upserted_model(window, m))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_http_response(mgr: &impl Manager<Wry>, id: &str) -> Result<HttpResponse> {
|
pub async fn get_http_response<R: Runtime>(
|
||||||
|
mgr: &impl Manager<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<HttpResponse> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
let (sql, params) = Query::select()
|
let (sql, params) = Query::select()
|
||||||
@@ -1223,7 +1296,10 @@ pub async fn get_http_response(mgr: &impl Manager<Wry>, id: &str) -> Result<Http
|
|||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_http_response(window: &WebviewWindow, id: &str) -> Result<HttpResponse> {
|
pub async fn delete_http_response<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<HttpResponse> {
|
||||||
let resp = get_http_response(window, id).await?;
|
let resp = get_http_response(window, id).await?;
|
||||||
|
|
||||||
// Delete the body file if it exists
|
// Delete the body file if it exists
|
||||||
@@ -1244,15 +1320,18 @@ pub async fn delete_http_response(window: &WebviewWindow, id: &str) -> Result<Ht
|
|||||||
emit_deleted_model(window, resp)
|
emit_deleted_model(window, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_all_http_responses(window: &WebviewWindow, request_id: &str) -> Result<()> {
|
pub async fn delete_all_http_responses<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
request_id: &str,
|
||||||
|
) -> Result<()> {
|
||||||
for r in list_responses(window, request_id, None).await? {
|
for r in list_responses(window, request_id, None).await? {
|
||||||
delete_http_response(window, &r.id).await?;
|
delete_http_response(window, &r.id).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_responses(
|
pub async fn list_responses<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
) -> Result<Vec<HttpResponse>> {
|
) -> Result<Vec<HttpResponse>> {
|
||||||
@@ -1271,8 +1350,8 @@ pub async fn list_responses(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_responses_by_workspace_id(
|
pub async fn list_responses_by_workspace_id<R: Runtime>(
|
||||||
mgr: &impl Manager<Wry>,
|
mgr: &impl Manager<R>,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
) -> Result<Vec<HttpResponse>> {
|
) -> Result<Vec<HttpResponse>> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
@@ -1288,7 +1367,7 @@ pub async fn list_responses_by_workspace_id(
|
|||||||
Ok(items.map(|v| v.unwrap()).collect())
|
Ok(items.map(|v| v.unwrap()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn debug_pool(mgr: &impl Manager<Wry>) {
|
pub async fn debug_pool<R: Runtime>(mgr: &impl Manager<R>) {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await;
|
let db = dbm.0.lock().await;
|
||||||
debug!("Debug database state: {:?}", db.state());
|
debug!("Debug database state: {:?}", db.state());
|
||||||
@@ -1310,7 +1389,7 @@ struct ModelPayload<M: Serialize + Clone> {
|
|||||||
pub window_label: String,
|
pub window_label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_upserted_model<M: Serialize + Clone>(window: &WebviewWindow, model: M) -> M {
|
fn emit_upserted_model<M: Serialize + Clone, R: Runtime>(window: &WebviewWindow<R>, model: M) -> M {
|
||||||
let payload = ModelPayload {
|
let payload = ModelPayload {
|
||||||
model: model.clone(),
|
model: model.clone(),
|
||||||
window_label: window.label().to_string(),
|
window_label: window.label().to_string(),
|
||||||
@@ -1320,7 +1399,10 @@ fn emit_upserted_model<M: Serialize + Clone>(window: &WebviewWindow, model: M) -
|
|||||||
model
|
model
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_deleted_model<M: Serialize + Clone>(window: &WebviewWindow, model: M) -> Result<M> {
|
fn emit_deleted_model<M: Serialize + Clone, R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
model: M,
|
||||||
|
) -> Result<M> {
|
||||||
let payload = ModelPayload {
|
let payload = ModelPayload {
|
||||||
model: model.clone(),
|
model: model.clone(),
|
||||||
window_label: window.label().to_string(),
|
window_label: window.label().to_string(),
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
|
|
||||||
use yaak_models::models::{CookieJar, Environment, Folder, GrpcConnection, GrpcEvent, GrpcRequest, HttpRequest, HttpResponse, KeyValue, Settings, Workspace};
|
use yaak_models::models::{
|
||||||
|
CookieJar, Environment, Folder, GrpcConnection, GrpcEvent, GrpcRequest, HttpRequest,
|
||||||
|
HttpResponse, KeyValue, Settings, Workspace,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -20,12 +23,22 @@ pub struct InternalEvent {
|
|||||||
pub enum InternalEventPayload {
|
pub enum InternalEventPayload {
|
||||||
BootRequest(BootRequest),
|
BootRequest(BootRequest),
|
||||||
BootResponse(BootResponse),
|
BootResponse(BootResponse),
|
||||||
|
|
||||||
ImportRequest(ImportRequest),
|
ImportRequest(ImportRequest),
|
||||||
ImportResponse(ImportResponse),
|
ImportResponse(ImportResponse),
|
||||||
|
|
||||||
FilterRequest(FilterRequest),
|
FilterRequest(FilterRequest),
|
||||||
FilterResponse(FilterResponse),
|
FilterResponse(FilterResponse),
|
||||||
|
|
||||||
ExportHttpRequestRequest(ExportHttpRequestRequest),
|
ExportHttpRequestRequest(ExportHttpRequestRequest),
|
||||||
ExportHttpRequestResponse(ExportHttpRequestResponse),
|
ExportHttpRequestResponse(ExportHttpRequestResponse),
|
||||||
|
|
||||||
|
SendHttpRequestRequest(SendHttpRequestRequest),
|
||||||
|
SendHttpRequestResponse(SendHttpRequestResponse),
|
||||||
|
|
||||||
|
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
|
||||||
|
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
|
||||||
|
|
||||||
/// Returned when a plugin doesn't get run, just so the server
|
/// Returned when a plugin doesn't get run, just so the server
|
||||||
/// has something to listen for
|
/// has something to listen for
|
||||||
EmptyResponse(EmptyResponse),
|
EmptyResponse(EmptyResponse),
|
||||||
@@ -95,17 +108,33 @@ pub struct ExportHttpRequestResponse {
|
|||||||
pub content: String,
|
pub content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Migrate plugins to return this type
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
// #[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[serde(default, rename_all = "camelCase")]
|
||||||
// #[serde(rename_all = "camelCase", untagged)]
|
#[ts(export)]
|
||||||
// #[ts(export)]
|
pub struct SendHttpRequestRequest {
|
||||||
// pub enum ExportableModel {
|
pub http_request: HttpRequest,
|
||||||
// Workspace(Workspace),
|
}
|
||||||
// Environment(Environment),
|
|
||||||
// Folder(Folder),
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
// HttpRequest(HttpRequest),
|
#[serde(default, rename_all = "camelCase")]
|
||||||
// GrpcRequest(GrpcRequest),
|
#[ts(export)]
|
||||||
// }
|
pub struct SendHttpRequestResponse {
|
||||||
|
pub http_response: HttpResponse,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(default, rename_all = "camelCase")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct GetHttpRequestByIdRequest {
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(default, rename_all = "camelCase")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct GetHttpRequestByIdResponse {
|
||||||
|
pub http_request: Option<HttpRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase")]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::events::{
|
use crate::events::{
|
||||||
ExportHttpRequestRequest, ExportHttpRequestResponse, FilterRequest, FilterResponse,
|
ExportHttpRequestRequest, ExportHttpRequestResponse, FilterRequest, FilterResponse
|
||||||
ImportRequest, ImportResponse, InternalEventPayload,
|
, ImportRequest, ImportResponse, InternalEvent, InternalEventPayload,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::Error::PluginErr;
|
use crate::error::Error::PluginErr;
|
||||||
@@ -10,6 +10,7 @@ use crate::plugin::start_server;
|
|||||||
use crate::server::PluginRuntimeGrpcServer;
|
use crate::server::PluginRuntimeGrpcServer;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tauri::{AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime};
|
||||||
|
use tokio::sync::mpsc;
|
||||||
use tokio::sync::watch::Sender;
|
use tokio::sync::watch::Sender;
|
||||||
use yaak_models::models::HttpRequest;
|
use yaak_models::models::HttpRequest;
|
||||||
|
|
||||||
@@ -35,14 +36,33 @@ impl PluginManager {
|
|||||||
PluginManager { kill_tx, server }
|
PluginManager { kill_tx, server }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn cleanup(&mut self) {
|
pub async fn subscribe(&self) -> (String, mpsc::Receiver<InternalEvent>) {
|
||||||
|
self.server.subscribe().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn unsubscribe(&self, rx_id: &str) {
|
||||||
|
self.server.unsubscribe(rx_id).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cleanup(&self) {
|
||||||
self.kill_tx.send_replace(true);
|
self.kill_tx.send_replace(true);
|
||||||
|
|
||||||
// Give it a bit of time to kill
|
// Give it a bit of time to kill
|
||||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_import(&mut self, content: &str) -> Result<(ImportResponse, String)> {
|
pub async fn reply(
|
||||||
|
&self,
|
||||||
|
source_event: &InternalEvent,
|
||||||
|
payload: &InternalEventPayload,
|
||||||
|
) -> Result<()> {
|
||||||
|
let reply_id = Some(source_event.clone().id);
|
||||||
|
self.server
|
||||||
|
.send(&payload, source_event.plugin_ref_id.as_str(), reply_id)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run_import(&self, content: &str) -> Result<(ImportResponse, String)> {
|
||||||
let reply_events = self
|
let reply_events = self
|
||||||
.server
|
.server
|
||||||
.send_and_wait(&InternalEventPayload::ImportRequest(ImportRequest {
|
.send_and_wait(&InternalEventPayload::ImportRequest(ImportRequest {
|
||||||
@@ -67,7 +87,7 @@ impl PluginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_export_curl(
|
pub async fn run_export_curl(
|
||||||
&mut self,
|
&self,
|
||||||
request: &HttpRequest,
|
request: &HttpRequest,
|
||||||
) -> Result<ExportHttpRequestResponse> {
|
) -> Result<ExportHttpRequestResponse> {
|
||||||
let event = self
|
let event = self
|
||||||
@@ -90,7 +110,7 @@ impl PluginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_filter(
|
pub async fn run_filter(
|
||||||
&mut self,
|
&self,
|
||||||
filter: &str,
|
filter: &str,
|
||||||
content: &str,
|
content: &str,
|
||||||
content_type: &str,
|
content_type: &str,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ use tauri::plugin::{Builder, TauriPlugin};
|
|||||||
use tauri::{Manager, RunEvent, Runtime, State};
|
use tauri::{Manager, RunEvent, Runtime, State};
|
||||||
use tokio::fs::read_dir;
|
use tokio::fs::read_dir;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio::sync::Mutex;
|
|
||||||
use tonic::codegen::tokio_stream;
|
use tonic::codegen::tokio_stream;
|
||||||
use tonic::transport::Server;
|
use tonic::transport::Server;
|
||||||
|
|
||||||
@@ -30,8 +29,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to read plugins dir");
|
.expect("Failed to read plugins dir");
|
||||||
let manager = PluginManager::new(&app, plugin_dirs).await;
|
let manager = PluginManager::new(&app, plugin_dirs).await;
|
||||||
let manager_state = Mutex::new(manager);
|
app.manage(manager);
|
||||||
app.manage(manager_state);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -41,8 +39,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
api.prevent_exit();
|
api.prevent_exit();
|
||||||
tauri::async_runtime::block_on(async move {
|
tauri::async_runtime::block_on(async move {
|
||||||
info!("Exiting plugin runtime due to app exit");
|
info!("Exiting plugin runtime due to app exit");
|
||||||
let manager: State<Mutex<PluginManager>> = app.state();
|
let manager: State<PluginManager> = app.state();
|
||||||
manager.lock().await.cleanup().await;
|
manager.cleanup().await;
|
||||||
exit(0);
|
exit(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -79,7 +77,7 @@ pub async fn start_server(
|
|||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
server.unsubscribe(rx_id).await;
|
server.unsubscribe(rx_id.as_str()).await;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ impl PluginRuntimeGrpcServer {
|
|||||||
(id, rx)
|
(id, rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn unsubscribe(&self, rx_id: String) {
|
pub async fn unsubscribe(&self, rx_id: &str) {
|
||||||
self.subscribers.lock().await.remove(rx_id.as_str());
|
self.subscribers.lock().await.remove(rx_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove_plugins(&self, plugin_ids: Vec<String>) {
|
pub async fn remove_plugins(&self, plugin_ids: Vec<String>) {
|
||||||
@@ -214,6 +214,13 @@ impl PluginRuntimeGrpcServer {
|
|||||||
let msg = format!("Failed to find plugin for {plugin_name}");
|
let msg = format!("Failed to find plugin for {plugin_name}");
|
||||||
Err(PluginNotFoundErr(msg))
|
Err(PluginNotFoundErr(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send(&self, payload: &InternalEventPayload, plugin_ref_id: &str, reply_id: Option<String>)-> Result<()> {
|
||||||
|
let plugin = self.plugin_by_ref_id(plugin_ref_id).await?;
|
||||||
|
let event = plugin.build_event_to_send(payload, reply_id);
|
||||||
|
plugin.send(&event).await
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn send_to_plugin(
|
pub async fn send_to_plugin(
|
||||||
&self,
|
&self,
|
||||||
@@ -301,7 +308,7 @@ impl PluginRuntimeGrpcServer {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server.unsubscribe(rx_id).await;
|
server.unsubscribe(rx_id.as_str()).await;
|
||||||
|
|
||||||
found_events
|
found_events
|
||||||
})
|
})
|
||||||
@@ -321,30 +328,6 @@ impl PluginRuntimeGrpcServer {
|
|||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send(&self, payload: InternalEventPayload) -> Result<Vec<InternalEvent>> {
|
|
||||||
let mut events: Vec<InternalEvent> = Vec::new();
|
|
||||||
let plugins = self.plugin_ref_to_plugin.lock().await;
|
|
||||||
if plugins.is_empty() {
|
|
||||||
return Err(NoPluginsErr("Send failed because no plugins exist".into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for ph in plugins.values() {
|
|
||||||
let event = ph.build_event_to_send(&payload, None);
|
|
||||||
self.send_to_plugin_handle(ph, &event).await?;
|
|
||||||
events.push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(events)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_to_plugin_handle(
|
|
||||||
&self,
|
|
||||||
plugin: &PluginHandle,
|
|
||||||
event: &InternalEvent,
|
|
||||||
) -> Result<()> {
|
|
||||||
plugin.send(event).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_plugins(
|
async fn load_plugins(
|
||||||
&self,
|
&self,
|
||||||
to_plugin_tx: mpsc::Sender<tonic::Result<EventStreamEvent>>,
|
to_plugin_tx: mpsc::Sender<tonic::Result<EventStreamEvent>>,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "templates"
|
name = "yaak_templates"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -4,9 +4,8 @@ import type { KeyboardEvent, ReactNode } from 'react';
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
|
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||||
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
||||||
import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
|
import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
|
||||||
@@ -56,8 +55,8 @@ const MAX_PER_GROUP = 8;
|
|||||||
export function CommandPalette({ onClose }: { onClose: () => void }) {
|
export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||||
const [command, setCommand] = useDebouncedState<string>('', 150);
|
const [command, setCommand] = useDebouncedState<string>('', 150);
|
||||||
const [selectedItemKey, setSelectedItemKey] = useState<string | null>(null);
|
const [selectedItemKey, setSelectedItemKey] = useState<string | null>(null);
|
||||||
|
const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const environments = useEnvironments();
|
const environments = useEnvironments();
|
||||||
const recentEnvironments = useRecentEnvironments();
|
const recentEnvironments = useRecentEnvironments();
|
||||||
@@ -68,12 +67,11 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
const openWorkspace = useOpenWorkspace();
|
const openWorkspace = useOpenWorkspace();
|
||||||
const createWorkspace = useCreateWorkspace();
|
const createWorkspace = useCreateWorkspace();
|
||||||
const createHttpRequest = useCreateHttpRequest();
|
const createHttpRequest = useCreateHttpRequest();
|
||||||
const { activeCookieJar } = useActiveCookieJar();
|
const [activeCookieJar] = useActiveCookieJar();
|
||||||
const createGrpcRequest = useCreateGrpcRequest();
|
const createGrpcRequest = useCreateGrpcRequest();
|
||||||
const createEnvironment = useCreateEnvironment();
|
const createEnvironment = useCreateEnvironment();
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const activeEnvironment = useActiveEnvironment();
|
|
||||||
const sendRequest = useSendAnyHttpRequest();
|
const sendRequest = useSendAnyHttpRequest();
|
||||||
const renameRequest = useRenameRequest(activeRequest?.id ?? null);
|
const renameRequest = useRenameRequest(activeRequest?.id ?? null);
|
||||||
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
||||||
@@ -86,9 +84,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
label: 'Open Settings',
|
label: 'Open Settings',
|
||||||
action: 'settings.show',
|
action: 'settings.show',
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
if (workspaceId == null) return;
|
if (workspace == null) return;
|
||||||
await invokeCmd('cmd_new_nested_window', {
|
await invokeCmd('cmd_new_nested_window', {
|
||||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
url: routes.paths.workspaceSettings({ workspaceId: workspace.id }),
|
||||||
label: 'settings',
|
label: 'settings',
|
||||||
title: 'Yaak Settings',
|
title: 'Yaak Settings',
|
||||||
});
|
});
|
||||||
@@ -190,7 +188,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
routes.paths,
|
routes.paths,
|
||||||
sendRequest,
|
sendRequest,
|
||||||
setSidebarHidden,
|
setSidebarHidden,
|
||||||
workspaceId,
|
workspace,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const sortedRequests = useMemo(() => {
|
const sortedRequests = useMemo(() => {
|
||||||
@@ -271,7 +269,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
return routes.navigate('request', {
|
return routes.navigate('request', {
|
||||||
workspaceId: r.workspaceId,
|
workspaceId: r.workspaceId,
|
||||||
requestId: r.id,
|
requestId: r.id,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -290,7 +288,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
environmentGroup.items.push({
|
environmentGroup.items.push({
|
||||||
key: `switch-environment-${e.id}`,
|
key: `switch-environment-${e.id}`,
|
||||||
label: e.name,
|
label: e.name,
|
||||||
onSelect: () => routes.setEnvironment(e),
|
onSelect: () => setActiveEnvironmentId(e.id),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,9 +311,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
workspaceCommands,
|
workspaceCommands,
|
||||||
sortedRequests,
|
sortedRequests,
|
||||||
routes,
|
routes,
|
||||||
activeEnvironmentId,
|
activeEnvironment,
|
||||||
sortedEnvironments,
|
sortedEnvironments,
|
||||||
activeEnvironment?.id,
|
setActiveEnvironmentId,
|
||||||
sortedWorkspaces,
|
sortedWorkspaces,
|
||||||
openWorkspace,
|
openWorkspace,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ interface Props {
|
|||||||
|
|
||||||
export const CookieDialog = function ({ cookieJarId }: Props) {
|
export const CookieDialog = function ({ cookieJarId }: Props) {
|
||||||
const updateCookieJar = useUpdateCookieJar(cookieJarId ?? null);
|
const updateCookieJar = useUpdateCookieJar(cookieJarId ?? null);
|
||||||
const cookieJars = useCookieJars();
|
const cookieJars = useCookieJars().data ?? [];
|
||||||
const cookieJar = cookieJars.find((c) => c.id === cookieJarId);
|
const cookieJar = cookieJars.find((c) => c.id === cookieJarId);
|
||||||
|
|
||||||
if (cookieJar == null) {
|
if (cookieJar == null) {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import { InlineCode } from './core/InlineCode';
|
|||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from './DialogContext';
|
||||||
|
|
||||||
export function CookieDropdown() {
|
export function CookieDropdown() {
|
||||||
const cookieJars = useCookieJars();
|
const cookieJars = useCookieJars().data ?? [];
|
||||||
const { activeCookieJar, setActiveCookieJarId } = useActiveCookieJar();
|
const [activeCookieJar, setActiveCookieJarId] = useActiveCookieJar();
|
||||||
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
||||||
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
||||||
const createCookieJar = useCreateCookieJar();
|
const createCookieJar = useCreateCookieJar();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
@@ -20,9 +19,8 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
|||||||
...buttonProps
|
...buttonProps
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const environments = useEnvironments();
|
const environments = useEnvironments();
|
||||||
const activeEnvironment = useActiveEnvironment();
|
const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment();
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const routes = useAppRoutes();
|
|
||||||
|
|
||||||
const showEnvironmentDialog = useCallback(() => {
|
const showEnvironmentDialog = useCallback(() => {
|
||||||
dialog.toggle({
|
dialog.toggle({
|
||||||
@@ -43,9 +41,9 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
|||||||
leftSlot: e.id === activeEnvironment?.id ? <Icon icon="check" /> : <Icon icon="empty" />,
|
leftSlot: e.id === activeEnvironment?.id ? <Icon icon="check" /> : <Icon icon="empty" />,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
if (e.id !== activeEnvironment?.id) {
|
if (e.id !== activeEnvironment?.id) {
|
||||||
routes.setEnvironment(e);
|
setActiveEnvironmentId(e.id);
|
||||||
} else {
|
} else {
|
||||||
routes.setEnvironment(null);
|
setActiveEnvironmentId(null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -62,7 +60,7 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
|||||||
onSelect: showEnvironmentDialog,
|
onSelect: showEnvironmentDialog,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[activeEnvironment?.id, environments, routes, showEnvironmentDialog],
|
[activeEnvironment?.id, environments, setActiveEnvironmentId, showEnvironmentDialog],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||||
import type { Model } from '@yaakapp/api';
|
import type { Model } from '@yaakapp/api';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useAtiveWorkspaceChangedToast } from '../hooks/useAtiveWorkspaceChangedToast';
|
import { useEnsureActiveCookieJar, useMigrateActiveCookieJarId } from '../hooks/useActiveCookieJar';
|
||||||
|
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
||||||
import { cookieJarsQueryKey } from '../hooks/useCookieJars';
|
import { cookieJarsQueryKey } from '../hooks/useCookieJars';
|
||||||
import { useCopy } from '../hooks/useCopy';
|
import { useCopy } from '../hooks/useCopy';
|
||||||
import { environmentsQueryKey } from '../hooks/useEnvironments';
|
import { environmentsQueryKey } from '../hooks/useEnvironments';
|
||||||
@@ -16,6 +17,7 @@ import { httpResponsesQueryKey } from '../hooks/useHttpResponses';
|
|||||||
import { keyValueQueryKey } from '../hooks/useKeyValue';
|
import { keyValueQueryKey } from '../hooks/useKeyValue';
|
||||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||||
import { useNotificationToast } from '../hooks/useNotificationToast';
|
import { useNotificationToast } from '../hooks/useNotificationToast';
|
||||||
|
import { useRecentCookieJars } from '../hooks/useRecentCookieJars';
|
||||||
import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
|
import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
|
||||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||||
@@ -25,6 +27,7 @@ import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
|
|||||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
||||||
import { workspacesQueryKey } from '../hooks/useWorkspaces';
|
import { workspacesQueryKey } from '../hooks/useWorkspaces';
|
||||||
import { useZoom } from '../hooks/useZoom';
|
import { useZoom } from '../hooks/useZoom';
|
||||||
|
import { extractKeyValue } from '../lib/keyValueStore';
|
||||||
import { modelsEq } from '../lib/models';
|
import { modelsEq } from '../lib/models';
|
||||||
import { catppuccinMacchiato } from '../lib/theme/themes/catppuccin';
|
import { catppuccinMacchiato } from '../lib/theme/themes/catppuccin';
|
||||||
import { githubLight } from '../lib/theme/themes/github';
|
import { githubLight } from '../lib/theme/themes/github';
|
||||||
@@ -38,12 +41,17 @@ export function GlobalHooks() {
|
|||||||
// Include here so they always update, even if no component references them
|
// Include here so they always update, even if no component references them
|
||||||
useRecentWorkspaces();
|
useRecentWorkspaces();
|
||||||
useRecentEnvironments();
|
useRecentEnvironments();
|
||||||
|
useRecentCookieJars();
|
||||||
useRecentRequests();
|
useRecentRequests();
|
||||||
|
|
||||||
// Other useful things
|
// Other useful things
|
||||||
useSyncThemeToDocument();
|
useSyncThemeToDocument();
|
||||||
useNotificationToast();
|
useNotificationToast();
|
||||||
useAtiveWorkspaceChangedToast();
|
useActiveWorkspaceChangedToast();
|
||||||
|
useEnsureActiveCookieJar();
|
||||||
|
|
||||||
|
// TODO: Remove in future version
|
||||||
|
useMigrateActiveCookieJarId();
|
||||||
|
|
||||||
const toggleCommandPalette = useToggleCommandPalette();
|
const toggleCommandPalette = useToggleCommandPalette();
|
||||||
useHotKey('command_palette.toggle', toggleCommandPalette);
|
useHotKey('command_palette.toggle', toggleCommandPalette);
|
||||||
@@ -96,21 +104,28 @@ export function GlobalHooks() {
|
|||||||
model.model,
|
model.model,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (shouldIgnoreModel(model)) return;
|
if (shouldIgnoreModel(model, windowLabel)) return;
|
||||||
|
|
||||||
queryClient.setQueryData<Model[]>(queryKey, (values = []) => {
|
queryClient.setQueryData(queryKey, (current: unknown) => {
|
||||||
const index = values.findIndex((v) => modelsEq(v, model)) ?? -1;
|
if (model.model === 'key_value') {
|
||||||
if (index >= 0) {
|
// Special-case for KeyValue
|
||||||
return [...values.slice(0, index), model, ...values.slice(index + 1)];
|
return extractKeyValue(model);
|
||||||
} else {
|
}
|
||||||
return pushToFront ? [model, ...(values ?? [])] : [...(values ?? []), model];
|
|
||||||
|
if (Array.isArray(current)) {
|
||||||
|
const index = current.findIndex((v) => modelsEq(v, model)) ?? -1;
|
||||||
|
if (index >= 0) {
|
||||||
|
return [...current.slice(0, index), model, ...current.slice(index + 1)];
|
||||||
|
} else {
|
||||||
|
return pushToFront ? [model, ...(current ?? [])] : [...(current ?? []), model];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
useListenToTauriEvent<ModelPayload>('deleted_model', ({ payload }) => {
|
useListenToTauriEvent<ModelPayload>('deleted_model', ({ payload }) => {
|
||||||
const { model } = payload;
|
const { model, windowLabel } = payload;
|
||||||
if (shouldIgnoreModel(model)) return;
|
if (shouldIgnoreModel(model, windowLabel)) return;
|
||||||
|
|
||||||
if (model.model === 'workspace') {
|
if (model.model === 'workspace') {
|
||||||
queryClient.setQueryData(workspacesQueryKey(), removeById(model));
|
queryClient.setQueryData(workspacesQueryKey(), removeById(model));
|
||||||
@@ -181,7 +196,11 @@ function removeById<T extends { id: string }>(model: T) {
|
|||||||
return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id);
|
return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldIgnoreModel = (payload: Model) => {
|
const shouldIgnoreModel = (payload: Model, windowLabel: string) => {
|
||||||
|
if (windowLabel === getCurrentWebviewWindow().label) {
|
||||||
|
// Never ignore same-window updates
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (payload.model === 'key_value') {
|
if (payload.model === 'key_value') {
|
||||||
return payload.namespace === 'no_sync';
|
return payload.namespace === 'no_sync';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export function MoveToWorkspaceDialog({ onDone, request, activeWorkspaceId }: Pr
|
|||||||
|
|
||||||
if (request.model === 'http_request') {
|
if (request.model === 'http_request') {
|
||||||
await updateHttpRequest.mutateAsync(args);
|
await updateHttpRequest.mutateAsync(args);
|
||||||
queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: httpRequestsQueryKey({ workspaceId: activeWorkspaceId }),
|
queryKey: httpRequestsQueryKey({ workspaceId: activeWorkspaceId }),
|
||||||
});
|
});
|
||||||
} else if (request.model === 'grpc_request') {
|
} else if (request.model === 'grpc_request') {
|
||||||
await updateGrpcRequest.mutateAsync(args);
|
await updateGrpcRequest.mutateAsync(args);
|
||||||
queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: grpcRequestsQueryKey({ workspaceId: activeWorkspaceId }),
|
queryKey: grpcRequestsQueryKey({ workspaceId: activeWorkspaceId }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useMemo, useRef } from 'react';
|
|||||||
import { useKeyPressEvent } from 'react-use';
|
import { useKeyPressEvent } from 'react-use';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||||
import { useHotKey } from '../hooks/useHotKey';
|
import { useHotKey } from '../hooks/useHotKey';
|
||||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||||
@@ -18,8 +18,8 @@ import { HttpMethodTag } from './core/HttpMethodTag';
|
|||||||
export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'className'>) {
|
export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'className'>) {
|
||||||
const dropdownRef = useRef<DropdownRef>(null);
|
const dropdownRef = useRef<DropdownRef>(null);
|
||||||
const activeRequest = useActiveRequest();
|
const activeRequest = useActiveRequest();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeEnvironment = useActiveEnvironment();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const allRecentRequestIds = useRecentRequests();
|
const allRecentRequestIds = useRecentRequests();
|
||||||
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
||||||
@@ -42,7 +42,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
|||||||
});
|
});
|
||||||
|
|
||||||
const items = useMemo<DropdownItem[]>(() => {
|
const items = useMemo<DropdownItem[]>(() => {
|
||||||
if (activeWorkspaceId === null) return [];
|
if (activeWorkspace === null) return [];
|
||||||
|
|
||||||
const recentRequestItems: DropdownItem[] = [];
|
const recentRequestItems: DropdownItem[] = [];
|
||||||
for (const id of recentRequestIds) {
|
for (const id of recentRequestIds) {
|
||||||
@@ -58,7 +58,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
|||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
environmentId: activeEnvironment?.id,
|
environmentId: activeEnvironment?.id,
|
||||||
workspaceId: activeWorkspaceId,
|
workspaceId: activeWorkspace.id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -76,7 +76,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
|||||||
}
|
}
|
||||||
|
|
||||||
return recentRequestItems.slice(0, 20);
|
return recentRequestItems.slice(0, 20);
|
||||||
}, [activeWorkspaceId, activeEnvironment?.id, recentRequestIds, requests, routes]);
|
}, [activeWorkspace, activeEnvironment?.id, recentRequestIds, requests, routes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown ref={dropdownRef} items={items}>
|
<Dropdown ref={dropdownRef} items={items}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { open } from '@tauri-apps/plugin-shell';
|
import { open } from '@tauri-apps/plugin-shell';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useAppInfo } from '../hooks/useAppInfo';
|
import { useAppInfo } from '../hooks/useAppInfo';
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||||
import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
|
import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
|
||||||
@@ -23,12 +23,12 @@ export function SettingsDropdown() {
|
|||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const checkForUpdates = useCheckForUpdates();
|
const checkForUpdates = useCheckForUpdates();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
|
|
||||||
const showSettings = async () => {
|
const showSettings = async () => {
|
||||||
if (!workspaceId) return;
|
if (!workspace) return;
|
||||||
await invokeCmd('cmd_new_nested_window', {
|
await invokeCmd('cmd_new_nested_window', {
|
||||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
url: routes.paths.workspaceSettings({ workspaceId: workspace.id }),
|
||||||
label: 'settings',
|
label: 'settings',
|
||||||
title: 'Yaak Settings',
|
title: 'Yaak Settings',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
|
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react';
|
import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import type { XYCoord } from 'react-dnd';
|
import type { XYCoord } from 'react-dnd';
|
||||||
import { useDrag, useDrop } from 'react-dnd';
|
import { useDrag, useDrop } from 'react-dnd';
|
||||||
import { useKey, useKeyPressEvent } from 'react-use';
|
import { useKey, useKeyPressEvent } from 'react-use';
|
||||||
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
|
|
||||||
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
|
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||||
@@ -32,7 +33,6 @@ import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
|||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
|
||||||
import { isResponseLoading } from '../lib/models';
|
import { isResponseLoading } from '../lib/models';
|
||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
@@ -61,7 +61,7 @@ export function Sidebar({ className }: Props) {
|
|||||||
const [hidden, setHidden] = useSidebarHidden();
|
const [hidden, setHidden] = useSidebarHidden();
|
||||||
const sidebarRef = useRef<HTMLLIElement>(null);
|
const sidebarRef = useRef<HTMLLIElement>(null);
|
||||||
const activeRequest = useActiveRequest();
|
const activeRequest = useActiveRequest();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const folders = useFolders();
|
const folders = useFolders();
|
||||||
const requests = useRequests();
|
const requests = useRequests();
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
@@ -207,14 +207,14 @@ export function Sidebar({ className }: Props) {
|
|||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
requestId: id,
|
requestId: id,
|
||||||
workspaceId: item.workspaceId,
|
workspaceId: item.workspaceId,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
setSelectedId(id);
|
setSelectedId(id);
|
||||||
setSelectedTree(tree);
|
setSelectedTree(tree);
|
||||||
if (!opts.noFocus) focusActiveRequest({ forced: { id, tree } });
|
if (!opts.noFocus) focusActiveRequest({ forced: { id, tree } });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[treeParentMap, collapsed, routes, activeEnvironmentId, focusActiveRequest],
|
[treeParentMap, collapsed, routes, activeEnvironment, focusActiveRequest],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClearSelected = useCallback(() => {
|
const handleClearSelected = useCallback(() => {
|
||||||
@@ -260,7 +260,7 @@ export function Sidebar({ className }: Props) {
|
|||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
requestId: selected.id,
|
requestId: selected.id,
|
||||||
workspaceId: activeWorkspace?.id,
|
workspaceId: activeWorkspace?.id,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useCallback, useMemo, useRef, useState } from 'react';
|
|||||||
import { useWindowSize } from 'react-use';
|
import { useWindowSize } from 'react-use';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
|
||||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||||
import { useImportData } from '../hooks/useImportData';
|
import { useImportData } from '../hooks/useImportData';
|
||||||
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
||||||
@@ -16,7 +15,6 @@ import { useWorkspaces } from '../hooks/useWorkspaces';
|
|||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { HotKeyList } from './core/HotKeyList';
|
import { HotKeyList } from './core/HotKeyList';
|
||||||
import { InlineCode } from './core/InlineCode';
|
|
||||||
import { FeedbackLink } from './core/Link';
|
import { FeedbackLink } from './core/Link';
|
||||||
import { HStack } from './core/Stacks';
|
import { HStack } from './core/Stacks';
|
||||||
import { CreateDropdown } from './CreateDropdown';
|
import { CreateDropdown } from './CreateDropdown';
|
||||||
@@ -38,7 +36,6 @@ export default function Workspace() {
|
|||||||
useSyncWorkspaceRequestTitle();
|
useSyncWorkspaceRequestTitle();
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
|
||||||
const { setWidth, width, resetWidth } = useSidebarWidth();
|
const { setWidth, width, resetWidth } = useSidebarWidth();
|
||||||
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
||||||
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
|
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
|
||||||
@@ -176,9 +173,8 @@ export default function Workspace() {
|
|||||||
{activeWorkspace == null ? (
|
{activeWorkspace == null ? (
|
||||||
<div className="m-auto">
|
<div className="m-auto">
|
||||||
<Banner color="warning" className="max-w-[30rem]">
|
<Banner color="warning" className="max-w-[30rem]">
|
||||||
The active workspace{' '}
|
The active workspace was not found. Select a workspace from the header menu or report
|
||||||
<InlineCode className="text-warning">{activeWorkspaceId}</InlineCode> was not found.
|
this bug to <FeedbackLink />
|
||||||
Select a workspace from the header menu or report this bug to <FeedbackLink />
|
|
||||||
</Banner>
|
</Banner>
|
||||||
</div>
|
</div>
|
||||||
) : activeRequest == null ? (
|
) : activeRequest == null ? (
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const s = useSettings();
|
const s = useSettings();
|
||||||
const e = useActiveEnvironment();
|
const [e] = useActiveEnvironment();
|
||||||
const w = useActiveWorkspace();
|
const w = useActiveWorkspace();
|
||||||
const environment = autocompleteVariables ? e : null;
|
const environment = autocompleteVariables ? e : null;
|
||||||
const workspace = autocompleteVariables ? w : null;
|
const workspace = autocompleteVariables ? w : null;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ class PlaceholderWidget extends WidgetType {
|
|||||||
readonly exists: boolean,
|
readonly exists: boolean,
|
||||||
readonly type: 'function' | 'variable' = 'variable',
|
readonly type: 'function' | 'variable' = 'variable',
|
||||||
) {
|
) {
|
||||||
console.log('PLACEHOLDER', { name, value });
|
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import classNames from 'classnames';
|
|||||||
import type { CSSProperties, MouseEvent as ReactMouseEvent, ReactNode } from 'react';
|
import type { CSSProperties, MouseEvent as ReactMouseEvent, ReactNode } from 'react';
|
||||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { useLocalStorage } from 'react-use';
|
import { useLocalStorage } from 'react-use';
|
||||||
import { useActiveWorkspaceId } from '../../hooks/useActiveWorkspaceId';
|
import { useActiveWorkspace } from '../../hooks/useActiveWorkspace';
|
||||||
import { clamp } from '../../lib/clamp';
|
import { clamp } from '../../lib/clamp';
|
||||||
import { ResizeHandle } from '../ResizeHandle';
|
import { ResizeHandle } from '../ResizeHandle';
|
||||||
|
|
||||||
@@ -42,10 +42,13 @@ export function SplitLayout({
|
|||||||
minWidthPx = 10,
|
minWidthPx = 10,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const [verticalBasedOnSize, setVerticalBasedOnSize] = useState<boolean>(false);
|
const [verticalBasedOnSize, setVerticalBasedOnSize] = useState<boolean>(false);
|
||||||
const [widthRaw, setWidth] = useLocalStorage<number>(`${name}_width::${useActiveWorkspaceId()}`);
|
const [widthRaw, setWidth] = useLocalStorage<number>(
|
||||||
|
`${name}_width::${activeWorkspace?.id ?? 'n/a'}`,
|
||||||
|
);
|
||||||
const [heightRaw, setHeight] = useLocalStorage<number>(
|
const [heightRaw, setHeight] = useLocalStorage<number>(
|
||||||
`${name}_height::${useActiveWorkspaceId()}`,
|
`${name}_height::${activeWorkspace?.id ?? 'n/a'}`,
|
||||||
);
|
);
|
||||||
const width = widthRaw ?? defaultRatio;
|
const width = widthRaw ?? defaultRatio;
|
||||||
let height = heightRaw ?? defaultRatio;
|
let height = heightRaw ?? defaultRatio;
|
||||||
|
|||||||
@@ -1,36 +1,87 @@
|
|||||||
import { useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useCookieJars } from './useCookieJars';
|
import { useCookieJars } from './useCookieJars';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
|
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
||||||
|
|
||||||
export function useActiveCookieJar() {
|
export function useActiveCookieJar() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const [activeCookieJarId, setActiveCookieJarId] = useActiveCookieJarId();
|
||||||
const cookieJars = useCookieJars();
|
const cookieJars = useCookieJars();
|
||||||
|
|
||||||
|
const activeCookieJar = useMemo(() => {
|
||||||
|
if (cookieJars.data == null) return undefined;
|
||||||
|
return cookieJars.data.find((cookieJar) => cookieJar.id === activeCookieJarId) ?? null;
|
||||||
|
}, [activeCookieJarId, cookieJars.data]);
|
||||||
|
|
||||||
|
return [activeCookieJar ?? null, setActiveCookieJarId] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useEnsureActiveCookieJar() {
|
||||||
|
const cookieJars = useCookieJars();
|
||||||
|
const [activeCookieJarId, setActiveCookieJarId] = useActiveCookieJarId();
|
||||||
|
useEffect(() => {
|
||||||
|
if (cookieJars.data == null) return;
|
||||||
|
|
||||||
|
if (cookieJars.data.find((j) => j.id === activeCookieJarId)) {
|
||||||
|
return; // There's an active jar
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstJar = cookieJars.data[0];
|
||||||
|
if (firstJar == null) {
|
||||||
|
console.log("Workspace doesn't have any cookie jars to activate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no active jar, so set it to the first one
|
||||||
|
console.log('Setting active cookie jar to', firstJar.id);
|
||||||
|
setActiveCookieJarId(firstJar.id);
|
||||||
|
}, [activeCookieJarId, cookieJars, cookieJars.data, setActiveCookieJarId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMigrateActiveCookieJarId() {
|
||||||
|
const workspace = useActiveWorkspace();
|
||||||
|
const [, setActiveCookieJarId] = useActiveCookieJarId();
|
||||||
const {
|
const {
|
||||||
set: setActiveCookieJarId,
|
set: setLegacyActiveCookieJarId,
|
||||||
value: activeCookieJarId,
|
value: legacyActiveCookieJarId,
|
||||||
isLoading: isLoadingActiveCookieJarId,
|
isLoading: isLoadingLegacyActiveCookieJarId,
|
||||||
} = useKeyValue<string | null>({
|
} = useKeyValue<string | null>({
|
||||||
namespace: 'global',
|
namespace: 'global',
|
||||||
key: ['activeCookieJar', workspaceId ?? 'n/a'],
|
key: ['activeCookieJar', workspace?.id ?? 'n/a'],
|
||||||
fallback: null,
|
fallback: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const activeCookieJar = useMemo(
|
useEffect(() => {
|
||||||
() => cookieJars.find((cookieJar) => cookieJar.id === activeCookieJarId),
|
if (legacyActiveCookieJarId == null || isLoadingLegacyActiveCookieJarId) return;
|
||||||
[activeCookieJarId, cookieJars],
|
|
||||||
|
console.log('Migrating active cookie jar ID to query param', legacyActiveCookieJarId);
|
||||||
|
setActiveCookieJarId(legacyActiveCookieJarId);
|
||||||
|
setLegacyActiveCookieJarId(null).catch(console.error);
|
||||||
|
}, [
|
||||||
|
workspace,
|
||||||
|
isLoadingLegacyActiveCookieJarId,
|
||||||
|
legacyActiveCookieJarId,
|
||||||
|
setActiveCookieJarId,
|
||||||
|
setLegacyActiveCookieJarId,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useActiveCookieJarId() {
|
||||||
|
// NOTE: This query param is accessed from Rust side, so do not change
|
||||||
|
const [params, setParams] = useSearchParams();
|
||||||
|
const id = params.get(QUERY_COOKIE_JAR_ID);
|
||||||
|
|
||||||
|
const setId = useCallback(
|
||||||
|
(id: string) => {
|
||||||
|
setParams((p) => {
|
||||||
|
const existing = Object.fromEntries(p);
|
||||||
|
return { ...existing, [QUERY_COOKIE_JAR_ID]: id };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setParams],
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Make this not be called so many times (move to GlobalHooks?)
|
return [id, setId] as const;
|
||||||
useEffect(() => {
|
|
||||||
if (!isLoadingActiveCookieJarId && activeCookieJar == null && cookieJars.length > 0) {
|
|
||||||
setActiveCookieJarId(cookieJars[0]?.id ?? null).catch(console.error);
|
|
||||||
}
|
|
||||||
}, [activeCookieJar, cookieJars, isLoadingActiveCookieJarId, setActiveCookieJarId]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
activeCookieJar: activeCookieJar ?? null,
|
|
||||||
setActiveCookieJarId: setActiveCookieJarId,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
import { useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import type { Environment } from '@yaakapp/api';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
|
||||||
import { useEnvironments } from './useEnvironments';
|
import { useEnvironments } from './useEnvironments';
|
||||||
|
|
||||||
export function useActiveEnvironment(): Environment | null {
|
export function useActiveEnvironment() {
|
||||||
const id = useActiveEnvironmentId();
|
const [id, setId] = useActiveEnvironmentId();
|
||||||
const environments = useEnvironments();
|
const environments = useEnvironments();
|
||||||
return useMemo(() => environments.find((w) => w.id === id) ?? null, [environments, id]);
|
const environment = useMemo(
|
||||||
|
() => environments.find((w) => w.id === id) ?? null,
|
||||||
|
[environments, id],
|
||||||
|
);
|
||||||
|
return [environment, setId] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
||||||
|
|
||||||
|
export function useActiveEnvironmentId() {
|
||||||
|
// NOTE: This query param is accessed from Rust side, so do not change
|
||||||
|
const [params, setParams] = useSearchParams();
|
||||||
|
const id = params.get(QUERY_ENVIRONMENT_ID);
|
||||||
|
|
||||||
|
const setId = useCallback(
|
||||||
|
(id: string | null) => {
|
||||||
|
setParams((p) => {
|
||||||
|
const existing = Object.fromEntries(p);
|
||||||
|
if (id == null) {
|
||||||
|
delete existing[QUERY_ENVIRONMENT_ID];
|
||||||
|
} else {
|
||||||
|
existing[QUERY_ENVIRONMENT_ID] = id;
|
||||||
|
}
|
||||||
|
return existing;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setParams],
|
||||||
|
);
|
||||||
|
|
||||||
|
return [id, setId] as const;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { useSearchParams } from 'react-router-dom';
|
|
||||||
|
|
||||||
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
|
||||||
|
|
||||||
export function useActiveEnvironmentId(): string | null {
|
|
||||||
const [params] = useSearchParams();
|
|
||||||
const environmentId = params.get(QUERY_ENVIRONMENT_ID);
|
|
||||||
if (environmentId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return environmentId;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { Workspace } from '@yaakapp/api';
|
import type { Workspace } from '@yaakapp/api';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useParams } from 'react-router-dom';
|
||||||
|
import type { RouteParamsWorkspace } from './useAppRoutes';
|
||||||
import { useWorkspaces } from './useWorkspaces';
|
import { useWorkspaces } from './useWorkspaces';
|
||||||
|
|
||||||
export function useActiveWorkspace(): Workspace | null {
|
export function useActiveWorkspace(): Workspace | null {
|
||||||
@@ -11,3 +12,8 @@ export function useActiveWorkspace(): Workspace | null {
|
|||||||
[workspaces, workspaceId],
|
[workspaces, workspaceId],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useActiveWorkspaceId(): string | null {
|
||||||
|
const { workspaceId } = useParams<RouteParamsWorkspace>();
|
||||||
|
return workspaceId ?? null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { InlineCode } from '../components/core/InlineCode';
|
|||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from '../components/ToastContext';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function useAtiveWorkspaceChangedToast() {
|
export function useActiveWorkspaceChangedToast() {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const [id, setId] = useState<string | null>(activeWorkspace?.id ?? null);
|
const [id, setId] = useState<string | null>(activeWorkspace?.id ?? null);
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { useParams } from 'react-router-dom';
|
|
||||||
import type { RouteParamsWorkspace } from './useAppRoutes';
|
|
||||||
|
|
||||||
export function useActiveWorkspaceId(): string | null {
|
|
||||||
const { workspaceId } = useParams<RouteParamsWorkspace>();
|
|
||||||
return workspaceId ?? null;
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
|
import type { Environment } from '@yaakapp/api';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import type { Environment } from '@yaakapp/api';
|
import { QUERY_COOKIE_JAR_ID } from './useActiveCookieJar';
|
||||||
import { QUERY_ENVIRONMENT_ID } from './useActiveEnvironmentId';
|
import { QUERY_ENVIRONMENT_ID } from './useActiveEnvironment';
|
||||||
import { useActiveRequestId } from './useActiveRequestId';
|
import { useActiveRequestId } from './useActiveRequestId';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export type RouteParamsWorkspace = {
|
export type RouteParamsWorkspace = {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
environmentId?: string;
|
environmentId?: string;
|
||||||
|
cookieJarId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RouteParamsRequest = RouteParamsWorkspace & {
|
export type RouteParamsRequest = RouteParamsWorkspace & {
|
||||||
@@ -22,34 +24,35 @@ export const routePaths = {
|
|||||||
return `/workspaces/${workspaceId}/settings`;
|
return `/workspaces/${workspaceId}/settings`;
|
||||||
},
|
},
|
||||||
workspace(
|
workspace(
|
||||||
{ workspaceId, environmentId } = {
|
{ workspaceId, environmentId, cookieJarId } = {
|
||||||
workspaceId: ':workspaceId',
|
workspaceId: ':workspaceId',
|
||||||
environmentId: ':environmentId',
|
environmentId: ':environmentId',
|
||||||
|
cookieJarId: ':cookieJarId',
|
||||||
} as RouteParamsWorkspace,
|
} as RouteParamsWorkspace,
|
||||||
) {
|
) {
|
||||||
let path = `/workspaces/${workspaceId}`;
|
const path = `/workspaces/${workspaceId}`;
|
||||||
if (environmentId != null) {
|
const params = new URLSearchParams();
|
||||||
path += `?${QUERY_ENVIRONMENT_ID}=${encodeURIComponent(environmentId)}`;
|
if (environmentId != null) params.set(QUERY_ENVIRONMENT_ID, environmentId);
|
||||||
}
|
if (cookieJarId != null) params.set(QUERY_COOKIE_JAR_ID, cookieJarId);
|
||||||
return path;
|
return `${path}?${params}`;
|
||||||
},
|
},
|
||||||
request(
|
request(
|
||||||
{ workspaceId, environmentId, requestId } = {
|
{ workspaceId, environmentId, requestId, cookieJarId } = {
|
||||||
workspaceId: ':workspaceId',
|
workspaceId: ':workspaceId',
|
||||||
environmentId: ':environmentId',
|
environmentId: ':environmentId',
|
||||||
requestId: ':requestId',
|
requestId: ':requestId',
|
||||||
} as RouteParamsRequest,
|
} as RouteParamsRequest,
|
||||||
) {
|
) {
|
||||||
let path = `/workspaces/${workspaceId}/requests/${requestId}`;
|
const path = `/workspaces/${workspaceId}/requests/${requestId}`;
|
||||||
if (environmentId != null) {
|
const params = new URLSearchParams();
|
||||||
path += `?${QUERY_ENVIRONMENT_ID}=${encodeURIComponent(environmentId)}`;
|
if (environmentId != null) params.set(QUERY_ENVIRONMENT_ID, environmentId);
|
||||||
}
|
if (cookieJarId != null) params.set(QUERY_COOKIE_JAR_ID, cookieJarId);
|
||||||
return path;
|
return `${path}?${params}`;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useAppRoutes() {
|
export function useAppRoutes() {
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const requestId = useActiveRequestId();
|
const requestId = useActiveRequestId();
|
||||||
const nav = useNavigate();
|
const nav = useNavigate();
|
||||||
|
|
||||||
@@ -66,22 +69,22 @@ export function useAppRoutes() {
|
|||||||
|
|
||||||
const setEnvironment = useCallback(
|
const setEnvironment = useCallback(
|
||||||
(environment: Environment | null) => {
|
(environment: Environment | null) => {
|
||||||
if (activeWorkspaceId == null) {
|
if (activeWorkspace == null) {
|
||||||
navigate('workspaces');
|
navigate('workspaces');
|
||||||
} else if (requestId == null) {
|
} else if (requestId == null) {
|
||||||
navigate('workspace', {
|
navigate('workspace', {
|
||||||
workspaceId: activeWorkspaceId,
|
workspaceId: activeWorkspace.id,
|
||||||
environmentId: environment == null ? undefined : environment.id,
|
environmentId: environment == null ? undefined : environment.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
navigate('request', {
|
navigate('request', {
|
||||||
workspaceId: activeWorkspaceId,
|
workspaceId: activeWorkspace.id,
|
||||||
environmentId: environment == null ? undefined : environment.id,
|
environmentId: environment == null ? undefined : environment.id,
|
||||||
requestId,
|
requestId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[navigate, activeWorkspaceId, requestId],
|
[navigate, activeWorkspace, requestId],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import type { CookieJar } from '../lib/models';
|
import type { CookieJar } from '../lib/models';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function cookieJarsQueryKey({ workspaceId }: { workspaceId: string }) {
|
export function cookieJarsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||||
return ['cookie_jars', { workspaceId }];
|
return ['cookie_jars', { workspaceId }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCookieJars() {
|
export function useCookieJars() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
return (
|
return useQuery({
|
||||||
useQuery({
|
enabled: workspace != null,
|
||||||
enabled: workspaceId != null,
|
queryKey: cookieJarsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||||
queryKey: cookieJarsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
queryFn: async () => {
|
||||||
queryFn: async () => {
|
if (workspace == null) return [];
|
||||||
if (workspaceId == null) return [];
|
return (await invokeCmd('cmd_list_cookie_jars', {
|
||||||
return (await invokeCmd('cmd_list_cookie_jars', { workspaceId })) as CookieJar[];
|
workspaceId: workspace.id,
|
||||||
},
|
})) as CookieJar[];
|
||||||
}).data ?? []
|
},
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useCopy } from './useCopy';
|
import { useCopy } from './useCopy';
|
||||||
|
|
||||||
export function useCopyAsCurl(requestId: string) {
|
export function useCopyAsCurl(requestId: string) {
|
||||||
const copy = useCopy();
|
const copy = useCopy();
|
||||||
const environmentId = useActiveEnvironmentId();
|
const [environment] = useActiveEnvironment();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ['copy_as_curl', requestId],
|
mutationKey: ['copy_as_curl', requestId],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const cmd: string = await invokeCmd('cmd_request_to_curl', { requestId, environmentId });
|
const cmd: string = await invokeCmd('cmd_request_to_curl', {
|
||||||
|
requestId,
|
||||||
|
environmentId: environment?.id,
|
||||||
|
});
|
||||||
copy(cmd);
|
copy(cmd);
|
||||||
return cmd;
|
return cmd;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import type { CookieJar } from '../lib/models';
|
import type { CookieJar } from '../lib/models';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { cookieJarsQueryKey } from './useCookieJars';
|
|
||||||
import { usePrompt } from './usePrompt';
|
import { usePrompt } from './usePrompt';
|
||||||
|
|
||||||
export function useCreateCookieJar() {
|
export function useCreateCookieJar() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
|
|
||||||
return useMutation<CookieJar>({
|
return useMutation<CookieJar>({
|
||||||
mutationKey: ['create_cookie_jar'],
|
mutationKey: ['create_cookie_jar'],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
if (workspaceId === null) {
|
if (workspace === null) {
|
||||||
throw new Error("Cannot create cookie jar when there's no active workspace");
|
throw new Error("Cannot create cookie jar when there's no active workspace");
|
||||||
}
|
}
|
||||||
const name = await prompt({
|
const name = await prompt({
|
||||||
@@ -25,14 +23,8 @@ export function useCreateCookieJar() {
|
|||||||
label: 'Name',
|
label: 'Name',
|
||||||
defaultValue: 'My Jar',
|
defaultValue: 'My Jar',
|
||||||
});
|
});
|
||||||
return invokeCmd('cmd_create_cookie_jar', { workspaceId, name });
|
return invokeCmd('cmd_create_cookie_jar', { workspaceId: workspace.id, name });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('cookie_jar', 'create'),
|
onSettled: () => trackEvent('cookie_jar', 'create'),
|
||||||
onSuccess: async (cookieJar) => {
|
|
||||||
queryClient.setQueryData<CookieJar[]>(
|
|
||||||
cookieJarsQueryKey({ workspaceId: cookieJar.workspaceId }),
|
|
||||||
(items) => [...(items ?? []), cookieJar],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { Environment } from '@yaakapp/api';
|
import type { Environment } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { environmentsQueryKey } from './useEnvironments';
|
|
||||||
import { usePrompt } from './usePrompt';
|
import { usePrompt } from './usePrompt';
|
||||||
|
|
||||||
export function useCreateEnvironment() {
|
export function useCreateEnvironment() {
|
||||||
const routes = useAppRoutes();
|
const [, setActiveEnvironmentId] = useActiveEnvironment();
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
return useMutation<Environment, unknown, void>({
|
return useMutation<Environment, unknown, void>({
|
||||||
mutationKey: ['create_environment'],
|
mutationKey: ['create_environment'],
|
||||||
@@ -25,16 +23,16 @@ export function useCreateEnvironment() {
|
|||||||
placeholder: 'My Environment',
|
placeholder: 'My Environment',
|
||||||
defaultValue: 'My Environment',
|
defaultValue: 'My Environment',
|
||||||
});
|
});
|
||||||
return invokeCmd('cmd_create_environment', { name, variables: [], workspaceId });
|
return invokeCmd('cmd_create_environment', {
|
||||||
|
name,
|
||||||
|
variables: [],
|
||||||
|
workspaceId: workspace?.id,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('environment', 'create'),
|
onSettled: () => trackEvent('environment', 'create'),
|
||||||
onSuccess: async (environment) => {
|
onSuccess: async (environment) => {
|
||||||
if (workspaceId == null) return;
|
if (workspace == null) return;
|
||||||
routes.setEnvironment(environment);
|
setActiveEnvironmentId(environment.id);
|
||||||
queryClient.setQueryData<Environment[]>(
|
|
||||||
environmentsQueryKey({ workspaceId }),
|
|
||||||
(environments) => [...(environments ?? []), environment],
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { Folder } from '@yaakapp/api';
|
import type { Folder } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveRequest } from './useActiveRequest';
|
import { useActiveRequest } from './useActiveRequest';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { foldersQueryKey } from './useFolders';
|
|
||||||
import { usePrompt } from './usePrompt';
|
import { usePrompt } from './usePrompt';
|
||||||
|
|
||||||
export function useCreateFolder() {
|
export function useCreateFolder() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const activeRequest = useActiveRequest();
|
const activeRequest = useActiveRequest();
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
|
|
||||||
return useMutation<Folder, unknown, Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>>({
|
return useMutation<Folder, unknown, Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>>({
|
||||||
mutationKey: ['create_folder'],
|
mutationKey: ['create_folder'],
|
||||||
mutationFn: async (patch) => {
|
mutationFn: async (patch) => {
|
||||||
if (workspaceId === null) {
|
if (workspace === null) {
|
||||||
throw new Error("Cannot create folder when there's no active workspace");
|
throw new Error("Cannot create folder when there's no active workspace");
|
||||||
}
|
}
|
||||||
patch.name =
|
patch.name =
|
||||||
@@ -32,13 +30,8 @@ export function useCreateFolder() {
|
|||||||
}));
|
}));
|
||||||
patch.sortPriority = patch.sortPriority || -Date.now();
|
patch.sortPriority = patch.sortPriority || -Date.now();
|
||||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||||
return invokeCmd('cmd_create_folder', { workspaceId, ...patch });
|
return invokeCmd('cmd_create_folder', { workspaceId: workspace.id, ...patch });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('folder', 'create'),
|
onSettled: () => trackEvent('folder', 'create'),
|
||||||
onSuccess: async (request) => {
|
|
||||||
await queryClient.invalidateQueries({
|
|
||||||
queryKey: foldersQueryKey({ workspaceId: request.workspaceId }),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { GrpcRequest } from '@yaakapp/api';
|
import type { GrpcRequest } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useActiveRequest } from './useActiveRequest';
|
import { useActiveRequest } from './useActiveRequest';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
|
|
||||||
export function useCreateGrpcRequest() {
|
export function useCreateGrpcRequest() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const activeRequest = useActiveRequest();
|
const activeRequest = useActiveRequest();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
|
|
||||||
@@ -20,12 +20,12 @@ export function useCreateGrpcRequest() {
|
|||||||
>({
|
>({
|
||||||
mutationKey: ['create_grpc_request'],
|
mutationKey: ['create_grpc_request'],
|
||||||
mutationFn: (patch) => {
|
mutationFn: (patch) => {
|
||||||
if (workspaceId === null) {
|
if (workspace === null) {
|
||||||
throw new Error("Cannot create grpc request when there's no active workspace");
|
throw new Error("Cannot create grpc request when there's no active workspace");
|
||||||
}
|
}
|
||||||
if (patch.sortPriority === undefined) {
|
if (patch.sortPriority === undefined) {
|
||||||
if (activeRequest != null) {
|
if (activeRequest != null) {
|
||||||
// Place above currently-active request
|
// Place above currently active request
|
||||||
patch.sortPriority = activeRequest.sortPriority + 0.0001;
|
patch.sortPriority = activeRequest.sortPriority + 0.0001;
|
||||||
} else {
|
} else {
|
||||||
// Place at the very top
|
// Place at the very top
|
||||||
@@ -33,14 +33,18 @@ export function useCreateGrpcRequest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||||
return invokeCmd('cmd_create_grpc_request', { workspaceId, name: '', ...patch });
|
return invokeCmd('cmd_create_grpc_request', {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
name: '',
|
||||||
|
...patch,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('grpc_request', 'create'),
|
onSettled: () => trackEvent('grpc_request', 'create'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
workspaceId: request.workspaceId,
|
workspaceId: request.workspaceId,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { HttpRequest } from '@yaakapp/api';
|
import type { HttpRequest } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useActiveRequest } from './useActiveRequest';
|
import { useActiveRequest } from './useActiveRequest';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
|
|
||||||
export function useCreateHttpRequest() {
|
export function useCreateHttpRequest() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const activeRequest = useActiveRequest();
|
const activeRequest = useActiveRequest();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
|
|
||||||
return useMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
return useMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
||||||
mutationKey: ['create_http_request'],
|
mutationKey: ['create_http_request'],
|
||||||
mutationFn: (patch = {}) => {
|
mutationFn: (patch = {}) => {
|
||||||
if (workspaceId === null) {
|
if (workspace === null) {
|
||||||
throw new Error("Cannot create request when there's no active workspace");
|
throw new Error("Cannot create request when there's no active workspace");
|
||||||
}
|
}
|
||||||
if (patch.sortPriority === undefined) {
|
if (patch.sortPriority === undefined) {
|
||||||
@@ -29,14 +29,16 @@ export function useCreateHttpRequest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||||
return invokeCmd('cmd_create_http_request', { request: { workspaceId, ...patch } });
|
return invokeCmd('cmd_create_http_request', {
|
||||||
|
request: { workspaceId: workspace.id, ...patch },
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_request', 'create'),
|
onSettled: () => trackEvent('http_request', 'create'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
workspaceId: request.workspaceId,
|
workspaceId: request.workspaceId,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { GrpcRequest } from '@yaakapp/api';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import type { GrpcRequest } from '@yaakapp/api';
|
|
||||||
import { getGrpcRequest } from '../lib/store';
|
import { getGrpcRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
|
||||||
|
|
||||||
export function useDeleteAnyGrpcRequest() {
|
export function useDeleteAnyGrpcRequest() {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
return useMutation<GrpcRequest | null, string, string>({
|
return useMutation<GrpcRequest | null, string, string>({
|
||||||
@@ -32,13 +30,5 @@ export function useDeleteAnyGrpcRequest() {
|
|||||||
return invokeCmd('cmd_delete_grpc_request', { requestId: id });
|
return invokeCmd('cmd_delete_grpc_request', { requestId: id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('grpc_request', 'delete'),
|
onSettled: () => trackEvent('grpc_request', 'delete'),
|
||||||
onSuccess: async (request) => {
|
|
||||||
if (request === null) return;
|
|
||||||
|
|
||||||
const { workspaceId, id: requestId } = request;
|
|
||||||
queryClient.setQueryData<GrpcRequest[]>(grpcRequestsQueryKey({ workspaceId }), (requests) =>
|
|
||||||
(requests ?? []).filter((r) => r.id !== requestId),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { HttpRequest } from '@yaakapp/api';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import type { HttpRequest } from '@yaakapp/api';
|
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
|
||||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
|
||||||
|
|
||||||
export function useDeleteAnyHttpRequest() {
|
export function useDeleteAnyHttpRequest() {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
return useMutation<HttpRequest | null, string, string>({
|
return useMutation<HttpRequest | null, string, string>({
|
||||||
@@ -33,15 +30,5 @@ export function useDeleteAnyHttpRequest() {
|
|||||||
return invokeCmd('cmd_delete_http_request', { requestId: id });
|
return invokeCmd('cmd_delete_http_request', { requestId: id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_request', 'delete'),
|
onSettled: () => trackEvent('http_request', 'delete'),
|
||||||
onSuccess: async (request) => {
|
|
||||||
// Was it cancelled?
|
|
||||||
if (request === null) return;
|
|
||||||
|
|
||||||
const { workspaceId, id: requestId } = request;
|
|
||||||
queryClient.setQueryData(httpResponsesQueryKey({ requestId }), []); // Responses were deleted
|
|
||||||
queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey({ workspaceId }), (requests) =>
|
|
||||||
(requests ?? []).filter((r) => r.id !== requestId),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import type { CookieJar } from '../lib/models';
|
import type { CookieJar } from '../lib/models';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { cookieJarsQueryKey } from './useCookieJars';
|
|
||||||
|
|
||||||
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
return useMutation<CookieJar | null, string>({
|
return useMutation<CookieJar | null, string>({
|
||||||
@@ -27,13 +25,5 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
|||||||
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('cookie_jar', 'delete'),
|
onSettled: () => trackEvent('cookie_jar', 'delete'),
|
||||||
onSuccess: async (cookieJar) => {
|
|
||||||
if (cookieJar === null) return;
|
|
||||||
|
|
||||||
const { id: cookieJarId, workspaceId } = cookieJar;
|
|
||||||
queryClient.setQueryData<CookieJar[]>(cookieJarsQueryKey({ workspaceId }), (cookieJars) =>
|
|
||||||
cookieJars?.filter((e) => e.id !== cookieJarId),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { Environment } from '@yaakapp/api';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import type { Environment, Workspace } from '@yaakapp/api';
|
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { environmentsQueryKey } from './useEnvironments';
|
|
||||||
|
|
||||||
export function useDeleteEnvironment(environment: Environment | null) {
|
export function useDeleteEnvironment(environment: Environment | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
return useMutation<Environment | null, string>({
|
return useMutation<Environment | null, string>({
|
||||||
@@ -27,13 +25,5 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
|||||||
return invokeCmd('cmd_delete_environment', { environmentId: environment?.id });
|
return invokeCmd('cmd_delete_environment', { environmentId: environment?.id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('environment', 'delete'),
|
onSettled: () => trackEvent('environment', 'delete'),
|
||||||
onSuccess: async (environment) => {
|
|
||||||
if (environment === null) return;
|
|
||||||
|
|
||||||
const { id: environmentId, workspaceId } = environment;
|
|
||||||
queryClient.setQueryData<Workspace[]>(environmentsQueryKey({ workspaceId }), (environments) =>
|
|
||||||
environments?.filter((e) => e.id !== environmentId),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { Folder } from '@yaakapp/api';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import type { Folder } from '@yaakapp/api';
|
|
||||||
import { getFolder } from '../lib/store';
|
import { getFolder } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { foldersQueryKey } from './useFolders';
|
|
||||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
|
||||||
|
|
||||||
export function useDeleteFolder(id: string | null) {
|
export function useDeleteFolder(id: string | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
return useMutation<Folder | null, string>({
|
return useMutation<Folder | null, string>({
|
||||||
@@ -30,15 +27,5 @@ export function useDeleteFolder(id: string | null) {
|
|||||||
return invokeCmd('cmd_delete_folder', { folderId: id });
|
return invokeCmd('cmd_delete_folder', { folderId: id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('folder', 'delete'),
|
onSettled: () => trackEvent('folder', 'delete'),
|
||||||
onSuccess: async (folder) => {
|
|
||||||
// Was it cancelled?
|
|
||||||
if (folder === null) return;
|
|
||||||
|
|
||||||
const { workspaceId } = folder;
|
|
||||||
|
|
||||||
// Nesting makes it hard to clean things up, so just clear everything that could have been deleted
|
|
||||||
await queryClient.invalidateQueries({ queryKey: httpRequestsQueryKey({ workspaceId }) });
|
|
||||||
await queryClient.invalidateQueries({ queryKey: foldersQueryKey({ workspaceId }) });
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { GrpcConnection } from '@yaakapp/api';
|
import type { GrpcConnection } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
|
||||||
|
|
||||||
export function useDeleteGrpcConnection(id: string | null) {
|
export function useDeleteGrpcConnection(id: string | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation<GrpcConnection>({
|
return useMutation<GrpcConnection>({
|
||||||
mutationKey: ['delete_grpc_connection', id],
|
mutationKey: ['delete_grpc_connection', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
return await invokeCmd('cmd_delete_grpc_connection', { id: id });
|
return await invokeCmd('cmd_delete_grpc_connection', { id: id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('grpc_connection', 'delete'),
|
onSettled: () => trackEvent('grpc_connection', 'delete'),
|
||||||
onSuccess: ({ requestId, id: connectionId }) => {
|
|
||||||
queryClient.setQueryData<GrpcConnection[]>(
|
|
||||||
grpcConnectionsQueryKey({ requestId }),
|
|
||||||
(connections) => (connections ?? []).filter((c) => c.id !== connectionId),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
|
||||||
|
|
||||||
export function useDeleteGrpcConnections(requestId?: string) {
|
export function useDeleteGrpcConnections(requestId?: string) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ['delete_grpc_connections', requestId],
|
mutationKey: ['delete_grpc_connections', requestId],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -12,9 +10,5 @@ export function useDeleteGrpcConnections(requestId?: string) {
|
|||||||
await invokeCmd('cmd_delete_all_grpc_connections', { requestId });
|
await invokeCmd('cmd_delete_all_grpc_connections', { requestId });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('grpc_connection', 'delete_many'),
|
onSettled: () => trackEvent('grpc_connection', 'delete_many'),
|
||||||
onSuccess: async () => {
|
|
||||||
if (requestId === undefined) return;
|
|
||||||
queryClient.setQueryData(grpcConnectionsQueryKey({ requestId }), []);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { HttpResponse } from '@yaakapp/api';
|
import type { HttpResponse } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
|
||||||
|
|
||||||
export function useDeleteHttpResponse(id: string | null) {
|
export function useDeleteHttpResponse(id: string | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation<HttpResponse>({
|
return useMutation<HttpResponse>({
|
||||||
mutationKey: ['delete_http_response', id],
|
mutationKey: ['delete_http_response', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
return await invokeCmd('cmd_delete_http_response', { id: id });
|
return await invokeCmd('cmd_delete_http_response', { id: id });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_response', 'delete'),
|
onSettled: () => trackEvent('http_response', 'delete'),
|
||||||
onSuccess: ({ requestId, id: responseId }) => {
|
|
||||||
queryClient.setQueryData<HttpResponse[]>(httpResponsesQueryKey({ requestId }), (responses) =>
|
|
||||||
(responses ?? []).filter((response) => response.id !== responseId),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
|
||||||
|
|
||||||
export function useDeleteHttpResponses(requestId?: string) {
|
export function useDeleteHttpResponses(requestId?: string) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ['delete_http_responses', requestId],
|
mutationKey: ['delete_http_responses', requestId],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -12,9 +10,5 @@ export function useDeleteHttpResponses(requestId?: string) {
|
|||||||
await invokeCmd('cmd_delete_all_http_responses', { requestId });
|
await invokeCmd('cmd_delete_all_http_responses', { requestId });
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_response', 'delete_many'),
|
onSettled: () => trackEvent('http_response', 'delete_many'),
|
||||||
onSuccess: async () => {
|
|
||||||
if (requestId === undefined) return;
|
|
||||||
queryClient.setQueryData(httpResponsesQueryKey({ requestId }), []);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { Workspace } from '@yaakapp/api';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import type { Workspace } from '@yaakapp/api';
|
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
|
||||||
import { workspacesQueryKey } from './useWorkspaces';
|
|
||||||
|
|
||||||
export function useDeleteWorkspace(workspace: Workspace | null) {
|
export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||||
const queryClient = useQueryClient();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
@@ -36,16 +33,9 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
|||||||
if (workspace === null) return;
|
if (workspace === null) return;
|
||||||
|
|
||||||
const { id: workspaceId } = workspace;
|
const { id: workspaceId } = workspace;
|
||||||
queryClient.setQueryData<Workspace[]>(workspacesQueryKey({}), (workspaces) =>
|
if (workspaceId === activeWorkspace?.id) {
|
||||||
workspaces?.filter((workspace) => workspace.id !== workspaceId),
|
|
||||||
);
|
|
||||||
if (workspaceId === activeWorkspaceId) {
|
|
||||||
routes.navigate('workspaces');
|
routes.navigate('workspaces');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also clean up other things that may have been deleted
|
|
||||||
queryClient.setQueryData(httpRequestsQueryKey({ workspaceId }), []);
|
|
||||||
await queryClient.invalidateQueries({ queryKey: httpRequestsQueryKey({ workspaceId }) });
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { GrpcRequest } from '@yaakapp/api';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { setKeyValue } from '../lib/keyValueStore';
|
import { setKeyValue } from '../lib/keyValueStore';
|
||||||
import type { GrpcRequest } from '@yaakapp/api';
|
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
import { protoFilesArgs, useGrpcProtoFiles } from './useGrpcProtoFiles';
|
import { protoFilesArgs, useGrpcProtoFiles } from './useGrpcProtoFiles';
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@ export function useDuplicateGrpcRequest({
|
|||||||
id: string | null;
|
id: string | null;
|
||||||
navigateAfter: boolean;
|
navigateAfter: boolean;
|
||||||
}) {
|
}) {
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const protoFiles = useGrpcProtoFiles(id);
|
const protoFiles = useGrpcProtoFiles(id);
|
||||||
return useMutation<GrpcRequest, string>({
|
return useMutation<GrpcRequest, string>({
|
||||||
@@ -30,11 +30,11 @@ export function useDuplicateGrpcRequest({
|
|||||||
// Also copy proto files to new request
|
// Also copy proto files to new request
|
||||||
await setKeyValue({ ...protoFilesArgs(request.id), value: protoFiles.value ?? [] });
|
await setKeyValue({ ...protoFilesArgs(request.id), value: protoFiles.value ?? [] });
|
||||||
|
|
||||||
if (navigateAfter && activeWorkspaceId !== null) {
|
if (navigateAfter && activeWorkspace !== null) {
|
||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
workspaceId: activeWorkspaceId,
|
workspaceId: activeWorkspace.id,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { HttpRequest } from '@yaakapp/api';
|
import type { HttpRequest } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
|
|
||||||
export function useDuplicateHttpRequest({
|
export function useDuplicateHttpRequest({
|
||||||
@@ -13,8 +13,8 @@ export function useDuplicateHttpRequest({
|
|||||||
id: string | null;
|
id: string | null;
|
||||||
navigateAfter: boolean;
|
navigateAfter: boolean;
|
||||||
}) {
|
}) {
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
return useMutation<HttpRequest, string>({
|
return useMutation<HttpRequest, string>({
|
||||||
mutationKey: ['duplicate_http_request', id],
|
mutationKey: ['duplicate_http_request', id],
|
||||||
@@ -24,11 +24,11 @@ export function useDuplicateHttpRequest({
|
|||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_request', 'duplicate'),
|
onSettled: () => trackEvent('http_request', 'duplicate'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
if (navigateAfter && activeWorkspaceId !== null) {
|
if (navigateAfter && activeWorkspace !== null) {
|
||||||
routes.navigate('request', {
|
routes.navigate('request', {
|
||||||
workspaceId: activeWorkspaceId,
|
workspaceId: activeWorkspace.id,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
environmentId: activeEnvironmentId ?? undefined,
|
environmentId: activeEnvironment?.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import type { Environment } from '@yaakapp/api';
|
import type { Environment } from '@yaakapp/api';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function environmentsQueryKey({ workspaceId }: { workspaceId: string }) {
|
export function environmentsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||||
return ['environments', { workspaceId }];
|
return ['environments', { workspaceId }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useEnvironments() {
|
export function useEnvironments() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
return (
|
return (
|
||||||
useQuery({
|
useQuery({
|
||||||
enabled: workspaceId != null,
|
enabled: workspace != null,
|
||||||
queryKey: environmentsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
queryKey: environmentsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (workspaceId == null) return [];
|
if (workspace == null) return [];
|
||||||
return (await invokeCmd('cmd_list_environments', { workspaceId })) as Environment[];
|
return (await invokeCmd('cmd_list_environments', {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
})) as Environment[];
|
||||||
},
|
},
|
||||||
}).data ?? []
|
}).data ?? []
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
export function useFloatingSidebarHidden() {
|
export function useFloatingSidebarHidden() {
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const { set, value } = useKeyValue<boolean>({
|
const { set, value } = useKeyValue<boolean>({
|
||||||
namespace: 'no_sync',
|
namespace: 'no_sync',
|
||||||
key: ['floating_sidebar_hidden', activeWorkspaceId ?? 'n/a'],
|
key: ['floating_sidebar_hidden', activeWorkspace?.id ?? 'n/a'],
|
||||||
fallback: false,
|
fallback: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import type { Folder } from '@yaakapp/api';
|
import type { Folder } from '@yaakapp/api';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function foldersQueryKey({ workspaceId }: { workspaceId: string }) {
|
export function foldersQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||||
return ['folders', { workspaceId }];
|
return ['folders', { workspaceId }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useFolders() {
|
export function useFolders() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
return (
|
return (
|
||||||
useQuery({
|
useQuery({
|
||||||
enabled: workspaceId != null,
|
enabled: workspace != null,
|
||||||
queryKey: foldersQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
queryKey: foldersQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (workspaceId == null) return [];
|
if (workspace == null) return [];
|
||||||
return (await invokeCmd('cmd_list_folders', { workspaceId })) as Folder[];
|
return (await invokeCmd('cmd_list_folders', { workspaceId: workspace.id })) as Folder[];
|
||||||
},
|
},
|
||||||
}).data ?? []
|
}).data ?? []
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { emit } from '@tauri-apps/api/event';
|
import { emit } from '@tauri-apps/api/event';
|
||||||
|
import type { GrpcConnection, GrpcRequest } from '@yaakapp/api';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||||
import type { GrpcConnection, GrpcRequest } from '@yaakapp/api';
|
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useDebouncedValue } from './useDebouncedValue';
|
import { useDebouncedValue } from './useDebouncedValue';
|
||||||
|
|
||||||
export interface ReflectResponseService {
|
export interface ReflectResponseService {
|
||||||
@@ -18,12 +18,12 @@ export function useGrpc(
|
|||||||
protoFiles: string[],
|
protoFiles: string[],
|
||||||
) {
|
) {
|
||||||
const requestId = req?.id ?? 'n/a';
|
const requestId = req?.id ?? 'n/a';
|
||||||
const environmentId = useActiveEnvironmentId();
|
const [environment] = useActiveEnvironment();
|
||||||
|
|
||||||
const go = useMutation<void, string>({
|
const go = useMutation<void, string>({
|
||||||
mutationKey: ['grpc_go', conn?.id],
|
mutationKey: ['grpc_go', conn?.id],
|
||||||
mutationFn: async () =>
|
mutationFn: async () =>
|
||||||
await invokeCmd('cmd_grpc_go', { requestId, environmentId, protoFiles }),
|
await invokeCmd('cmd_grpc_go', { requestId, environmentId: environment?.id, protoFiles }),
|
||||||
onSettled: () => trackEvent('grpc_request', 'send'),
|
onSettled: () => trackEvent('grpc_request', 'send'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import type { GrpcRequest } from '@yaakapp/api';
|
import type { GrpcRequest } from '@yaakapp/api';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function grpcRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
export function grpcRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||||
return ['grpc_requests', { workspaceId }];
|
return ['grpc_requests', { workspaceId }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useGrpcRequests() {
|
export function useGrpcRequests() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
return (
|
return (
|
||||||
useQuery({
|
useQuery({
|
||||||
enabled: workspaceId != null,
|
enabled: workspace != null,
|
||||||
queryKey: grpcRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
queryKey: grpcRequestsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (workspaceId == null) return [];
|
if (workspace == null) return [];
|
||||||
return (await invokeCmd('cmd_list_grpc_requests', { workspaceId })) as GrpcRequest[];
|
return (await invokeCmd('cmd_list_grpc_requests', {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
})) as GrpcRequest[];
|
||||||
},
|
},
|
||||||
}).data ?? []
|
}).data ?? []
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import type { HttpRequest } from '@yaakapp/api';
|
import type { HttpRequest } from '@yaakapp/api';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function httpRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
export function httpRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||||
return ['http_requests', { workspaceId }];
|
return ['http_requests', { workspaceId }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useHttpRequests() {
|
export function useHttpRequests() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
return (
|
return (
|
||||||
useQuery({
|
useQuery({
|
||||||
enabled: workspaceId != null,
|
enabled: workspace != null,
|
||||||
queryKey: httpRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
queryKey: httpRequestsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (workspaceId == null) return [];
|
if (workspace == null) return [];
|
||||||
return (await invokeCmd('cmd_list_http_requests', { workspaceId })) as HttpRequest[];
|
return (await invokeCmd('cmd_list_http_requests', {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
})) as HttpRequest[];
|
||||||
},
|
},
|
||||||
}).data ?? []
|
}).data ?? []
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from '../components/ToastContext';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||||
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
||||||
|
|
||||||
export function useImportCurl() {
|
export function useImportCurl() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspace = useActiveWorkspace();
|
||||||
const updateRequest = useUpdateAnyHttpRequest();
|
const updateRequest = useUpdateAnyHttpRequest();
|
||||||
const createRequest = useCreateHttpRequest();
|
const createRequest = useCreateHttpRequest();
|
||||||
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
||||||
@@ -24,7 +24,7 @@ export function useImportCurl() {
|
|||||||
}) => {
|
}) => {
|
||||||
const request: Record<string, unknown> = await invokeCmd('cmd_curl_to_request', {
|
const request: Record<string, unknown> = await invokeCmd('cmd_curl_to_request', {
|
||||||
command,
|
command,
|
||||||
workspaceId,
|
workspaceId: workspace?.id,
|
||||||
});
|
});
|
||||||
delete request.id;
|
delete request.id;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import type { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
||||||
import { Button } from '../components/core/Button';
|
import { Button } from '../components/core/Button';
|
||||||
import { FormattedError } from '../components/core/FormattedError';
|
import { FormattedError } from '../components/core/FormattedError';
|
||||||
import { VStack } from '../components/core/Stacks';
|
import { VStack } from '../components/core/Stacks';
|
||||||
import { useDialog } from '../components/DialogContext';
|
import { useDialog } from '../components/DialogContext';
|
||||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||||
import type { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
|
||||||
import { count } from '../lib/pluralize';
|
import { count } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
import { useAlert } from './useAlert';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ export function useImportData() {
|
|||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
|
|
||||||
const importData = async (filePath: string): Promise<boolean> => {
|
const importData = async (filePath: string): Promise<boolean> => {
|
||||||
const imported: {
|
const imported: {
|
||||||
@@ -26,7 +26,7 @@ export function useImportData() {
|
|||||||
grpcRequests: GrpcRequest[];
|
grpcRequests: GrpcRequest[];
|
||||||
} = await invokeCmd('cmd_import_data', {
|
} = await invokeCmd('cmd_import_data', {
|
||||||
filePath,
|
filePath,
|
||||||
workspaceId: activeWorkspaceId,
|
workspaceId: activeWorkspace?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const importedWorkspace = imported.workspaces[0];
|
const importedWorkspace = imported.workspaces[0];
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
|
import type { HttpRequest } from '@yaakapp/api';
|
||||||
import type { IntrospectionQuery } from 'graphql';
|
import type { IntrospectionQuery } from 'graphql';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
||||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||||
import type { HttpRequest } from '@yaakapp/api';
|
|
||||||
import { getResponseBodyText } from '../lib/responseBody';
|
import { getResponseBodyText } from '../lib/responseBody';
|
||||||
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
|
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useDebouncedValue } from './useDebouncedValue';
|
import { useDebouncedValue } from './useDebouncedValue';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
|||||||
// Debounce the request because it can change rapidly and we don't
|
// Debounce the request because it can change rapidly and we don't
|
||||||
// want to send so too many requests.
|
// want to send so too many requests.
|
||||||
const request = useDebouncedValue(baseRequest);
|
const request = useDebouncedValue(baseRequest);
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const [refetchKey, setRefetchKey] = useState<number>(0);
|
const [refetchKey, setRefetchKey] = useState<number>(0);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
@@ -40,7 +40,10 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
|||||||
bodyType: 'application/json',
|
bodyType: 'application/json',
|
||||||
body: { text: introspectionRequestBody },
|
body: { text: introspectionRequestBody },
|
||||||
};
|
};
|
||||||
const response = await minPromiseMillis(sendEphemeralRequest(args, activeEnvironmentId), 700);
|
const response = await minPromiseMillis(
|
||||||
|
sendEphemeralRequest(args, activeEnvironment?.id ?? null),
|
||||||
|
700,
|
||||||
|
);
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
throw new Error(response.error);
|
throw new Error(response.error);
|
||||||
@@ -72,7 +75,7 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
|||||||
runIntrospection(); // Run immediately
|
runIntrospection(); // Run immediately
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [request.id, request.url, request.method, refetchKey, activeEnvironmentId]);
|
}, [request.id, request.url, request.method, refetchKey, activeEnvironment?.id]);
|
||||||
|
|
||||||
const refetch = useCallback(() => {
|
const refetch = useCallback(() => {
|
||||||
setRefetchKey((k) => k + 1);
|
setRefetchKey((k) => k + 1);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { buildKeyValueKey, getKeyValue, setKeyValue } from '../lib/keyValueStore';
|
import { buildKeyValueKey, getKeyValue, setKeyValue } from '../lib/keyValueStore';
|
||||||
|
|
||||||
@@ -24,7 +24,6 @@ export function useKeyValue<T extends Object | null>({
|
|||||||
key: string | string[];
|
key: string | string[];
|
||||||
fallback: T;
|
fallback: T;
|
||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const query = useQuery<T>({
|
const query = useQuery<T>({
|
||||||
queryKey: keyValueQueryKey({ namespace, key }),
|
queryKey: keyValueQueryKey({ namespace, key }),
|
||||||
queryFn: async () => getKeyValue({ namespace, key, fallback }),
|
queryFn: async () => getKeyValue({ namespace, key, fallback }),
|
||||||
@@ -34,8 +33,6 @@ export function useKeyValue<T extends Object | null>({
|
|||||||
const mutate = useMutation<void, unknown, T>({
|
const mutate = useMutation<void, unknown, T>({
|
||||||
mutationKey: ['set_key_value', namespace, key],
|
mutationKey: ['set_key_value', namespace, key],
|
||||||
mutationFn: (value) => setKeyValue<T>({ namespace, key, value }),
|
mutationFn: (value) => setKeyValue<T>({ namespace, key, value }),
|
||||||
// k/v should be as fast as possible, so optimistically update the cache
|
|
||||||
onMutate: (value) => queryClient.setQueryData<T>(keyValueQueryKey({ namespace, key }), value),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const set = useCallback(
|
const set = useCallback(
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ import { useMutation } from '@tanstack/react-query';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useDialog } from '../components/DialogContext';
|
import { useDialog } from '../components/DialogContext';
|
||||||
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useRequests } from './useRequests';
|
import { useRequests } from './useRequests';
|
||||||
|
|
||||||
export function useMoveToWorkspace(id: string) {
|
export function useMoveToWorkspace(id: string) {
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const requests = useRequests();
|
const requests = useRequests();
|
||||||
const request = requests.find((r) => r.id === id);
|
const request = requests.find((r) => r.id === id);
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
|
|
||||||
return useMutation<void, unknown>({
|
return useMutation<void, unknown>({
|
||||||
mutationKey: ['move_workspace', id],
|
mutationKey: ['move_workspace', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
if (request == null || activeWorkspaceId == null) return;
|
if (request == null || activeWorkspace == null) return;
|
||||||
|
|
||||||
dialog.show({
|
dialog.show({
|
||||||
id: 'change-workspace',
|
id: 'change-workspace',
|
||||||
@@ -24,7 +24,7 @@ export function useMoveToWorkspace(id: string) {
|
|||||||
<MoveToWorkspaceDialog
|
<MoveToWorkspaceDialog
|
||||||
onDone={hide}
|
onDone={hide}
|
||||||
request={request}
|
request={request}
|
||||||
activeWorkspaceId={activeWorkspaceId}
|
activeWorkspaceId={activeWorkspace.id}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useAppRoutes } from './useAppRoutes';
|
import { useAppRoutes } from './useAppRoutes';
|
||||||
|
import { getRecentCookieJars } from './useRecentCookieJars';
|
||||||
import { getRecentEnvironments } from './useRecentEnvironments';
|
import { getRecentEnvironments } from './useRecentEnvironments';
|
||||||
import { getRecentRequests } from './useRecentRequests';
|
import { getRecentRequests } from './useRecentRequests';
|
||||||
|
|
||||||
@@ -16,29 +17,21 @@ export function useOpenWorkspace() {
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
inNewWindow: boolean;
|
inNewWindow: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
|
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
||||||
|
const requestId = (await getRecentRequests(workspaceId))[0];
|
||||||
|
const cookieJarId = (await getRecentCookieJars(workspaceId))[0];
|
||||||
|
const baseArgs = { workspaceId, environmentId, cookieJarId } as const;
|
||||||
if (inNewWindow) {
|
if (inNewWindow) {
|
||||||
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
|
||||||
const requestId = (await getRecentRequests(workspaceId))[0];
|
|
||||||
const path =
|
const path =
|
||||||
requestId != null
|
requestId != null
|
||||||
? routes.paths.request({
|
? routes.paths.request({ ...baseArgs, requestId })
|
||||||
workspaceId,
|
: routes.paths.workspace({ ...baseArgs });
|
||||||
environmentId,
|
|
||||||
requestId,
|
|
||||||
})
|
|
||||||
: routes.paths.workspace({ workspaceId, environmentId });
|
|
||||||
await invokeCmd('cmd_new_window', { url: path });
|
await invokeCmd('cmd_new_window', { url: path });
|
||||||
} else {
|
} else {
|
||||||
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
|
||||||
const requestId = (await getRecentRequests(workspaceId))[0];
|
|
||||||
if (requestId != null) {
|
if (requestId != null) {
|
||||||
routes.navigate('request', {
|
routes.navigate('request', { ...baseArgs, requestId });
|
||||||
workspaceId: workspaceId,
|
|
||||||
environmentId,
|
|
||||||
requestId,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
routes.navigate('workspace', { workspaceId, environmentId });
|
routes.navigate('workspace', { ...baseArgs });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import type { Appearance } from '../lib/theme/appearance';
|
||||||
import {
|
import {
|
||||||
getCSSAppearance,
|
getCSSAppearance,
|
||||||
getWindowAppearance,
|
getWindowAppearance,
|
||||||
subscribeToWindowAppearanceChange,
|
subscribeToWindowAppearanceChange,
|
||||||
} from '../lib/theme/appearance';
|
} from '../lib/theme/appearance';
|
||||||
import { type Appearance } from '../lib/theme/window';
|
|
||||||
|
|
||||||
export function usePreferredAppearance() {
|
export function usePreferredAppearance() {
|
||||||
const [preferredAppearance, setPreferredAppearance] = useState<Appearance>(getCSSAppearance());
|
const [preferredAppearance, setPreferredAppearance] = useState<Appearance>(getCSSAppearance());
|
||||||
|
|||||||
47
src-web/hooks/useRecentCookieJars.ts
Normal file
47
src-web/hooks/useRecentCookieJars.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { useEffect, useMemo } from 'react';
|
||||||
|
import { getKeyValue } from '../lib/keyValueStore';
|
||||||
|
import { useActiveCookieJar } from './useActiveCookieJar';
|
||||||
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
import { useCookieJars } from './useCookieJars';
|
||||||
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
|
const kvKey = (workspaceId: string) => 'recent_cookie_jars::' + workspaceId;
|
||||||
|
const namespace = 'global';
|
||||||
|
const fallback: string[] = [];
|
||||||
|
|
||||||
|
export function useRecentCookieJars() {
|
||||||
|
const cookieJars = useCookieJars();
|
||||||
|
const activeWorkspace = useActiveWorkspace();
|
||||||
|
const [activeCookieJar] = useActiveCookieJar();
|
||||||
|
const activeCookieJarId = activeCookieJar?.id ?? null;
|
||||||
|
const kv = useKeyValue<string[]>({
|
||||||
|
key: kvKey(activeWorkspace?.id ?? 'n/a'),
|
||||||
|
namespace,
|
||||||
|
fallback,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set history when active request changes
|
||||||
|
useEffect(() => {
|
||||||
|
kv.set((currentHistory: string[]) => {
|
||||||
|
if (activeCookieJarId === null) return currentHistory;
|
||||||
|
const withoutCurrent = currentHistory.filter((id) => id !== activeCookieJarId);
|
||||||
|
return [activeCookieJarId, ...withoutCurrent];
|
||||||
|
}).catch(console.error);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [activeCookieJarId]);
|
||||||
|
|
||||||
|
const onlyValidIds = useMemo(
|
||||||
|
() => kv.value?.filter((id) => cookieJars.data?.some((e) => e.id === id)) ?? [],
|
||||||
|
[kv.value, cookieJars],
|
||||||
|
);
|
||||||
|
|
||||||
|
return onlyValidIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRecentCookieJars(workspaceId: string) {
|
||||||
|
return getKeyValue<string[]>({
|
||||||
|
namespace,
|
||||||
|
key: kvKey(workspaceId),
|
||||||
|
fallback,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { getKeyValue } from '../lib/keyValueStore';
|
import { getKeyValue } from '../lib/keyValueStore';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useEnvironments } from './useEnvironments';
|
import { useEnvironments } from './useEnvironments';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
@@ -11,10 +11,10 @@ const fallback: string[] = [];
|
|||||||
|
|
||||||
export function useRecentEnvironments() {
|
export function useRecentEnvironments() {
|
||||||
const environments = useEnvironments();
|
const environments = useEnvironments();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeEnvironmentId = useActiveEnvironmentId();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const kv = useKeyValue<string[]>({
|
const kv = useKeyValue<string[]>({
|
||||||
key: kvKey(activeWorkspaceId ?? 'n/a'),
|
key: kvKey(activeWorkspace?.id ?? 'n/a'),
|
||||||
namespace,
|
namespace,
|
||||||
fallback,
|
fallback,
|
||||||
});
|
});
|
||||||
@@ -22,12 +22,12 @@ export function useRecentEnvironments() {
|
|||||||
// Set history when active request changes
|
// Set history when active request changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
kv.set((currentHistory: string[]) => {
|
kv.set((currentHistory: string[]) => {
|
||||||
if (activeEnvironmentId === null) return currentHistory;
|
if (activeEnvironment === null) return currentHistory;
|
||||||
const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironmentId);
|
const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironment.id);
|
||||||
return [activeEnvironmentId, ...withoutCurrentEnvironment];
|
return [activeEnvironment.id, ...withoutCurrentEnvironment];
|
||||||
}).catch(console.error);
|
}).catch(console.error);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [activeEnvironmentId]);
|
}, [activeEnvironment?.id]);
|
||||||
|
|
||||||
const onlyValidIds = useMemo(
|
const onlyValidIds = useMemo(
|
||||||
() => kv.value?.filter((id) => environments.some((e) => e.id === id)) ?? [],
|
() => kv.value?.filter((id) => environments.some((e) => e.id === id)) ?? [],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { getKeyValue } from '../lib/keyValueStore';
|
import { getKeyValue } from '../lib/keyValueStore';
|
||||||
import { useActiveRequestId } from './useActiveRequestId';
|
import { useActiveRequestId } from './useActiveRequestId';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
import { useRequests } from './useRequests';
|
import { useRequests } from './useRequests';
|
||||||
|
|
||||||
@@ -11,11 +11,11 @@ const fallback: string[] = [];
|
|||||||
|
|
||||||
export function useRecentRequests() {
|
export function useRecentRequests() {
|
||||||
const requests = useRequests();
|
const requests = useRequests();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeRequestId = useActiveRequestId();
|
const activeRequestId = useActiveRequestId();
|
||||||
|
|
||||||
const kv = useKeyValue<string[]>({
|
const kv = useKeyValue<string[]>({
|
||||||
key: kvKey(activeWorkspaceId ?? 'n/a'),
|
key: kvKey(activeWorkspace?.id ?? 'n/a'),
|
||||||
namespace,
|
namespace,
|
||||||
fallback,
|
fallback,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { getKeyValue } from '../lib/keyValueStore';
|
import { getKeyValue } from '../lib/keyValueStore';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
import { useWorkspaces } from './useWorkspaces';
|
import { useWorkspaces } from './useWorkspaces';
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ const fallback: string[] = [];
|
|||||||
|
|
||||||
export function useRecentWorkspaces() {
|
export function useRecentWorkspaces() {
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const kv = useKeyValue<string[]>({
|
const kv = useKeyValue<string[]>({
|
||||||
key: kvKey(),
|
key: kvKey(),
|
||||||
namespace,
|
namespace,
|
||||||
@@ -20,12 +20,12 @@ export function useRecentWorkspaces() {
|
|||||||
// Set history when active request changes
|
// Set history when active request changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
kv.set((currentHistory: string[]) => {
|
kv.set((currentHistory: string[]) => {
|
||||||
if (activeWorkspaceId === null) return currentHistory;
|
if (activeWorkspace === null) return currentHistory;
|
||||||
const withoutCurrent = currentHistory.filter((id) => id !== activeWorkspaceId);
|
const withoutCurrent = currentHistory.filter((id) => id !== activeWorkspace.id);
|
||||||
return [activeWorkspaceId, ...withoutCurrent];
|
return [activeWorkspace.id, ...withoutCurrent];
|
||||||
}).catch(console.error);
|
}).catch(console.error);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [activeWorkspaceId]);
|
}, [activeWorkspace]);
|
||||||
|
|
||||||
const onlyValidIds = useMemo(
|
const onlyValidIds = useMemo(
|
||||||
() => kv.value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [],
|
() => kv.value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [],
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { save } from '@tauri-apps/plugin-dialog';
|
|
||||||
import slugify from 'slugify';
|
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import type { HttpResponse } from '@yaakapp/api';
|
import type { HttpResponse } from '@yaakapp/api';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveCookieJar } from './useActiveCookieJar';
|
import { useActiveCookieJar } from './useActiveCookieJar';
|
||||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useAlert } from './useAlert';
|
import { useAlert } from './useAlert';
|
||||||
import { useHttpRequests } from './useHttpRequests';
|
import { useHttpRequests } from './useHttpRequests';
|
||||||
|
|
||||||
export function useSendAnyHttpRequest(options: { download?: boolean } = {}) {
|
export function useSendAnyHttpRequest() {
|
||||||
const environment = useActiveEnvironment();
|
const [environment] = useActiveEnvironment();
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
const { activeCookieJar } = useActiveCookieJar();
|
const [activeCookieJar] = useActiveCookieJar();
|
||||||
const requests = useHttpRequests();
|
const requests = useHttpRequests();
|
||||||
return useMutation<HttpResponse | null, string, string | null>({
|
return useMutation<HttpResponse | null, string, string | null>({
|
||||||
mutationKey: ['send_any_request'],
|
mutationKey: ['send_any_request'],
|
||||||
@@ -22,21 +20,9 @@ export function useSendAnyHttpRequest(options: { download?: boolean } = {}) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let downloadDir: string | null = null;
|
|
||||||
if (options.download) {
|
|
||||||
downloadDir = await save({
|
|
||||||
title: 'Select Download Destination',
|
|
||||||
defaultPath: slugify(request.name, { lower: true, trim: true, strict: true }),
|
|
||||||
});
|
|
||||||
if (downloadDir == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return invokeCmd('cmd_send_http_request', {
|
return invokeCmd('cmd_send_http_request', {
|
||||||
request,
|
request,
|
||||||
environmentId: environment?.id,
|
environmentId: environment?.id,
|
||||||
downloadDir: downloadDir,
|
|
||||||
cookieJarId: activeCookieJar?.id,
|
cookieJarId: activeCookieJar?.id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
|
|
||||||
export function useSidebarHidden() {
|
export function useSidebarHidden() {
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const { set, value } = useKeyValue<boolean>({
|
const { set, value } = useKeyValue<boolean>({
|
||||||
namespace: 'no_sync',
|
namespace: 'no_sync',
|
||||||
key: ['sidebar_hidden', activeWorkspaceId ?? 'n/a'],
|
key: ['sidebar_hidden', activeWorkspace?.id ?? 'n/a'],
|
||||||
fallback: false,
|
fallback: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useLocalStorage } from 'react-use';
|
import { useLocalStorage } from 'react-use';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
|
||||||
export function useSidebarWidth() {
|
export function useSidebarWidth() {
|
||||||
const activeWorkspaceId = useActiveWorkspaceId();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const [width, setWidth] = useLocalStorage<number>(`sidebar_width::${activeWorkspaceId}`, 250);
|
const [width, setWidth] = useLocalStorage<number>(
|
||||||
|
`sidebar_width::${activeWorkspace?.id ?? 'n/a'}`,
|
||||||
|
250,
|
||||||
|
);
|
||||||
const resetWidth = useCallback(() => setWidth(250), [setWidth]);
|
const resetWidth = useCallback(() => setWidth(250), [setWidth]);
|
||||||
return useMemo(() => ({ width, setWidth, resetWidth }), [width, setWidth, resetWidth]);
|
return useMemo(() => ({ width, setWidth, resetWidth }), [width, setWidth, resetWidth]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ export function useSyncThemeToDocument() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function emitBgChange(t: YaakTheme) {
|
function emitBgChange(t: YaakTheme) {
|
||||||
if (t.background == null) return;
|
if (t.surface == null) return;
|
||||||
emit('yaak_bg_changed', t.background.hex()).catch(console.error);
|
emit('yaak_bg_changed', t.surface.hexNoAlpha()).catch(console.error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { emit } from '@tauri-apps/api/event';
|
|||||||
export function useSyncWorkspaceRequestTitle() {
|
export function useSyncWorkspaceRequestTitle() {
|
||||||
const activeRequest = useActiveRequest();
|
const activeRequest = useActiveRequest();
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const activeEnvironment = useActiveEnvironment();
|
const [activeEnvironment] = useActiveEnvironment();
|
||||||
const osInfo = useOsInfo();
|
const osInfo = useOsInfo();
|
||||||
const appInfo = useAppInfo();
|
const appInfo = useAppInfo();
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { Folder } from '@yaakapp/api';
|
import type { Folder } from '@yaakapp/api';
|
||||||
import { getFolder } from '../lib/store';
|
import { getFolder } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { foldersQueryKey } from './useFolders';
|
|
||||||
|
|
||||||
export function useUpdateAnyFolder() {
|
export function useUpdateAnyFolder() {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
return useMutation<void, unknown, { id: string; update: (r: Folder) => Folder }>({
|
return useMutation<void, unknown, { id: string; update: (r: Folder) => Folder }>({
|
||||||
mutationKey: ['update_any_folder'],
|
mutationKey: ['update_any_folder'],
|
||||||
mutationFn: async ({ id, update }) => {
|
mutationFn: async ({ id, update }) => {
|
||||||
@@ -17,12 +14,5 @@ export function useUpdateAnyFolder() {
|
|||||||
|
|
||||||
await invokeCmd('cmd_update_folder', { folder: update(folder) });
|
await invokeCmd('cmd_update_folder', { folder: update(folder) });
|
||||||
},
|
},
|
||||||
onMutate: async ({ id, update }) => {
|
|
||||||
const folder = await getFolder(id);
|
|
||||||
if (folder === null) return;
|
|
||||||
queryClient.setQueryData<Folder[]>(foldersQueryKey(folder), (folders) =>
|
|
||||||
(folders ?? []).map((f) => (f.id === folder.id ? update(f) : f)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { GrpcRequest } from '@yaakapp/api';
|
import type { GrpcRequest } from '@yaakapp/api';
|
||||||
import { getGrpcRequest } from '../lib/store';
|
import { getGrpcRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
|
||||||
|
|
||||||
export function useUpdateAnyGrpcRequest() {
|
export function useUpdateAnyGrpcRequest() {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
return useMutation<
|
return useMutation<
|
||||||
void,
|
void,
|
||||||
unknown,
|
unknown,
|
||||||
@@ -23,14 +20,5 @@ export function useUpdateAnyGrpcRequest() {
|
|||||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||||
await invokeCmd('cmd_update_grpc_request', { request: patchedRequest });
|
await invokeCmd('cmd_update_grpc_request', { request: patchedRequest });
|
||||||
},
|
},
|
||||||
onMutate: async ({ id, update }) => {
|
|
||||||
const request = await getGrpcRequest(id);
|
|
||||||
if (request === null) return;
|
|
||||||
const patchedRequest =
|
|
||||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
|
||||||
queryClient.setQueryData<GrpcRequest[]>(grpcRequestsQueryKey(request), (requests) =>
|
|
||||||
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { HttpRequest } from '@yaakapp/api';
|
import type { HttpRequest } from '@yaakapp/api';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
|
||||||
|
|
||||||
export function useUpdateAnyHttpRequest() {
|
export function useUpdateAnyHttpRequest() {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
return useMutation<
|
return useMutation<
|
||||||
void,
|
void,
|
||||||
unknown,
|
unknown,
|
||||||
@@ -23,14 +20,5 @@ export function useUpdateAnyHttpRequest() {
|
|||||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||||
await invokeCmd('cmd_update_http_request', { request: patchedRequest });
|
await invokeCmd('cmd_update_http_request', { request: patchedRequest });
|
||||||
},
|
},
|
||||||
onMutate: async ({ id, update }) => {
|
|
||||||
const request = await getHttpRequest(id);
|
|
||||||
if (request === null) return;
|
|
||||||
const patchedRequest =
|
|
||||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
|
||||||
queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey(request), (requests) =>
|
|
||||||
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { CookieJar } from '../lib/models';
|
import type { CookieJar } from '../lib/models';
|
||||||
import { getCookieJar } from '../lib/store';
|
import { getCookieJar } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { cookieJarsQueryKey } from './useCookieJars';
|
|
||||||
|
|
||||||
export function useUpdateCookieJar(id: string | null) {
|
export function useUpdateCookieJar(id: string | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation<void, unknown, Partial<CookieJar> | ((j: CookieJar) => CookieJar)>({
|
return useMutation<void, unknown, Partial<CookieJar> | ((j: CookieJar) => CookieJar)>({
|
||||||
mutationKey: ['update_cookie_jar', id],
|
mutationKey: ['update_cookie_jar', id],
|
||||||
mutationFn: async (v) => {
|
mutationFn: async (v) => {
|
||||||
@@ -15,17 +13,7 @@ export function useUpdateCookieJar(id: string | null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
||||||
console.log('NEW COOKIE JAR', newCookieJar.cookies.length);
|
|
||||||
await invokeCmd('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
await invokeCmd('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
||||||
},
|
},
|
||||||
onMutate: async (v) => {
|
|
||||||
const cookieJar = await getCookieJar(id);
|
|
||||||
if (cookieJar === null) return;
|
|
||||||
|
|
||||||
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
|
||||||
queryClient.setQueryData<CookieJar[]>(cookieJarsQueryKey(cookieJar), (cookieJars) =>
|
|
||||||
(cookieJars ?? []).map((j) => (j.id === newCookieJar.id ? newCookieJar : j)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { Environment } from '@yaakapp/api';
|
import type { Environment } from '@yaakapp/api';
|
||||||
import { getEnvironment } from '../lib/store';
|
import { getEnvironment } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { environmentsQueryKey } from './useEnvironments';
|
|
||||||
|
|
||||||
export function useUpdateEnvironment(id: string | null) {
|
export function useUpdateEnvironment(id: string | null) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation<void, unknown, Partial<Environment> | ((r: Environment) => Environment)>({
|
return useMutation<void, unknown, Partial<Environment> | ((r: Environment) => Environment)>({
|
||||||
mutationKey: ['update_environment', id],
|
mutationKey: ['update_environment', id],
|
||||||
mutationFn: async (v) => {
|
mutationFn: async (v) => {
|
||||||
@@ -17,14 +15,5 @@ export function useUpdateEnvironment(id: string | null) {
|
|||||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
||||||
await invokeCmd('cmd_update_environment', { environment: newEnvironment });
|
await invokeCmd('cmd_update_environment', { environment: newEnvironment });
|
||||||
},
|
},
|
||||||
onMutate: async (v) => {
|
|
||||||
const environment = await getEnvironment(id);
|
|
||||||
if (environment === null) return;
|
|
||||||
|
|
||||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
|
||||||
queryClient.setQueryData<Environment[]>(environmentsQueryKey(environment), (environments) =>
|
|
||||||
(environments ?? []).map((r) => (r.id === newEnvironment.id ? newEnvironment : r)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user