mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Removed session storage logic and added a few UI improvements
This commit is contained in:
@@ -440,46 +440,6 @@ export const useCreateCommit = () => {
|
||||
}
|
||||
>({
|
||||
mutationFn: async ({ workspaceId, environment, secretPath, pendingChanges, message }) => {
|
||||
const transformedSecretUpdates = pendingChanges.secrets
|
||||
.filter((change) => change.type === PendingAction.Update)
|
||||
.map((change: PendingSecretUpdate) => {
|
||||
const updatePayload: {
|
||||
secretKey: string;
|
||||
newSecretName?: string;
|
||||
secretValue?: string;
|
||||
secretComment?: string;
|
||||
skipMultilineEncoding?: boolean;
|
||||
tagIds?: string[];
|
||||
secretMetadata?: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
} = {
|
||||
secretKey: change.secretKey
|
||||
};
|
||||
|
||||
// Only include fields that actually changed
|
||||
if (change.newSecretName) {
|
||||
updatePayload.newSecretName = change.newSecretName;
|
||||
}
|
||||
if (change.secretValue !== undefined) {
|
||||
updatePayload.secretValue = change.secretValue;
|
||||
}
|
||||
if (change.secretComment !== undefined) {
|
||||
updatePayload.secretComment = change.secretComment;
|
||||
}
|
||||
if (change.skipMultilineEncoding !== undefined) {
|
||||
updatePayload.skipMultilineEncoding = change.skipMultilineEncoding;
|
||||
}
|
||||
if (change.tags) {
|
||||
updatePayload.tagIds = change.tags.map((tag) => tag.id);
|
||||
}
|
||||
if (change.secretMetadata) {
|
||||
updatePayload.secretMetadata = change.secretMetadata;
|
||||
}
|
||||
|
||||
return updatePayload;
|
||||
});
|
||||
const { data } = await apiRequest.post("/api/v1/pit/batch/commit", {
|
||||
projectId: workspaceId,
|
||||
environment,
|
||||
@@ -497,7 +457,23 @@ export const useCreateCommit = () => {
|
||||
tagIds: change.tags?.map((tag) => tag.id),
|
||||
secretMetadata: change.secretMetadata
|
||||
})) || [],
|
||||
update: transformedSecretUpdates || [],
|
||||
update:
|
||||
pendingChanges.secrets
|
||||
.filter((change) => change.type === PendingAction.Update)
|
||||
.map((change: PendingSecretUpdate) => ({
|
||||
secretKey: change.secretKey,
|
||||
newSecretName: change.newSecretName,
|
||||
secretValue: change.secretValue || change.existingSecret.value,
|
||||
secretComment: change.secretComment || change.existingSecret.comment,
|
||||
skipMultilineEncoding:
|
||||
change.skipMultilineEncoding !== undefined
|
||||
? change.skipMultilineEncoding
|
||||
: change.existingSecret.skipMultilineEncoding,
|
||||
tagIds:
|
||||
change.tags?.map((tag) => tag.id) ||
|
||||
change.existingSecret.tags?.map((tag) => tag.id),
|
||||
secretMetadata: change.secretMetadata || change.existingSecret.secretMetadata
|
||||
})) || [],
|
||||
delete:
|
||||
pendingChanges.secrets.filter((change) => change.type === PendingAction.Delete) || []
|
||||
},
|
||||
|
||||
@@ -417,7 +417,9 @@ const Page = () => {
|
||||
imports?.length ||
|
||||
dynamicSecrets?.length ||
|
||||
secretRotations?.length ||
|
||||
noAccessSecretCount
|
||||
noAccessSecretCount ||
|
||||
pendingChanges.secrets.length ||
|
||||
pendingChanges.folders.length
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -604,15 +606,16 @@ const Page = () => {
|
||||
secretMetadata: change.secretMetadata || mergedSecrets[updateIndex].secretMetadata,
|
||||
isPending: true,
|
||||
pendingAction: PendingAction.Update,
|
||||
tags:
|
||||
change.tags?.map((tag) => ({
|
||||
id: tag.id,
|
||||
slug: tag.slug,
|
||||
projectId: workspaceId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
__v: 0
|
||||
})) || []
|
||||
tags: change.tags
|
||||
? change.tags?.map((tag) => ({
|
||||
id: tag.id,
|
||||
slug: tag.slug,
|
||||
projectId: workspaceId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
__v: 0
|
||||
})) || []
|
||||
: mergedSecrets[updateIndex].tags
|
||||
};
|
||||
}
|
||||
break;
|
||||
@@ -935,25 +938,34 @@ const Page = () => {
|
||||
folders?.length === 0 && <PermissionDeniedBanner />}
|
||||
</div>
|
||||
</div>
|
||||
{!isDetailsLoading && totalCount > 0 && (
|
||||
<Pagination
|
||||
startAdornment={
|
||||
<SecretTableResourceCount
|
||||
dynamicSecretCount={totalDynamicSecretCount}
|
||||
importCount={totalImportCount}
|
||||
secretCount={totalSecretCount}
|
||||
folderCount={totalFolderCount}
|
||||
secretRotationCount={totalSecretRotationCount}
|
||||
/>
|
||||
}
|
||||
className="rounded-b-md border-t border-solid border-t-mineshaft-600"
|
||||
count={totalCount}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
onChangePage={(newPage) => setPage(newPage)}
|
||||
onChangePerPage={handlePerPageChange}
|
||||
/>
|
||||
)}
|
||||
{!isDetailsLoading &&
|
||||
(totalCount > 0 ||
|
||||
pendingChanges.secrets.length > 0 ||
|
||||
pendingChanges.folders.length > 0) && (
|
||||
<Pagination
|
||||
startAdornment={
|
||||
<SecretTableResourceCount
|
||||
dynamicSecretCount={totalDynamicSecretCount}
|
||||
importCount={totalImportCount}
|
||||
secretCount={
|
||||
totalSecretCount +
|
||||
pendingChanges.secrets.filter((s) => s.type === PendingAction.Create).length
|
||||
}
|
||||
folderCount={
|
||||
totalFolderCount +
|
||||
pendingChanges.folders.filter((f) => f.type === PendingAction.Create).length
|
||||
}
|
||||
secretRotationCount={totalSecretRotationCount}
|
||||
/>
|
||||
}
|
||||
className="rounded-b-md border-t border-solid border-t-mineshaft-600"
|
||||
count={totalCount + pendingChanges.secrets.length + pendingChanges.folders.length}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
onChangePage={(newPage) => setPage(newPage)}
|
||||
onChangePerPage={handlePerPageChange}
|
||||
/>
|
||||
)}
|
||||
<Modal
|
||||
isOpen={createSecretPopUp.isOpen}
|
||||
onOpenChange={(state) => togglePopUp(PopUpNames.CreateSecretForm, state)}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useRouter } from "@tanstack/react-router";
|
||||
import { createStore, StateCreator, StoreApi, useStore } from "zustand";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { PendingAction } from "@app/hooks/api/secretFolders/types";
|
||||
import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types";
|
||||
|
||||
@@ -45,6 +46,7 @@ export interface PendingSecretUpdate extends BasePendingChange {
|
||||
tags?: { id: string; slug: string }[];
|
||||
originalSecretMetadata?: { key: string; value: string }[];
|
||||
secretMetadata?: { key: string; value: string }[];
|
||||
existingSecret: SecretV3RawSanitized;
|
||||
}
|
||||
|
||||
export interface PendingSecretDelete extends BasePendingChange {
|
||||
@@ -100,68 +102,6 @@ export interface BatchContext {
|
||||
secretPath: string;
|
||||
}
|
||||
|
||||
const STORAGE_KEY = "infisical_pending_changes";
|
||||
|
||||
const generateContextKey = (workspaceId: string, environment: string, secretPath: string) => {
|
||||
return `${workspaceId}_${environment}_${secretPath}`;
|
||||
};
|
||||
|
||||
const savePendingChangesToStorage = (
|
||||
changes: PendingChanges,
|
||||
workspaceId: string,
|
||||
environment: string,
|
||||
secretPath: string
|
||||
) => {
|
||||
const key = `${STORAGE_KEY}_${generateContextKey(workspaceId, environment, secretPath)}`;
|
||||
try {
|
||||
sessionStorage.setItem(key, JSON.stringify(changes));
|
||||
} catch (error) {
|
||||
console.warn("Failed to save pending changes to sessionStorage:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const loadPendingChangesFromStorage = (
|
||||
workspaceId: string,
|
||||
environment: string,
|
||||
secretPath: string
|
||||
): PendingChanges => {
|
||||
const key = `${STORAGE_KEY}_${generateContextKey(workspaceId, environment, secretPath)}`;
|
||||
const stored = sessionStorage.getItem(key);
|
||||
if (!stored) return { secrets: [], folders: [] };
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(stored);
|
||||
if (Array.isArray(parsed)) {
|
||||
return {
|
||||
secrets: parsed.filter(
|
||||
(change: any) => !change.resourceType || change.resourceType === "secret"
|
||||
),
|
||||
folders: []
|
||||
};
|
||||
}
|
||||
return {
|
||||
secrets: parsed.secrets || [],
|
||||
folders: parsed.folders || []
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn("Failed to parse pending changes from sessionStorage:", error);
|
||||
return { secrets: [], folders: [] };
|
||||
}
|
||||
};
|
||||
|
||||
const clearPendingChangesFromStorage = (
|
||||
workspaceId: string,
|
||||
environment: string,
|
||||
secretPath: string
|
||||
) => {
|
||||
const key = `${STORAGE_KEY}_${generateContextKey(workspaceId, environment, secretPath)}`;
|
||||
try {
|
||||
sessionStorage.removeItem(key);
|
||||
} catch (error) {
|
||||
console.warn("Failed to clear pending changes from sessionStorage:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const normalizeValue = (value: any): string | boolean | undefined => {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return undefined;
|
||||
@@ -207,7 +147,8 @@ const cleanupRevertedSecretFields = (update: PendingSecretUpdate): PendingSecret
|
||||
|
||||
if (
|
||||
cleaned.secretComment !== undefined &&
|
||||
!areValuesEqual(cleaned.secretComment, cleaned.originalComment)
|
||||
(!areValuesEqual(cleaned.secretComment, cleaned.originalComment) ||
|
||||
!areValuesEqual(cleaned.secretComment, cleaned.existingSecret.comment))
|
||||
) {
|
||||
hasChanges = true;
|
||||
} else {
|
||||
@@ -302,6 +243,7 @@ const createSelectedSecretStore: StateCreator<CombinedState, [], [], SelectedSec
|
||||
type BatchModeState = {
|
||||
isBatchMode: boolean;
|
||||
pendingChanges: PendingChanges;
|
||||
pendingChangesByContext: Map<string, PendingChanges>;
|
||||
existingSecretKeys: Set<string>;
|
||||
existingFolderNames: Set<string>;
|
||||
currentContext: BatchContext | null;
|
||||
@@ -315,16 +257,32 @@ type BatchModeState = {
|
||||
};
|
||||
};
|
||||
|
||||
const generateContextKey = (workspaceId: string, environment: string, secretPath: string) => {
|
||||
return `${workspaceId}_${environment}_${secretPath}`;
|
||||
};
|
||||
|
||||
const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState> = (set, get) => ({
|
||||
isBatchMode: true, // Always enabled by default
|
||||
pendingChanges: { secrets: [], folders: [] },
|
||||
pendingChangesByContext: new Map<string, PendingChanges>(),
|
||||
currentContext: null,
|
||||
existingSecretKeys: new Set<string>(),
|
||||
existingFolderNames: new Set<string>(),
|
||||
batchActions: {
|
||||
addPendingChange: (change: PendingChange, context: BatchContext) =>
|
||||
set((state) => {
|
||||
const newChanges = { ...state.pendingChanges };
|
||||
const contextKey = generateContextKey(
|
||||
context.workspaceId,
|
||||
context.environment,
|
||||
context.secretPath
|
||||
);
|
||||
|
||||
// Get existing changes for this context or create new empty state
|
||||
const existingChanges = state.pendingChangesByContext.get(contextKey) || {
|
||||
secrets: [],
|
||||
folders: []
|
||||
};
|
||||
const newChanges = { ...existingChanges };
|
||||
|
||||
if (change.resourceType === "folder") {
|
||||
const existingFolder =
|
||||
@@ -332,6 +290,10 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
newChanges.folders.some((f) => f.folderName === change.folderName);
|
||||
|
||||
if (change.type === PendingAction.Create && existingFolder) {
|
||||
createNotification({
|
||||
text: "Another folder with same name already exists",
|
||||
type: "error"
|
||||
});
|
||||
return { pendingChanges: newChanges };
|
||||
}
|
||||
if (
|
||||
@@ -339,6 +301,10 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
change.folderName !== change.originalFolderName &&
|
||||
existingFolder
|
||||
) {
|
||||
createNotification({
|
||||
text: "Another folder with same name already exists",
|
||||
type: "error"
|
||||
});
|
||||
return { pendingChanges: newChanges };
|
||||
}
|
||||
}
|
||||
@@ -346,9 +312,19 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
if (change.resourceType === "secret") {
|
||||
const existingSecret =
|
||||
state.existingSecretKeys.has(change.secretKey) ||
|
||||
newChanges.secrets.some((s) => (s.secretKey === change.secretKey && s.type !== PendingAction.Create) || (change.type === PendingAction.Create && change.originalKey !== change.secretKey && s.secretKey === change.secretKey));
|
||||
newChanges.secrets.some(
|
||||
(s) =>
|
||||
(s.secretKey === change.secretKey && s.type !== PendingAction.Create) ||
|
||||
(change.type === PendingAction.Create &&
|
||||
change.originalKey !== change.secretKey &&
|
||||
s.secretKey === change.secretKey)
|
||||
);
|
||||
|
||||
if (change.type === PendingAction.Create && existingSecret) {
|
||||
createNotification({
|
||||
text: "Another secret with same name already exists",
|
||||
type: "error"
|
||||
});
|
||||
return { pendingChanges: newChanges };
|
||||
}
|
||||
|
||||
@@ -366,6 +342,10 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
));
|
||||
|
||||
if (existingNewSecretName) {
|
||||
createNotification({
|
||||
text: "Another secret with same name already exists",
|
||||
type: "error"
|
||||
});
|
||||
return { pendingChanges: newChanges };
|
||||
}
|
||||
}
|
||||
@@ -425,7 +405,6 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
|
||||
if (existingUpdateIndex >= 0) {
|
||||
const existingUpdate = secretChanges[existingUpdateIndex] as PendingSecretUpdate;
|
||||
|
||||
const mergedUpdate: PendingSecretUpdate = {
|
||||
...existingUpdate,
|
||||
secretKey: existingUpdate.secretKey,
|
||||
@@ -456,7 +435,7 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
change.secretMetadata !== undefined
|
||||
? change.secretMetadata
|
||||
: existingUpdate.secretMetadata,
|
||||
|
||||
existingSecret: existingUpdate.existingSecret,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
@@ -566,18 +545,40 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
newChanges.folders = folderChanges;
|
||||
}
|
||||
|
||||
savePendingChangesToStorage(
|
||||
newChanges,
|
||||
context.workspaceId,
|
||||
context.environment,
|
||||
context.secretPath
|
||||
);
|
||||
return { pendingChanges: newChanges };
|
||||
const updatedContextMap = new Map(state.pendingChangesByContext);
|
||||
updatedContextMap.set(contextKey, newChanges);
|
||||
|
||||
const currentChanges =
|
||||
contextKey ===
|
||||
generateContextKey(
|
||||
state.currentContext?.workspaceId || context.workspaceId,
|
||||
state.currentContext?.environment || context.environment,
|
||||
state.currentContext?.secretPath || context.secretPath
|
||||
)
|
||||
? newChanges
|
||||
: state.pendingChanges;
|
||||
|
||||
return {
|
||||
pendingChangesByContext: updatedContextMap,
|
||||
pendingChanges: currentChanges,
|
||||
currentContext: context
|
||||
};
|
||||
}),
|
||||
|
||||
removePendingChange: (changeId: string, resourceType: string, context: BatchContext) =>
|
||||
set((state) => {
|
||||
const newChanges = { ...state.pendingChanges };
|
||||
const contextKey = generateContextKey(
|
||||
context.workspaceId,
|
||||
context.environment,
|
||||
context.secretPath
|
||||
);
|
||||
|
||||
// Get existing changes for this context
|
||||
const existingChanges = state.pendingChangesByContext.get(contextKey) || {
|
||||
secrets: [],
|
||||
folders: []
|
||||
};
|
||||
const newChanges = { ...existingChanges };
|
||||
|
||||
if (resourceType === "secret") {
|
||||
newChanges.secrets = newChanges.secrets.filter((c) => c.id !== changeId);
|
||||
@@ -585,28 +586,70 @@ const createBatchModeStore: StateCreator<CombinedState, [], [], BatchModeState>
|
||||
newChanges.folders = newChanges.folders.filter((c) => c.id !== changeId);
|
||||
}
|
||||
|
||||
savePendingChangesToStorage(
|
||||
newChanges,
|
||||
context.workspaceId,
|
||||
context.environment,
|
||||
context.secretPath
|
||||
);
|
||||
return { pendingChanges: newChanges };
|
||||
const updatedContextMap = new Map(state.pendingChangesByContext);
|
||||
updatedContextMap.set(contextKey, newChanges);
|
||||
|
||||
const isCurrentContext =
|
||||
state.currentContext &&
|
||||
contextKey ===
|
||||
generateContextKey(
|
||||
state.currentContext.workspaceId,
|
||||
state.currentContext.environment,
|
||||
state.currentContext.secretPath
|
||||
);
|
||||
|
||||
return {
|
||||
pendingChangesByContext: updatedContextMap,
|
||||
pendingChanges: isCurrentContext ? newChanges : state.pendingChanges
|
||||
};
|
||||
}),
|
||||
|
||||
loadPendingChanges: (context) => {
|
||||
const changes = loadPendingChangesFromStorage(
|
||||
const contextKey = generateContextKey(
|
||||
context.workspaceId,
|
||||
context.environment,
|
||||
context.secretPath
|
||||
);
|
||||
set({ pendingChanges: changes });
|
||||
|
||||
set((state) => {
|
||||
const contextChanges = state.pendingChangesByContext.get(contextKey) || {
|
||||
secrets: [],
|
||||
folders: []
|
||||
};
|
||||
|
||||
return {
|
||||
pendingChanges: contextChanges,
|
||||
currentContext: context
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
clearAllPendingChanges: (context) => {
|
||||
clearPendingChangesFromStorage(context.workspaceId, context.environment, context.secretPath);
|
||||
set({
|
||||
pendingChanges: { secrets: [], folders: [] }
|
||||
const contextKey = generateContextKey(
|
||||
context.workspaceId,
|
||||
context.environment,
|
||||
context.secretPath
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
// Clear changes for this specific context
|
||||
const updatedContextMap = new Map(state.pendingChangesByContext);
|
||||
updatedContextMap.delete(contextKey);
|
||||
|
||||
// If this is the current context, also clear the active pending changes
|
||||
const isCurrentContext =
|
||||
state.currentContext &&
|
||||
contextKey ===
|
||||
generateContextKey(
|
||||
state.currentContext.workspaceId,
|
||||
state.currentContext.environment,
|
||||
state.currentContext.secretPath
|
||||
);
|
||||
|
||||
return {
|
||||
pendingChangesByContext: updatedContextMap,
|
||||
pendingChanges: isCurrentContext ? { secrets: [], folders: [] } : state.pendingChanges
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ const ChangeTable: React.FC<ChangeTableProps> = ({
|
||||
{hasKeyChange && (
|
||||
<ComparisonTableRow
|
||||
label="Key"
|
||||
previousValue={<span className="font-mono">{change.secretKey}</span>}
|
||||
previousValue={<span className="font-mono">{change.existingSecret.key}</span>}
|
||||
newValue={<span className="font-mono">{change.newSecretName}</span>}
|
||||
/>
|
||||
)}
|
||||
@@ -200,7 +200,7 @@ const ChangeTable: React.FC<ChangeTableProps> = ({
|
||||
label="Value"
|
||||
previousValue={
|
||||
<div className="max-w-md break-all rounded">
|
||||
{change.originalValue || <span className="italic">(empty)</span>}
|
||||
{change.existingSecret.value || <span className="italic">(empty)</span>}
|
||||
</div>
|
||||
}
|
||||
newValue={
|
||||
@@ -213,28 +213,32 @@ const ChangeTable: React.FC<ChangeTableProps> = ({
|
||||
{hasCommentChange && (
|
||||
<ComparisonTableRow
|
||||
label="Comment"
|
||||
previousValue={change.originalComment || <span className="italic">(empty)</span>}
|
||||
previousValue={
|
||||
change.existingSecret.comment || <span className="italic">(empty)</span>
|
||||
}
|
||||
newValue={change.secretComment || <span className="italic">(empty)</span>}
|
||||
/>
|
||||
)}
|
||||
{hasMultilineChange && (
|
||||
<ComparisonTableRow
|
||||
label="Multiline"
|
||||
previousValue={change.originalSkipMultilineEncoding ? "Enabled" : "Disabled"}
|
||||
label="Multi-line Encoding"
|
||||
previousValue={
|
||||
change.existingSecret.skipMultilineEncoding ? "Enabled" : "Disabled"
|
||||
}
|
||||
newValue={change.skipMultilineEncoding ? "Enabled" : "Disabled"}
|
||||
/>
|
||||
)}
|
||||
{hasTagsChange && (
|
||||
<ComparisonTableRow
|
||||
label="Tags"
|
||||
previousValue={<TagsList tags={change.originalTags} />}
|
||||
previousValue={<TagsList tags={change.existingSecret.tags} />}
|
||||
newValue={<TagsList tags={change.tags} />}
|
||||
/>
|
||||
)}
|
||||
{hasMetadataChange && (
|
||||
<ComparisonTableRow
|
||||
label="Metadata"
|
||||
previousValue={<MetadataList metadata={change.originalSecretMetadata} />}
|
||||
previousValue={<MetadataList metadata={change.existingSecret.secretMetadata} />}
|
||||
newValue={<MetadataList metadata={change.secretMetadata} />}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -220,7 +220,7 @@ export const SecretItem = memo(
|
||||
}
|
||||
|
||||
if (isDirty && !isSubmitting && !isAutoSavingRef.current) {
|
||||
const debounceTime = isPending ? 500 : 1500;
|
||||
const debounceTime = 600;
|
||||
|
||||
autoSaveTimeoutRef.current = setTimeout(() => {
|
||||
autoSaveChanges(formValues);
|
||||
|
||||
@@ -86,17 +86,16 @@ export const SecretListView = ({
|
||||
const selectedSecrets = useSelectedSecrets();
|
||||
const { toggle: toggleSelectedSecret } = useSelectedSecretActions();
|
||||
const { isBatchMode, pendingChanges } = useBatchMode();
|
||||
useNavigationBlocker(
|
||||
{
|
||||
shouldBlock: pendingChanges.secrets.length > 0 || pendingChanges.folders.length > 0,
|
||||
message: "You have unsaved changes. If you leave now, your work will be lost. Do you want to continue?",
|
||||
context: {
|
||||
workspaceId,
|
||||
environment,
|
||||
secretPath
|
||||
}
|
||||
useNavigationBlocker({
|
||||
shouldBlock: pendingChanges.secrets.length > 0 || pendingChanges.folders.length > 0,
|
||||
message:
|
||||
"You have unsaved changes. If you leave now, your work will be lost. Do you want to continue?",
|
||||
context: {
|
||||
workspaceId,
|
||||
environment,
|
||||
secretPath
|
||||
}
|
||||
);
|
||||
});
|
||||
const { addPendingChange } = useBatchModeActions();
|
||||
|
||||
const handleSecretOperation = async (
|
||||
@@ -368,7 +367,8 @@ export const SecretListView = ({
|
||||
}),
|
||||
|
||||
timestamp: Date.now(),
|
||||
resourceType: "secret"
|
||||
resourceType: "secret",
|
||||
existingSecret: orgSecret
|
||||
};
|
||||
|
||||
addPendingChange(updateChange, {
|
||||
|
||||
Reference in New Issue
Block a user