Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FOUR-11020:HOME - START NEW REQUEST: Create a new component to suppor… #1454

Merged
merged 1 commit into from
Oct 10, 2023
Merged
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
157 changes: 157 additions & 0 deletions src/components/renderer/card.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<template>
<div class="m-3 card-request">
<div v-for="event in emptyStartEvents" :key="event.id" class="card">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<span v-uni-id="event.id.toString()">{{ transformedName }}</span>
<span v-if="process.startEvents.length > 1">
: {{ event.name }}
</span>
<a
href="#"
:aria-expanded="ariaExpanded"
:aria-controls="getComputedId(process)"
@click="showRequestDetails"
>
...
</a>
</div>
<div class="text-right">
<button
v-uni-aria-describedby="event.id.toString()"
:href="getNewRequestLinkHref(process, event)"
class="btn btn-primary btn-sm"
@click.prevent="newRequestLink(process, event)"
>
<i class="fas fa-caret-square-right mr-1"></i> {{ $t("Start") }}
</button>
</div>
</div>
<div
v-if="showdetail"
:id="getComputedId(process)"
:aria-hidden="ariaHidden"
>
<hr />
<p class="card-text text-muted">{{ process.description }}</p>
</div>
</div>
</div>
</div>
</template>

<script>
import { createUniqIdsMixin } from "vue-uniq-ids";

const uniqIdsMixin = createUniqIdsMixin();

export default {
mixins: [uniqIdsMixin],
props: ["name", "description", "filter", "id", "process"],
data() {
return {
disabled: false,
spin: 0,
showtip: true,
showdetail: false
};
},
computed: {
ariaHidden() {
return this.showdetail ? "false" : "true";
},
ariaExpanded() {
return this.showdetail ? "true" : "false";
},
emptyStartEvents() {
return this.process.startEvents.filter(
(event) =>
!event.eventDefinitions || event.eventDefinitions.length === 0
);
},
transformedName() {
return this.process.name.replace(
new RegExp(this.filter, "gi"),
(match) => {
return match;
}
);
},
truncatedDescription() {
if (!this.process.description) {
return `<span class="text-primary"></span>`;
}

let result = "";
const wordArray = this.process.description.split(" ");

// Number of maximum characters we want for our description
const maxLength = 100;
let word = null;

while ((word = wordArray.shift())) {
if (result.length + word.length + 1 <= maxLength) {
result = `${result} ${word}`;
}
}

return result.replace(new RegExp(this.filter, "gi"), (match) => {
return `<span class="text-primary"> ${match} </span>`;
});
}
},
methods: {
newRequestLink(process, event) {
if (this.disabled) return;
this.disabled = true;

// Start a process
this.spin = `${process.id}.${event.id}`;
const startEventId = event.id;

window.ProcessMaker.apiClient
.post(`/process_events/${this.process.id}?event=${startEventId}`)
.then((response) => {
this.spin = 0;
const instance = response.data;
if (this.$cookies.get("isMobile")) {
window.location = `/requests/mobile/${instance.id}?fromRedirect=true`;
} else {
window.location = `/requests/${instance.id}?fromRedirect=true`;
}
})
.catch((err) => {
this.disabled = false;
const { data } = err.response;
if (data.message) {
ProcessMaker.alert(data.message, "danger");
}
});
},
showRequestDetails(id) {
if (this.showdetail === false) {
this.showdetail = true;
} else {
this.showdetail = false;
}
},
getNewRequestLinkHref(process, event) {
const { id } = process;
const startEventId = event.id;
return `/process_events/${id}?event=${startEventId}`;
},
getComputedId(process) {
return `process-${process.id}`;
}
}
};
</script>

<style scoped>
.card-request {
width: 45%;
min-width: 40%;
max-width: 50%;
}
</style>
77 changes: 16 additions & 61 deletions src/components/renderer/form-list-table.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
<template>
<div class="container mt-4">
<div class="card">
<div
class="card-header d-flex justify-content-between align-items-center"
>
<h4>{{ title }}</h4>
<div>
<i class="fas fa-search" />
</div>
<div class="card mt-4 mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h4>{{ title }}</h4>
<div>
<i class="fas fa-search" />
</div>
</div>
<div class="card-body list-table">
<template v-if="listOption === 'My Tasks'">
<FormTasks></FormTasks>
</template>
<template v-if="listOption === 'My Requests'">
<FormRequests></FormRequests>
</template>
<template v-if="listOption === 'Start new Request'">
<!--
TODO Card for New Requests
<FormNewRequest></FormNewRequest>
-->
<FormNewRequest></FormNewRequest>
</template>
</div>
</div>
Expand All @@ -28,75 +23,35 @@
<script>
import FormTasks from "./form-tasks.vue";
import FormRequests from "./form-requests.vue";
import FormNewRequest from "./form-new-request.vue";

export default {
components: { FormTasks, FormRequests },
components: { FormTasks, FormRequests, FormNewRequest },
mixins: [],
props: ["listOption"],
data() {
return {
title: this.$t("List Table"),
data: [],
tableData: [],
fields: [],
actions: [
{
value: "edit",
content: "Open Task",
icon: "fas fa-caret-square-right",
link: true,
href: "/tasks/{{id}}/edit"
},
{
value: "showRequestSummary",
content: "Open Request",
icon: "fas fa-clipboard",
link: true,
href: "/requests/{{process_request.id}}"
}
]
title: this.$t("List Table")
};
},
watch: {
listOption() {
this.title = this.listOption;
// this.populateFields(this.title);
}
},
mounted() {
this.title = this.listOption;
// this.populateFields(this.title);
},
methods: {
callAPI(url) {
try {
ProcessMaker.apiClient.get(url).then((response) => {
this.tableData = response.data;
});
} catch (error) {
console.error("Error fetching data:", error);
}
},
populateFields(option) {
this.fields = [];
if (option === this.$t("My Tasks")) {
this.callAPI("/tasks");
}

if (option === this.$t("My Requests")) {
this.callAPI("/requests");
}

if (option === this.$t("Start new Request")) {
this.callAPI("/start_processes");
}
}
}
methods: {}
};
</script>

<style lang="scss">
.prevent-interaction.form-list-table::after {
content: attr(placeholder);
}
.list-table {
height: 300px;
overflow: auto;
}
</style>
103 changes: 103 additions & 0 deletions src/components/renderer/form-new-request.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<template>
<div>
<div v-if="Object.keys(processes).length && !loading" class="process-list">
<div
v-for="(category, index) in processes"
:key="`category-${index}`"
class="mt-3"
>
<!--
<h5 class="mb-n2">
{{ index }}
<span class="badge badge-pill badge-secondary">
{{ category.length }}
</span>
</h5>
-->
<b-container fluid>
<b-card-group>
<template v-for="(process, id) in category">
<ProcessCard
v-if="hasEmptyStartEvents(process)"
:key="`process-${id}`"
:filter="filter"
:process="process"
/>
</template>
</b-card-group>
</b-container>
</div>
</div>
</div>
</template>

<script>
import ProcessCard from "./card.vue";

export default {
components: { ProcessCard },
data() {
return {
filter: "",
loading: false,
error: false,
loaded: false,
processes: {},
perPage: 10,
page: 1
};
},
mounted() {
this.fetch();
},
methods: {
hasEmptyStartEvents(process) {
return !!process.events.find(
(event) =>
!event.eventDefinitions || event.eventDefinitions.length === 0
);
},
fetch() {
// Now call our api
window.ProcessMaker.apiClient
.get(
`start_processes?page=${this.page}&per_page=${this.perPage}&filter=${this.filter}&order_by=category.name,name` +
"&order_direction=asc,asc" +
"&include=events,categories" +
"&without_event_definitions=true"
)
.then((response) => {
const { data } = response;
// Empty processes
this.processes = {};
// Now populate our processes array with data for rendering
this.populate(data.data);
// Do initial filter
// Set data in paginate
data.meta.from -= 1;
this.$refs.listProcess.data = data;
this.$refs.listProcess.setPaginationData(data.meta);
})
.catch(() => {
this.error = true;
});
},
populate(data) {
// Each element in data represents an individual process
// We need to pull out the category name, and if it's available in our processes, append it there
// if not, create the category in our processes array and then append it
for (const process of data) {
for (const category of process.categories) {
// Now determine if we have it defined in our processes list
if (typeof this.processes[category.name] === "undefined") {
// Create it
this.processes[category.name] = [];
}
// Now append
this.processes[category.name].push(process);
}
}
}
}
};
</script>
Loading