stash
This commit is contained in:
parent
cfcc2c15d3
commit
4f2fe011c0
28 changed files with 3499 additions and 2922 deletions
102
frontend/src/views/InventoryDetailForeign.vue
Normal file
102
frontend/src/views/InventoryDetailForeign.vue
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<BaseLayout>
|
||||
<main class="content">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ item.name }}</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Description</label>
|
||||
Foreighn {{ item.description }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="tags" class="form-label">Tags</label>
|
||||
<span class="badge bg-dark" v-for="(tag, index) in item.tags" :key="index">
|
||||
{{ getNameFromHandle(tag) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="property" class="form-label">Properties</label>
|
||||
<span class="badge bg-dark" v-for="(property, index) in item.properties" :key="index">
|
||||
{{ property.name }}={{ property.value }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="quantity" class="form-label">Quantity</label>
|
||||
{{ item.owned_quantity }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="image" class="form-label">Image</label>
|
||||
<div>
|
||||
<authenticated-image v-for="file in item.files" :key="file.id" :src="file.name"
|
||||
:owner="file.owner" class="img-thumbnail border-info"></authenticated-image>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<button class="btn btn-primary" @click="$router.push('/inventory/' + id + '/edit')">
|
||||
<b-icon-pencil-square></b-icon-pencil-square>
|
||||
Edit
|
||||
</button>
|
||||
<button type="submit" class="btn btn-danger"
|
||||
@click="deleteInventoryItem(item).then(() => $router.push('/inventory'))">
|
||||
<b-icon-trash></b-icon-trash>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</BaseLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as BIcons from "bootstrap-icons-vue";
|
||||
import BaseLayout from "@/components/BaseLayout.vue";
|
||||
import {mapActions, mapGetters, mapState} from "vuex";
|
||||
import AuthenticatedImage from "@/components/AuthenticatedImage.vue";
|
||||
|
||||
export default {
|
||||
name: "InventoryDetail",
|
||||
components: {
|
||||
AuthenticatedImage,
|
||||
BaseLayout,
|
||||
...BIcons
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["loaded_items", "getNameFromHandle"]),
|
||||
...mapState(["storage_locations"]),
|
||||
item() {
|
||||
return this.loaded_items.find(item => item.id === parseInt(this.id)) || {}
|
||||
},
|
||||
location() {
|
||||
return this.storage_locations.find(loc => loc.id === this.item.storage_location) || null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(["fetchInventoryItems", "deleteInventoryItem", "fetchFilesByItem", "fetchStorageLocations"]),
|
||||
},
|
||||
async mounted() {
|
||||
await this.fetchInventoryItems()
|
||||
await this.fetchStorageLocations()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
img {
|
||||
width: 190px;
|
||||
height: 107px;
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -27,20 +27,13 @@
|
|||
<tbody>
|
||||
<tr v-for="item in search_results" :key="item.id">
|
||||
<td>
|
||||
<router-link :to="`/inventory/${item.id}`">{{ item.name }}</router-link>
|
||||
<router-link :to="`/inventory/${item.handle}`">{{ item.name }}</router-link>
|
||||
</td>
|
||||
<td>
|
||||
<user-name-tag :user="item"/>
|
||||
</td>
|
||||
<td class="d-none d-md-table-cell">{{ item.owned_quantity }}</td>
|
||||
<td class="table-action">
|
||||
<!--<router-link :to="`/inventory/${item.id}/edit`">
|
||||
<b-icon-pencil-square></b-icon-pencil-square>
|
||||
</router-link>
|
||||
<a :href="`/inventory/${item.id}/delete`"
|
||||
@click.prevent="deleteInventoryItem(item)">
|
||||
<b-icon-trash></b-icon-trash>
|
||||
</a>-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -56,7 +49,7 @@
|
|||
class="card-img-top img-preview"/>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-0">
|
||||
<router-link :to="`/inventory/${item.id}`">
|
||||
<router-link :to="`/inventory/${item.handle}`">
|
||||
{{ item.name }}
|
||||
</router-link></h5>
|
||||
<div class="card-text text-black-50">
|
||||
|
|
@ -78,7 +71,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {mapActions} from 'vuex';
|
||||
import {mapActions, mapState} from 'vuex';
|
||||
import * as BIcons from "bootstrap-icons-vue";
|
||||
import BaseLayout from "@/components/BaseLayout.vue";
|
||||
import SearchBox from "@/components/SearchBox.vue";
|
||||
|
|
@ -114,10 +107,13 @@ export default {
|
|||
},
|
||||
loadResults() {
|
||||
this.fetchSearchResults({query: this.query}).then((results) => {
|
||||
this.search_results = results;
|
||||
this.search_results = results.map(e=>({...e, handle: e.owner==this.user?e.id:"shared/"+e.owner+"/"+e.id}));
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
watch: {
|
||||
query: {
|
||||
immediate: false,
|
||||
|
|
|
|||
|
|
@ -142,14 +142,15 @@
|
|||
<div class="card-body">
|
||||
<!-- Step-specific content based on workflow type and current step -->
|
||||
<component
|
||||
v-if="stepComponent"
|
||||
:is="stepComponent"
|
||||
v-if="workflowComponent"
|
||||
:is="workflowComponent"
|
||||
:workflow-instance="workflowInstance"
|
||||
:step="currentStep"
|
||||
:payload="workflowInstance.payload"
|
||||
@update="handleStepUpdate"
|
||||
@next="handleNextStep"
|
||||
@prev="handlePrevStep"
|
||||
@complete="completeWorkflow"
|
||||
/>
|
||||
|
||||
<!-- Default step content if no specific component -->
|
||||
|
|
@ -201,8 +202,7 @@
|
|||
import * as BIcons from "bootstrap-icons-vue";
|
||||
import BaseLayout from "@/components/BaseLayout.vue";
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { workflowRegistry } from '@/workflows.js';
|
||||
import { getStepComponent, hasStepComponent } from '@/components/workflow/ComponentRegistry.js';
|
||||
import { getWorkflow, getWorkflowComponent } from '@/workflows.js';
|
||||
|
||||
export default {
|
||||
name: 'WorkflowDetail',
|
||||
|
|
@ -238,11 +238,11 @@ export default {
|
|||
workflowDefinition() {
|
||||
// `name` doubles as the workflow type identifier (e.g. 'import-items').
|
||||
if (!this.workflowInstance?.name) return null;
|
||||
return workflowRegistry.get(this.workflowInstance.name);
|
||||
return getWorkflow(this.workflowInstance.name);
|
||||
},
|
||||
|
||||
stepDefinitions() {
|
||||
return this.workflowDefinition?.getStepDefinitions() || [];
|
||||
return this.workflowDefinition?.stepDefinitions || [];
|
||||
},
|
||||
|
||||
totalSteps() {
|
||||
|
|
@ -257,13 +257,12 @@ export default {
|
|||
return this.workflowInstance?.state === 'running';
|
||||
},
|
||||
|
||||
stepComponent() {
|
||||
// Return step-specific component if it exists using the component registry
|
||||
workflowComponent() {
|
||||
// Return the single component implementing the whole workflow, if any,
|
||||
// using the workflow component registry. The component itself decides
|
||||
// what to render based on the `step` prop it receives.
|
||||
const workflowType = this.workflowInstance?.name;
|
||||
if (workflowType && this.currentStep) {
|
||||
return getStepComponent(workflowType, this.currentStep);
|
||||
}
|
||||
return null;
|
||||
return workflowType ? getWorkflowComponent(workflowType) : null;
|
||||
},
|
||||
|
||||
currentStepIndex() {
|
||||
|
|
@ -282,8 +281,8 @@ export default {
|
|||
},
|
||||
|
||||
hasCustomComponent() {
|
||||
// Check if the current step has a custom component defined
|
||||
return this.stepComponent !== null;
|
||||
// Check if the current workflow has a custom component defined
|
||||
return this.workflowComponent !== null;
|
||||
},
|
||||
|
||||
componentStatusClass() {
|
||||
|
|
@ -463,12 +462,6 @@ export default {
|
|||
formatDateTime(dateString) {
|
||||
if (!dateString) return 'N/A';
|
||||
return new Date(dateString).toLocaleString();
|
||||
},
|
||||
|
||||
hasStepComponent(stepNumber) {
|
||||
// Check if a specific step has a custom component available
|
||||
const workflowType = this.workflowInstance?.name;
|
||||
return workflowType ? hasStepComponent(workflowType, stepNumber) : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@
|
|||
import * as BIcons from "bootstrap-icons-vue";
|
||||
import BaseLayout from "@/components/BaseLayout.vue";
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { workflowRegistry } from '@/workflows.js';
|
||||
import { getAllWorkflows, getWorkflow, buildWorkflowApiPayload } from '@/workflows.js';
|
||||
|
||||
export default {
|
||||
name: 'Workflows',
|
||||
|
|
@ -148,7 +148,7 @@ export default {
|
|||
return this.active_workflows;
|
||||
},
|
||||
availableWorkflows() {
|
||||
return workflowRegistry.getAll();
|
||||
return getAllWorkflows();
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
|
@ -221,22 +221,22 @@ export default {
|
|||
},
|
||||
getWorkflowDisplayName(workflow) {
|
||||
// `name` doubles as the workflow type identifier (e.g. 'import-items').
|
||||
return workflowRegistry.get(workflow.name)?.name || workflow.name;
|
||||
return getWorkflow(workflow.name)?.name || workflow.name;
|
||||
},
|
||||
async startWorkflow(workflow) {
|
||||
try {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
|
||||
// Use the workflow's toApiFormat method to get properly formatted data
|
||||
const workflowData = workflow.toApiFormat();
|
||||
// Build the properly formatted data to start this workflow
|
||||
const workflowData = buildWorkflowApiPayload(workflow);
|
||||
|
||||
const newWorkflow = await this.createWorkflow(workflowData);
|
||||
console.log('Workflow started successfully:', newWorkflow);
|
||||
|
||||
// Immediately navigate to the workflow detail view
|
||||
// Get the first step from the workflow definition
|
||||
const firstStep = workflow.getStepDefinitions()?.[0]?.step || "initial";
|
||||
const firstStep = workflow.stepDefinitions?.[0]?.step || "initial";
|
||||
this.$router.push({
|
||||
name: 'workflow-detail',
|
||||
params: {
|
||||
|
|
@ -258,7 +258,7 @@ export default {
|
|||
// Use the workflow's current step if available, otherwise use the first step
|
||||
const currentStep = workflow.current_step ||
|
||||
workflow.payload?.current_step ||
|
||||
workflow.getStepDefinitions?.()?.[0]?.step ||
|
||||
getWorkflow(workflow.name)?.stepDefinitions?.[0]?.step ||
|
||||
"initial";
|
||||
|
||||
this.$router.push({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue