-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from jbaptperez/feature/manage-payloads
Feature - Manage payloads
- Loading branch information
Showing
8 changed files
with
247 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
dist/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<script setup> | ||
import { ref, inject} from "vue"; | ||
import { useAbilityStore } from "../../stores/abilityStore"; | ||
import { useCoreDisplayStore } from "../../stores/coreDisplayStore"; | ||
import { storeToRefs } from "pinia"; | ||
const $api = inject("$api"); | ||
const abilityStore = useAbilityStore(); | ||
const coreDisplayStore = useCoreDisplayStore(); | ||
const { modals } = storeToRefs(coreDisplayStore); | ||
const fileUploadPlaceholder = "No file selected."; | ||
const fileName = ref(fileUploadPlaceholder); | ||
const isFileSelected = ref(false); | ||
const input = ref(null); | ||
async function updateFileName($event) { | ||
if ($event.target.files.length > 0) { | ||
fileName.value = $event.target.files[0].name; | ||
isFileSelected.value = true; | ||
} else { | ||
isFileSelected.value = false; | ||
} | ||
} | ||
async function submitFile($event) { | ||
const file = input.value.files[0]; | ||
await abilityStore.savePayload($api, file, true, true); | ||
fileName.value = fileUploadPlaceholder; | ||
isFileSelected.value = false; | ||
modals.value.payloads.showUpload = false; | ||
} | ||
</script> | ||
|
||
<template lang="pug"> | ||
.modal(:class="{ 'is-active': modals.payloads.showUpload }") | ||
.modal-background(@click="modals.payloads.showUpload = false") | ||
.modal-card | ||
header.modal-card-head | ||
p.modal-card-title Upload a payload | ||
.modal-card-body | ||
.file.has-name.is-fullwidth | ||
label.file-label | ||
input.file-input(type="file", ref="input", @change="updateFileName") | ||
span.file-cta | ||
span.file-icon | ||
font-awesome-icon(icon="fas fa-upload") | ||
span.file-label Choose a file... | ||
span.file-name {{ fileName }} | ||
footer.modal-card-foot.is-flex.is-justify-content-flex-end | ||
button.button(@click="modals.payloads.showUpload = false") Close | ||
button.button.is-primary(:disabled="!isFileSelected", @click="submitFile($event)") | ||
span.icon | ||
font-awesome-icon(icon="fas fa-save") | ||
span Upload | ||
</template> | ||
|
||
<style scoped> | ||
.modal-card{ | ||
width: 70%; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { mount } from "@vue/test-utils"; | ||
import { axe, toHaveNoViolations } from "jest-axe"; | ||
import PayloadsView from "../views/PayloadsView.vue"; | ||
|
||
expect.extend(toHaveNoViolations); | ||
const wrapper = mount(PayloadsView); | ||
test("PayloadsView should have no accessibility violations", async () => { | ||
const results = await axe(wrapper.element, { | ||
// Set axe rules: https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md | ||
rules: { | ||
region: { enabled: false }, | ||
}, | ||
}); | ||
expect(results).toHaveNoViolations(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<script setup> | ||
import { inject, onMounted, computed } from "vue"; | ||
import { storeToRefs } from "pinia"; | ||
import { useCoreDisplayStore } from "@/stores/coreDisplayStore"; | ||
import UploadModal from "@/components/payloads/UploadModal.vue"; | ||
import { useAbilityStore } from "@/stores/abilityStore"; | ||
const $api = inject("$api"); | ||
const abilityStore = useAbilityStore(); | ||
const coreDisplayStore = useCoreDisplayStore(); | ||
const { payloads } = storeToRefs(abilityStore); | ||
const { modals } = storeToRefs(coreDisplayStore); | ||
const structuredPayloads = computed(() => { | ||
const regex = /^(?:plugins\/([^/]+)|data)?\/payloads\/(.+)$/; | ||
return payloads.value.map(payload => { | ||
const match = payload.match(regex); | ||
if (!match) { | ||
console.error(`Payload path "${payload}" does not match the expected format.`); | ||
return null; | ||
} | ||
let belongsToAPlugin = match[1] !== undefined; | ||
return { | ||
fullPath: payload, | ||
belongsToAPlugin: match[1] !== undefined, | ||
pluginName: match[1] || null, | ||
fileName: match[2], | ||
}; | ||
}).filter(Boolean); // Remove null values | ||
}); | ||
const pluginStructuredPayloads = computed(() => { | ||
return structuredPayloads.value.filter(payload => payload.belongsToAPlugin); | ||
}); | ||
const nonPluginStructuredPayloads = computed(() => { | ||
return structuredPayloads.value.filter(payload => !payload.belongsToAPlugin); | ||
}); | ||
onMounted(async () => { | ||
await abilityStore.getPayloads($api, true, false, true); | ||
}); | ||
</script> | ||
|
||
<template lang="pug"> | ||
.content | ||
h2 Payloads | ||
p | ||
| Payloads are any files that you can reference in ability executors. | ||
| They are transferred to an agent which can then use them.<br/> | ||
| You can only add or delete local payloads, not plugin ones. | ||
hr | ||
|
||
.content | ||
h2 Local Payloads | ||
.columns.mb-4 | ||
.column.is-one-quarter.is-flex.buttons.mb-0 | ||
button.button(@click="modals.payloads.showUpload = true") | ||
span.icon | ||
font-awesome-icon(icon="fas fa-file-import") | ||
span Upload a payload | ||
.column.is-half.is-flex.is-justify-content-center | ||
span.tag.is-medium.m-0 | ||
span.has-text-success | ||
strong | ||
| {{ nonPluginStructuredPayloads.length }} | ||
| payload{{ nonPluginStructuredPayloads.length === 0 || nonPluginStructuredPayloads.length > 1 ? 's' : '' }} | ||
table.table.is-striped.is-fullwidth.is-narrow | ||
thead | ||
tr | ||
th File name | ||
th File path | ||
th | ||
tbody | ||
tr.pointer(v-for="(payload, index) in nonPluginStructuredPayloads") | ||
td {{ payload.fileName }} | ||
td.is-four-fifths {{ payload.fullPath }} | ||
td.has-text-centered | ||
button.delete.is-white(@click.stop="abilityStore.deletePayload($api, payload.fileName, true)") | ||
|
||
.content | ||
h2 Plugin Payloads | ||
.columns.mb-4 | ||
.column.is-full.is-flex.is-justify-content-center | ||
span.tag.is-medium.m-0 | ||
span.has-text-success | ||
strong | ||
| {{ pluginStructuredPayloads.length }} | ||
| payload{{ pluginStructuredPayloads.length === 0 || pluginStructuredPayloads.length > 1 ? 's' : '' }} | ||
table.table.is-striped.is-fullwidth.is-narrow | ||
thead | ||
tr | ||
th File name | ||
th File path | ||
th Plugin Name | ||
tbody | ||
tr.pointer(v-for="payload in pluginStructuredPayloads") | ||
td {{ payload.fileName }} | ||
td.is-four-fifths {{ payload.fullPath }} | ||
td {{ payload.pluginName }} | ||
UploadModal | ||
</template> | ||
|
||
<style scoped> | ||
tr { | ||
cursor: pointer; | ||
} | ||
td.has-text-centered { | ||
width: 40px; | ||
} | ||
</style> |