Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/components/operations/AddPotentialLinkModal.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { inject, ref, onMounted, reactive, computed } from "vue";
import { inject, ref, onMounted, reactive, computed, watch } from "vue";
import { storeToRefs } from "pinia";
import { toast } from 'bulma-toast'

Expand All @@ -10,7 +10,7 @@ import { useAbilityStore } from "@/stores/abilityStore";
import { useSourceStore } from "@/stores/sourceStore";
import { cartesian } from "@/utils/utils";

const props = defineProps({
const props = defineProps({
active: Boolean,
operation: Object,
agent: Object
Expand All @@ -25,6 +25,20 @@ const abilityStore = useAbilityStore();
const sourceStore = useSourceStore();
const { sources } = storeToRefs(sourceStore);

// Re-fetch abilities and agents when the modal is opened
watch(
() => props.active,
async (newValue) => {
if (newValue) {
await Promise.all([
abilityStore.getAbilities($api),
agentStore.getAgents($api),
sourceStore.getSources($api),
]);
}
}
);

let selectedPotentialLink = ref({});
let selectedPotentialLinkFacts = ref({});
let potentialLinkCommand = ref("");
Expand Down
29 changes: 22 additions & 7 deletions src/components/operations/CreateModal.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { ref, inject, onMounted } from "vue";
import { ref, inject, onMounted, watch } from "vue";
import { storeToRefs } from "pinia";
import { toast } from 'bulma-toast';
import { sanitizeInput, validateInput } from "@/utils/sanitize";
Expand Down Expand Up @@ -45,15 +45,30 @@ let validation = ref({
name: "",
});

async function refreshDropdownData() {
await Promise.all([
agentStore.getAgents($api),
adversaryStore.getAdversaries($api),
getSources(),
coreStore.getObfuscators($api),
getPlanners(),
]);
}

onMounted(async () => {
await agentStore.getAgents($api);
agentStore.updateAgentGroups();
await adversaryStore.getAdversaries($api);
await getSources();
await coreStore.getObfuscators($api);
await getPlanners();
await refreshDropdownData();
});

// Re-fetch all dropdown data when the modal is opened
watch(
() => modals.value.operations.showCreate,
async (newValue) => {
if (newValue) {
await refreshDropdownData();
}
}
);

async function getSources() {
try {
await sourceStore.getSources($api);
Expand Down
21 changes: 14 additions & 7 deletions src/components/schedules/CreateScheduleModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,26 @@ let validation = ref({
name: "",
});

async function refreshDropdownData() {
await Promise.all([
agentStore.getAgents($api),
adversaryStore.getAdversaries($api),
getSources(),
coreStore.getObfuscators($api),
getPlanners(),
]);
}

onMounted(async () => {
await agentStore.getAgents($api);
agentStore.updateAgentGroups();
await adversaryStore.getAdversaries($api);
await getSources();
await coreStore.getObfuscators($api);
await getPlanners();
await refreshDropdownData();
});

// Re-fetch all dropdown data and reset fields when the modal is opened
watch(
() => modals.value.schedules.showCreate,
(newValue) => {
async (newValue) => {
if (newValue) {
await refreshDropdownData();
resetFields();
}
}
Expand Down
27 changes: 16 additions & 11 deletions src/stores/adversaryStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const useAdversaryStore = defineStore("adversaryStore", {
this.adversaries.push(response.data);
this.adversaries.sort((a, b) => a.name > b.name);
this.selectedAdversary = response.data;
this.updateSelectedAdversaryAbilities();
this.updateSelectedAdversaryAbilities($api);
} catch (error) {
console.error("Error creating an adversary", error);
}
Expand Down Expand Up @@ -112,19 +112,24 @@ export const useAdversaryStore = defineStore("adversaryStore", {
console.error("Error deleting adversary", error);
}
},
updateSelectedAdversaryAbilities() {
async updateSelectedAdversaryAbilities($api) {
if (!this.selectedAdversary.atomic_ordering) {
this.selectedAdversaryAbilities = [];
} else {
this.selectedAdversaryAbilities =
this.selectedAdversary.atomic_ordering.map((ability_id) => {
return {
...abilityStore().abilities.find(
(ability) => ability.ability_id === ability_id
),
};
});
return;
}
// Re-fetch abilities to ensure we have the latest data
if ($api) {
await abilityStore().getAbilities($api);
}
this.selectedAdversaryAbilities =
this.selectedAdversary.atomic_ordering
.map((ability_id) => {
const found = abilityStore().abilities.find(
(ability) => ability.ability_id === ability_id
);
return found ? { ...found } : null;
})
.filter((ability) => ability !== null);
Comment on lines +120 to +132
},
},
});
13 changes: 8 additions & 5 deletions src/stores/agentStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ export const useAgentStore = defineStore("agentStore", {
agents: [],
agentConfig: {},
selectedAgent: {},
agentGroups: []
};
},

getters: {
agentGroups: (state) => {
if (!state.agents) return [];
return [...new Set(state.agents.map((agent) => agent.group))];
},
},

actions: {
async getAgents($api) {
try {
Expand Down Expand Up @@ -64,9 +70,6 @@ export const useAgentStore = defineStore("agentStore", {
throw error;
}
},
updateAgentGroups() {
if (!this.agents) return;
this.agentGroups = [...new Set(this.agents.map((agent) => agent.group))];
}
// agentGroups is now a getter derived from agents state
},
});
2 changes: 1 addition & 1 deletion src/views/AdversariesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ onMounted(async () => {

function selectAdversary(adversary) {
selectedAdversary.value = adversary;
adversaryStore.updateSelectedAdversaryAbilities();
adversaryStore.updateSelectedAdversaryAbilities($api);
isAdversaryDropdownOpen.value = false;
adversarySearchQuery.value = "";
}
Expand Down
9 changes: 8 additions & 1 deletion src/views/OperationsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const coreStore = useCoreStore();
const { modals } = storeToRefs(coreDisplayStore);

let updateInterval = ref();
let operationsListInterval = ref();
Comment on lines 47 to +48
let showPotentialLinkModal = ref(false);
let selectedOutputLink = ref(null);

Expand Down Expand Up @@ -175,12 +176,18 @@ onMounted(async () => {
await operationStore.getOperations($api);
await coreStore.getObfuscators($api);
await agentStore.getAgents($api);
agentStore.updateAgentGroups();
// agentGroups is now a computed getter, no manual update needed
selectOperation();

// Periodically refresh the operations list to pick up new/changed operations
operationsListInterval.value = setInterval(async () => {
await operationStore.getOperations($api);
}, 15000);
Comment on lines +182 to +185
});

onBeforeUnmount(() => {
if (updateInterval) clearInterval(updateInterval);
if (operationsListInterval.value) clearInterval(operationsListInterval.value);
});
Comment on lines 188 to 191

const resetFilter = () => {
Expand Down
2 changes: 1 addition & 1 deletion src/views/SchedulesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ onMounted(async () => {
await scheduleStore.getSchedules($api);
await coreStore.getObfuscators($api);
await agentStore.getAgents($api);
agentStore.updateAgentGroups();
// agentGroups is now a computed getter, no manual update needed
});
</script>

Expand Down
Loading