feat: complete basic front end
This commit is contained in:
@@ -72,7 +72,7 @@
|
||||
>
|
||||
<SLA-card-label v-if="hasSlaPolicyId" :chat="chat" show-extended-info />
|
||||
<linear
|
||||
v-if="isLinearIntegrationEnabled"
|
||||
v-if="isLinearIntegrationEnabled && isLinearFeatureEnabled"
|
||||
:conversation-id="currentChat.id"
|
||||
/>
|
||||
<more-actions :conversation-id="currentChat.id" />
|
||||
@@ -130,6 +130,7 @@ export default {
|
||||
currentChat: 'getSelectedChat',
|
||||
accountId: 'getCurrentAccountId',
|
||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||
appIntegrations: 'integrations/getAppIntegrations',
|
||||
}),
|
||||
chatMetadata() {
|
||||
return this.chat.meta;
|
||||
@@ -188,6 +189,11 @@ export default {
|
||||
return this.chat?.sla_policy_id;
|
||||
},
|
||||
isLinearIntegrationEnabled() {
|
||||
return this.appIntegrations.find(
|
||||
integration => integration.id === 'linear' && !!integration.hooks.length
|
||||
);
|
||||
},
|
||||
isLinearFeatureEnabled() {
|
||||
return this.isFeatureEnabledonAccount(
|
||||
this.accountId,
|
||||
FEATURE_FLAGS.LINEAR
|
||||
|
||||
@@ -1,144 +1,145 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between group">
|
||||
<a
|
||||
:href="issue.url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-block rounded-sm mb-0 break-all py-0.5 text-primary-600"
|
||||
>
|
||||
{{ `${issue.identifier} ${issue.title}` }}
|
||||
</a>
|
||||
<woot-button
|
||||
size="small"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
class="!px-2 hover:!bg-transparent hidden dark:hover:!bg-transparent underline group-hover:block"
|
||||
@click="unlinkIssue"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.UNLINK.TITLE') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
|
||||
<!-- <span class="text-sm font-normal text-slate-900 dark:text-slate-25">
|
||||
{{ issue.description }}
|
||||
</span> -->
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between w-full">
|
||||
<span
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.ISSUE.STATUS') }}
|
||||
</span>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<span
|
||||
class="text-sm font-normal text-left text-slate-900 dark:text-slate-25 tabular-nums"
|
||||
>
|
||||
{{ issue.state.name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between w-full">
|
||||
<span
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.ISSUE.PRIORITY') }}
|
||||
</span>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<span
|
||||
class="text-sm font-normal text-left text-slate-900 dark:text-slate-25 tabular-nums"
|
||||
>
|
||||
{{ priorityLabel }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between w-full">
|
||||
<span
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.ISSUE.ASSIGNEE') }}
|
||||
</span>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<span
|
||||
class="text-sm font-normal text-left text-slate-900 dark:text-slate-25 tabular-nums"
|
||||
>
|
||||
{{ assigneeName }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between w-full">
|
||||
<span
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.ISSUE.LABELS') }}
|
||||
</span>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<span
|
||||
class="text-sm font-normal text-left text-slate-900 dark:text-slate-25 tabular-nums"
|
||||
>
|
||||
{{ labels }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between w-full">
|
||||
<span
|
||||
class="text-sm sticky top-0 h-fit font-normal tracking-[-0.6%] min-w-[140px] truncate text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.ISSUE.CREATED_AT') }}
|
||||
</span>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<span
|
||||
class="text-sm font-normal text-left text-slate-900 dark:text-slate-25 tabular-nums"
|
||||
>
|
||||
{{ formatDate(issue.createdAt) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { format } from 'date-fns';
|
||||
import UserAvatarWithName from 'dashboard/components/widgets/UserAvatarWithName.vue';
|
||||
import { computed } from 'vue';
|
||||
const priorityMap = {
|
||||
0: 'Low',
|
||||
1: 'Medium',
|
||||
2: 'High',
|
||||
3: 'Urgent',
|
||||
};
|
||||
export default {
|
||||
props: {
|
||||
issue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
linkId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
const props = defineProps({
|
||||
issue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
priorityLabel() {
|
||||
return priorityMap[this.issue.priority];
|
||||
},
|
||||
assigneeName() {
|
||||
return this.issue.assignee ? this.issue.assignee.name : '---';
|
||||
},
|
||||
labels() {
|
||||
return this.issue.labels.nodes.length
|
||||
? this.issue.labels.nodes.map(label => label.name).join(', ')
|
||||
: '---';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
unlinkIssue() {
|
||||
this.$emit('unlink-issue', this.linkId);
|
||||
},
|
||||
formatDate(timestamp) {
|
||||
return format(new Date(timestamp), 'MMM dd, hh:mm a');
|
||||
},
|
||||
linkId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(['unlink-issue']);
|
||||
const formattedDate = computed(() => {
|
||||
return format(new Date(props.issue.createdAt), 'hh:mm a, MMM dd');
|
||||
});
|
||||
|
||||
const assignee = computed(() => {
|
||||
if (!props.issue.assignee) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
name: props.issue.assignee.name,
|
||||
thumbnail: props.issue.assignee.avatarUrl,
|
||||
};
|
||||
});
|
||||
|
||||
const labels = computed(() => {
|
||||
if (props.issue.labels.nodes.length) {
|
||||
return props.issue.labels.nodes;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
const priorityLabel = computed(() => {
|
||||
return priorityMap[props.issue.priority];
|
||||
});
|
||||
const unlinkIssue = () => {
|
||||
emit('unlink-issue', props.linkId);
|
||||
};
|
||||
|
||||
const openIssue = () => {
|
||||
window.open(props.issue.url, '_blank');
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="absolute flex flex-col items-start bg-[#fdfdfd] dark:bg-slate-800 z-50 px-4 py-3 border border-solid border-slate-75 dark:border-slate-700 w-[384px] rounded-xl gap-4 max-h-96 overflow-auto"
|
||||
>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row justify-between w-full">
|
||||
<div
|
||||
class="flex items-center justify-center gap-1 px-2 py-1 border rounded-lg border-ash-200"
|
||||
>
|
||||
<fluent-icon
|
||||
icon="linear"
|
||||
size="19"
|
||||
class="text-[#5E6AD2]"
|
||||
view-box="0 0 19 19"
|
||||
/>
|
||||
<span class="text-xs font-medium text-ash-900">
|
||||
{{ issue.identifier }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
@click="unlinkIssue"
|
||||
>
|
||||
<fluent-icon
|
||||
icon="unlink"
|
||||
size="14"
|
||||
type="outline"
|
||||
icon-lib="lucide"
|
||||
/>
|
||||
</woot-button>
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
@click="openIssue"
|
||||
>
|
||||
<fluent-icon icon="arrow-up-right" size="14" />
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="mt-2 text-sm font-medium text-ash-900">
|
||||
{{ issue.title }}
|
||||
</span>
|
||||
<span class="mt-1 text-sm text-ash-800">
|
||||
{{
|
||||
issue.description.length > 130
|
||||
? issue.description.slice(0, 130) + '...'
|
||||
: issue.description
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-row gap-2 divide-x divide-ash-200">
|
||||
<user-avatar-with-name v-if="assignee" :user="assignee" />
|
||||
<div class="flex items-center gap-1">
|
||||
<fluent-icon
|
||||
icon="status"
|
||||
size="14"
|
||||
:class="`text-[${issue.state.color}]`"
|
||||
/>
|
||||
<h6 class="text-xs text-slate-600">
|
||||
{{ issue.state.name }}
|
||||
</h6>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<fluent-icon
|
||||
:icon="`priority-${priorityLabel.toLowerCase()}`"
|
||||
size="14"
|
||||
view-box="0 0 14 14"
|
||||
/>
|
||||
<h6 class="text-xs text-slate-600">{{ priorityLabel }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="labels.length" class="flex flex-wrap items-center gap-1">
|
||||
<woot-label
|
||||
v-for="label in labels"
|
||||
:key="label.id"
|
||||
:title="label.name"
|
||||
:description="label.description"
|
||||
:color="label.color"
|
||||
variant="smooth"
|
||||
small
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<span class="text-xs text-ash-800">
|
||||
{{ `Created at ${formattedDate}` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<div class="relative" @mouseover="openSlaPopover()">
|
||||
<div class="relative" @mouseover="linkedIssue ? openIssue() : null">
|
||||
<woot-button
|
||||
v-on-clickaway="closeSlaPopover"
|
||||
v-tooltip="tooltipText"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
@click="openSlaPopover()"
|
||||
@click="openIssue()"
|
||||
>
|
||||
<fluent-icon
|
||||
icon="linear"
|
||||
@@ -12,11 +13,16 @@
|
||||
class="text-[#5E6AD2]"
|
||||
view-box="0 0 19 19"
|
||||
/>
|
||||
<span v-if="linkedIssue" class="text-xs font-medium text-ash-800">
|
||||
{{ linkedIssue.issue.identifier }}
|
||||
</span>
|
||||
</woot-button>
|
||||
<linear-issue-details
|
||||
v-if="showSlaPopoverCard"
|
||||
<issue-item
|
||||
v-if="shouldShowIssue"
|
||||
:issue="linkedIssue.issue"
|
||||
:link-id="linkedIssue.id"
|
||||
class="absolute right-0 top-[46px]"
|
||||
@unlink-issue="unlinkIssue"
|
||||
/>
|
||||
<woot-modal
|
||||
:show.sync="showPopup"
|
||||
@@ -34,15 +40,16 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import LinearIssueDetails from './LinearIssueDetails.vue';
|
||||
import IssueItem from './IssueItem.vue';
|
||||
import LinearAPI from 'dashboard/api/integrations/linear';
|
||||
import CreateOrLinkIssue from './CreateOrLinkIssue.vue';
|
||||
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
export default {
|
||||
components: {
|
||||
LinearIssueDetails,
|
||||
IssueItem,
|
||||
CreateOrLinkIssue,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
conversationId: {
|
||||
type: [Number, String],
|
||||
@@ -52,7 +59,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
linkedIssue: null,
|
||||
showSlaPopover: false,
|
||||
showIssue: false,
|
||||
showPopup: false,
|
||||
};
|
||||
},
|
||||
@@ -60,8 +67,13 @@ export default {
|
||||
...mapGetters({
|
||||
currentAccountId: 'getCurrentAccountId',
|
||||
}),
|
||||
showSlaPopoverCard() {
|
||||
return this.showSlaPopover && this.linkedIssue;
|
||||
shouldShowIssue() {
|
||||
return this.showIssue && this.linkedIssue;
|
||||
},
|
||||
tooltipText() {
|
||||
return this.linkedIssue === null
|
||||
? this.$t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK_BUTTON')
|
||||
: null;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
@@ -99,12 +111,12 @@ export default {
|
||||
);
|
||||
}
|
||||
},
|
||||
openSlaPopover() {
|
||||
openIssue() {
|
||||
if (!this.linkedIssue) this.showPopup = true;
|
||||
this.showSlaPopover = true;
|
||||
this.showIssue = true;
|
||||
},
|
||||
closeSlaPopover() {
|
||||
this.showSlaPopover = false;
|
||||
this.showIssue = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
},
|
||||
"ADD_OR_LINK": {
|
||||
"TITLE": "Create/link linear issue",
|
||||
"DESCRIPTION": "Create or link a linear issue to the conversation",
|
||||
"DESCRIPTION": "Create Linear issues from conversations, or link existing ones for seamless tracking.",
|
||||
"FORM": {
|
||||
"TITLE": {
|
||||
"LABEL": "Title",
|
||||
|
||||
@@ -277,5 +277,6 @@
|
||||
"avatar-upload-outline": "M19.754 11a.75.75 0 0 1 .743.648l.007.102v7a3.25 3.25 0 0 1-3.065 3.246l-.185.005h-11a3.25 3.25 0 0 1-3.244-3.066l-.006-.184V11.75a.75.75 0 0 1 1.494-.102l.006.102v7a1.75 1.75 0 0 0 1.607 1.745l.143.006h11A1.75 1.75 0 0 0 19 18.894l.005-.143V11.75a.75.75 0 0 1 .75-.75ZM6.22 7.216l4.996-4.996a.75.75 0 0 1 .976-.073l.084.072l5.005 4.997a.75.75 0 0 1-.976 1.134l-.084-.073l-3.723-3.716l.001 11.694a.75.75 0 0 1-.648.743l-.102.007a.75.75 0 0 1-.743-.648L11 16.255V4.558L7.28 8.277a.75.75 0 0 1-.976.073l-.084-.073a.75.75 0 0 1-.073-.977l.073-.084l4.996-4.996L6.22 7.216Z",
|
||||
"text-copy-outline": "M5.503 4.627L5.5 6.75v10.504a3.25 3.25 0 0 0 3.25 3.25h8.616a2.25 2.25 0 0 1-2.122 1.5H8.75A4.75 4.75 0 0 1 4 17.254V6.75c0-.98.627-1.815 1.503-2.123M17.75 2A2.25 2.25 0 0 1 20 4.25v13a2.25 2.25 0 0 1-2.25 2.25h-9a2.25 2.25 0 0 1-2.25-2.25v-13A2.25 2.25 0 0 1 8.75 2zm0 1.5h-9a.75.75 0 0 0-.75.75v13c0 .414.336.75.75.75h9a.75.75 0 0 0 .75-.75v-13a.75.75 0 0 0-.75-.75",
|
||||
"linear-outline": "M1.17156 10.4618C1.14041 10.329 1.2986 10.2454 1.39505 10.3418L6.50679 15.4536C6.60323 15.55 6.5196 15.7082 6.38681 15.6771C3.80721 15.0719 1.77669 13.0414 1.17156 10.4618ZM1.00026 8.4131C0.997795 8.45277 1.01271 8.49149 1.0408 8.51959L8.32904 15.8078C8.35714 15.8359 8.39586 15.8509 8.43553 15.8484C8.76721 15.8277 9.09266 15.784 9.41026 15.7187C9.51729 15.6968 9.55447 15.5653 9.47721 15.488L1.36063 7.37142C1.28337 7.29416 1.15187 7.33134 1.12989 7.43837C1.06466 7.75597 1.02092 8.08142 1.00026 8.4131ZM1.58953 6.00739C1.56622 6.05972 1.57809 6.12087 1.6186 6.16139L10.6872 15.23C10.7278 15.2705 10.7889 15.2824 10.8412 15.2591C11.0913 15.1477 11.3336 15.0221 11.5672 14.8833C11.6445 14.8374 11.6564 14.7312 11.5929 14.6676L2.18099 5.25577C2.11742 5.1922 2.01121 5.20412 1.96529 5.28142C1.8265 5.51499 1.70091 5.75733 1.58953 6.00739ZM2.77222 4.37899C2.7204 4.32718 2.7172 4.24407 2.76602 4.18942C4.04913 2.75294 5.9156 1.84863 7.99327 1.84863C11.863 1.84863 15 4.98565 15 8.85536C15 10.933 14.0957 12.7995 12.6592 14.0826C12.6046 14.1314 12.5215 14.1282 12.4696 14.0764L2.77222 4.37899Z",
|
||||
"status-outline":"m8.462 6.81l3.284 13.616c.178.737 1.211.775 1.443.054l3.257-10.122l.586 2.095a.75.75 0 0 0 .722.548h3.494a.75.75 0 0 0 0-1.5h-2.925l-1.105-3.95c-.2-.717-1.208-.736-1.436-.028l-3.203 9.957L9.224 3.574c-.182-.757-1.255-.769-1.454-.016l-2.1 7.943H2.75a.75.75 0 0 0 0 1.5h3.496a.75.75 0 0 0 .725-.558z"
|
||||
"status-outline": "m8.462 6.81l3.284 13.616c.178.737 1.211.775 1.443.054l3.257-10.122l.586 2.095a.75.75 0 0 0 .722.548h3.494a.75.75 0 0 0 0-1.5h-2.925l-1.105-3.95c-.2-.717-1.208-.736-1.436-.028l-3.203 9.957L9.224 3.574c-.182-.757-1.255-.769-1.454-.016l-2.1 7.943H2.75a.75.75 0 0 0 0 1.5h3.496a.75.75 0 0 0 .725-.558z",
|
||||
"unlink-outline": "m18.84 12.25l1.72-1.71h-.02a5.004 5.004 0 0 0-.12-7.07a5.006 5.006 0 0 0-6.95 0l-1.72 1.71m-6.58 6.57l-1.71 1.71a5.004 5.004 0 0 0 .12 7.07a5.006 5.006 0 0 0 6.95 0l1.71-1.71M8 2v3M2 8h3m11 11v3m3-6h3"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user