mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-15 17:14:05 -08:00
be7aac3279
* feat(editor): extract credentials view into reusable layout components for workflows view * feat(editor): add workflow card and start work on empty state * feat: add hoverable card and finish workflows empty state * fix: undo workflows response interface changes * chore: fix linting issues. * fix: remove enterprise sharing env schema * fix(editor): fix workflows resource view when sharing is enabled * fix: change owner tag design and order * feat: add personalization survey on workflows page * fix: update component snapshots * feat: refactored workflow card to use workflow-activator properly * fix: fix workflow activator and proptypes * fix: hide owner tag for workflow card until sharing is available * fix: fixed ownedBy and sharedWith appearing for workflows list * feat: update tags component design * refactor: change resource filter select to n8n-user-select * fix: made telemetry messages reusable * chore: remove unused import * refactor: fix component name casing * refactor: use Vue.set to make workflow property reactive * feat: add support for clicking on tags for filtering * chore: fix tags linting issues * fix: fix resources list layout when title words are very long * refactor: add active and inactive status text to workflow activator * fix: fix credentials and workflows sorting when name contains leading whitespace * fix: remove wrongfully added style tag * feat: add translations and storybook examples for truncated tags * fix: remove enterprise sharing env from schema * refactor: fix workflows module and workflows field store naming conflict * fix: fix workflow activator wrapping * feat: updated empty workflows list cards design * feat: update workflow activator margins and workflow card * feat: add duplicate workflow functionality and update tags * feat: fix duplicate workflow flow * fix: fix status color for workflow activator with could not be started status * fix: remove createdAt and updatedAt from workflow duplication
179 lines
4.2 KiB
Vue
179 lines
4.2 KiB
Vue
<template>
|
|
<div :class="$style.container" v-show="loading || collections.length">
|
|
<agile ref="slider" :dots="false" :navButtons="false" :infinite="false" :slides-to-show="4" @after-change="updateCarouselScroll">
|
|
<Card v-for="n in (loading ? 4: 0)" :key="`loading-${n}`" :loading="loading" />
|
|
<CollectionCard
|
|
v-for="collection in (loading? []: collections)"
|
|
:key="collection.id"
|
|
:collection="collection"
|
|
@click="(e) => onCardClick(e, collection.id)"
|
|
/>
|
|
</agile>
|
|
<button v-show="carouselScrollPosition > 0" :class="$style.leftButton" @click="scrollLeft">
|
|
<font-awesome-icon icon="chevron-left" />
|
|
</button>
|
|
<button v-show="!scrollEnd" :class="$style.rightButton" @click="scrollRight">
|
|
<font-awesome-icon icon="chevron-right" />
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { PropType } from "vue";
|
|
import { ITemplatesCollection } from "@/Interface";
|
|
import Card from '@/components/CollectionWorkflowCard.vue';
|
|
import CollectionCard from '@/components/CollectionCard.vue';
|
|
import VueAgile from 'vue-agile';
|
|
|
|
import { genericHelpers } from '@/components/mixins/genericHelpers';
|
|
import mixins from 'vue-typed-mixins';
|
|
|
|
export default mixins(genericHelpers).extend({
|
|
name: 'CollectionsCarousel',
|
|
props: {
|
|
collections: {
|
|
type: Array as PropType<ITemplatesCollection[]>,
|
|
},
|
|
loading: {
|
|
type: Boolean,
|
|
},
|
|
},
|
|
watch: {
|
|
collections() {
|
|
setTimeout(() => {
|
|
this.updateCarouselScroll();
|
|
}, 0);
|
|
},
|
|
loading() {
|
|
setTimeout(() => {
|
|
this.updateCarouselScroll();
|
|
}, 0);
|
|
},
|
|
},
|
|
components: {
|
|
Card,
|
|
CollectionCard,
|
|
VueAgile,
|
|
},
|
|
data() {
|
|
return {
|
|
carouselScrollPosition: 0,
|
|
cardWidth: 240,
|
|
scrollEnd: false,
|
|
listElement: null as null | Element,
|
|
};
|
|
},
|
|
methods: {
|
|
updateCarouselScroll() {
|
|
if (this.listElement) {
|
|
this.carouselScrollPosition = Number(this.listElement.scrollLeft.toFixed());
|
|
|
|
const width = this.listElement.clientWidth;
|
|
const scrollWidth = this.listElement.scrollWidth;
|
|
const scrollLeft = this.carouselScrollPosition;
|
|
this.scrollEnd = scrollWidth - width <= scrollLeft + 7;
|
|
}
|
|
},
|
|
onCardClick(event: MouseEvent, id: string) {
|
|
this.$emit('openCollection', {event, id});
|
|
},
|
|
scrollLeft() {
|
|
if (this.listElement) {
|
|
this.listElement.scrollBy({ left: -(this.cardWidth * 2), top: 0, behavior: 'smooth' });
|
|
}
|
|
},
|
|
scrollRight() {
|
|
if (this.listElement) {
|
|
this.listElement.scrollBy({ left: this.cardWidth * 2, top: 0, behavior: 'smooth' });
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
this.$nextTick(() => {
|
|
const slider = this.$refs.slider;
|
|
if (!slider) {
|
|
return;
|
|
}
|
|
// @ts-ignore
|
|
this.listElement = slider.$el.querySelector('.agile__list');
|
|
if (this.listElement) {
|
|
this.listElement.addEventListener('scroll', this.updateCarouselScroll);
|
|
}
|
|
});
|
|
},
|
|
beforeDestroy() {
|
|
if (this.$refs.slider) {
|
|
// @ts-ignore
|
|
this.$refs.slider.destroy();
|
|
}
|
|
window.removeEventListener('scroll', this.updateCarouselScroll);
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" module>
|
|
.container {
|
|
position: relative;
|
|
}
|
|
|
|
.button {
|
|
width: 28px;
|
|
height: 37px;
|
|
position: absolute;
|
|
top: 35%;
|
|
border-radius: var(--border-radius-large);
|
|
border: var(--border-base);
|
|
background-color: #fbfcfe;
|
|
cursor: pointer;
|
|
|
|
&:after {
|
|
content: '';
|
|
width: 40px;
|
|
height: 140px;
|
|
top: -55px;
|
|
position: absolute;
|
|
}
|
|
svg {
|
|
color: var(--color-foreground-xdark);
|
|
}
|
|
}
|
|
|
|
.leftButton {
|
|
composes: button;
|
|
left: -30px;
|
|
|
|
&:after {
|
|
left: 27px;
|
|
background: linear-gradient(270deg,
|
|
hsla(var(--color-background-light-h), var(--color-background-light-s), var(--color-background-light-l), 50%),
|
|
hsla(var(--color-background-light-h), var(--color-background-light-s), var(--color-background-light-l), 100%));
|
|
}
|
|
}
|
|
|
|
.rightButton {
|
|
composes: button;
|
|
right: -30px;
|
|
&:after {
|
|
right: 27px;
|
|
background: linear-gradient(90deg,
|
|
hsla(var(--color-background-light-h), var(--color-background-light-s), var(--color-background-light-l), 50%),
|
|
hsla(var(--color-background-light-h), var(--color-background-light-s), var(--color-background-light-l), 100%));
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
.agile {
|
|
&__list {
|
|
width: 100%;
|
|
padding-bottom: var(--spacing-2xs);
|
|
overflow-x: auto;
|
|
transition: all 1s ease-in-out;
|
|
}
|
|
|
|
&__track {
|
|
width: 50px;
|
|
}
|
|
}
|
|
</style>
|