Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 553d3c3d7c | |||
| 82b9c3a545 | |||
| 04faa51c45 | |||
| 4fdf61bf1e | |||
| d870fdcb30 | |||
| 0f7c902711 | |||
| 9ab8f311c8 | |||
| c52caa0838 | |||
| 889ec0e3be | |||
| 80a6d5501b | |||
| 92f6d61c5d | |||
| 244e4236a5 |
@@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<IssuesSelectedItem :issue="selectedIssue" />
|
<IssuesSelectedItem :issue="selectedIssue" :model-card="modelCard" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!selectedIssue" class="flex flex-col space-y-2">
|
<div v-if="!selectedIssue" class="flex flex-col space-y-2">
|
||||||
|
|||||||
@@ -6,9 +6,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<IssuesBasicTiptap
|
<IssuesBasicTiptap
|
||||||
v-if="issue.description?.doc"
|
v-if="issue.description?.doc"
|
||||||
class="border rounded-xl border-outline-3"
|
class="border rounded-xl border-outline-3 w-full"
|
||||||
:doc="issue.description?.doc"
|
:doc="issue.description?.doc"
|
||||||
></IssuesBasicTiptap>
|
></IssuesBasicTiptap>
|
||||||
|
|
||||||
|
<div v-if="app.$parametersBinding && hasObjectDeltas" class="w-full pt-1 pb-1">
|
||||||
|
<FormButton
|
||||||
|
class="w-full justify-center"
|
||||||
|
:disabled="isApplying || isResolved"
|
||||||
|
@click="applyChanges"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
isApplying ? 'Applying...' : isResolved ? 'Issue resolved' : 'Apply changes'
|
||||||
|
}}
|
||||||
|
</FormButton>
|
||||||
|
</div>
|
||||||
<div class="flex flex-wrap items-center gap-x-3 gap-y-1">
|
<div class="flex flex-wrap items-center gap-x-3 gap-y-1">
|
||||||
<IssuesStatusIcon :status="issue.status" show-label />
|
<IssuesStatusIcon :status="issue.status" show-label />
|
||||||
<IssuesPriorityIcon :priority="issue.priority" show-label />
|
<IssuesPriorityIcon :priority="issue.priority" show-label />
|
||||||
@@ -84,14 +96,85 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useQuery } from '@vue/apollo-composable'
|
||||||
|
import { ResourceMetaType, IssueStatus } from '~/lib/common/generated/gql/graphql'
|
||||||
|
import { issueResourceMetaSearchQuery } from '~/lib/issues/graphql/queries'
|
||||||
import type { IssuesItemFragment } from '~/lib/common/generated/gql/graphql'
|
import type { IssuesItemFragment } from '~/lib/common/generated/gql/graphql'
|
||||||
|
import type { IModelCard } from '~/lib/models/card'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { Calendar } from 'lucide-vue-next'
|
import { Calendar } from 'lucide-vue-next'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
issue: IssuesItemFragment
|
issue: IssuesItemFragment
|
||||||
|
modelCard: IModelCard
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const app = useNuxtApp()
|
||||||
|
const isApplying = ref(false)
|
||||||
|
|
||||||
|
const isResolved = computed(() => {
|
||||||
|
return props.issue.status === IssueStatus.Resolved
|
||||||
|
})
|
||||||
|
|
||||||
|
const queryVariables = computed(() => ({
|
||||||
|
workspaceId: props.modelCard.workspaceId!,
|
||||||
|
projectId: props.modelCard.projectId,
|
||||||
|
resourceType: ResourceMetaType.Issue,
|
||||||
|
resourceId: props.issue.id,
|
||||||
|
metaType: 'objectDeltas'
|
||||||
|
}))
|
||||||
|
|
||||||
|
const queryOptions = computed(() => ({
|
||||||
|
fetchPolicy: 'cache-and-network' as const,
|
||||||
|
enabled: !!props.modelCard.workspaceId,
|
||||||
|
clientId: props.modelCard.accountId
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { result: resourceMetaResult } = useQuery(
|
||||||
|
issueResourceMetaSearchQuery,
|
||||||
|
queryVariables,
|
||||||
|
queryOptions
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasObjectDeltas = computed<boolean>(() => {
|
||||||
|
const metadata = resourceMetaResult.value?.resourceMetaSearch
|
||||||
|
return Array.isArray(metadata) && metadata.length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const objectDeltasPayload = computed<unknown>(() => {
|
||||||
|
if (!hasObjectDeltas.value) return null
|
||||||
|
const metadata = resourceMetaResult.value?.resourceMetaSearch
|
||||||
|
|
||||||
|
if (Array.isArray(metadata) && metadata.length > 0) {
|
||||||
|
return metadata[0]?.data as unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
const applyChanges = async () => {
|
||||||
|
if (!objectDeltasPayload.value) return
|
||||||
|
|
||||||
|
isApplying.value = true
|
||||||
|
try {
|
||||||
|
const payload =
|
||||||
|
typeof objectDeltasPayload.value === 'string'
|
||||||
|
? objectDeltasPayload.value
|
||||||
|
: JSON.stringify(objectDeltasPayload.value)
|
||||||
|
|
||||||
|
if (app.$parametersBinding) {
|
||||||
|
await app.$parametersBinding.update(payload)
|
||||||
|
} else {
|
||||||
|
console.warn('IParametersBinding not available in this host app')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to apply changes:', error)
|
||||||
|
} finally {
|
||||||
|
isApplying.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const formattedDate = computed((): string | null => {
|
const formattedDate = computed((): string | null => {
|
||||||
try {
|
try {
|
||||||
const date = props.issue.dueDate ? dayjs(props.issue.dueDate).toDate() : null
|
const date = props.issue.dueDate ? dayjs(props.issue.dueDate).toDate() : null
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export interface IBasicConnectorBinding
|
|||||||
highlightObjects: (objectIds: string[]) => Promise<void>
|
highlightObjects: (objectIds: string[]) => Promise<void>
|
||||||
removeModel: (model: IModelCard) => Promise<void>
|
removeModel: (model: IModelCard) => Promise<void>
|
||||||
removeModels: (models: IModelCard[]) => Promise<void>
|
removeModels: (models: IModelCard[]) => Promise<void>
|
||||||
|
updateParameters: (payload: string) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBasicConnectorBindingHostEvents
|
export interface IBasicConnectorBindingHostEvents
|
||||||
@@ -107,6 +108,10 @@ export class MockedBaseBinding implements IBasicConnectorBinding {
|
|||||||
await console.log('no way dude')
|
await console.log('no way dude')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async updateParameters(payload: string) {
|
||||||
|
await console.log('Mock: updateParameters called with payload:', payload)
|
||||||
|
}
|
||||||
|
|
||||||
public async showDevTools() {
|
public async showDevTools() {
|
||||||
await console.log('No way dude')
|
await console.log('No way dude')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export interface IParametersBinding {
|
||||||
|
update: (payload: string) => Promise<void>
|
||||||
|
}
|
||||||
@@ -64,6 +64,7 @@ type Documents = {
|
|||||||
"\n subscription ProjectModelIngestionUpdated(\n $input: ProjectModelIngestionSubscriptionInput!\n ) {\n projectModelIngestionUpdated(input: $input) {\n type\n modelIngestion {\n id\n statusData {\n __typename\n ... on ModelIngestionSuccessStatus {\n status\n versionId\n }\n ... on ModelIngestionProcessingStatus {\n status\n progressMessage\n progress\n }\n ... on ModelIngestionFailedStatus {\n status\n errorReason\n }\n ... on ModelIngestionCancelledStatus {\n status\n cancellationMessage\n }\n ... on ModelIngestionQueuedStatus {\n status\n progressMessage\n }\n }\n }\n }\n }\n": typeof types.ProjectModelIngestionUpdatedDocument,
|
"\n subscription ProjectModelIngestionUpdated(\n $input: ProjectModelIngestionSubscriptionInput!\n ) {\n projectModelIngestionUpdated(input: $input) {\n type\n modelIngestion {\n id\n statusData {\n __typename\n ... on ModelIngestionSuccessStatus {\n status\n versionId\n }\n ... on ModelIngestionProcessingStatus {\n status\n progressMessage\n progress\n }\n ... on ModelIngestionFailedStatus {\n status\n errorReason\n }\n ... on ModelIngestionCancelledStatus {\n status\n cancellationMessage\n }\n ... on ModelIngestionQueuedStatus {\n status\n progressMessage\n }\n }\n }\n }\n }\n": typeof types.ProjectModelIngestionUpdatedDocument,
|
||||||
"\n fragment IssuesItem on Issue {\n id\n status\n title\n priority\n viewerState\n identifier\n resourceIdString\n activities(input: { limit: 1, sortDirection: asc }) {\n totalCount\n items {\n actor {\n id\n user {\n name\n id\n avatar\n }\n }\n eventType\n createdAt\n }\n }\n replies {\n totalCount\n items {\n id\n author {\n id\n user {\n name\n id\n avatar\n }\n }\n createdAt\n description {\n doc\n }\n }\n }\n description {\n doc\n }\n labels {\n hexColor\n id\n name\n }\n author {\n id\n user {\n id\n name\n avatar\n }\n }\n dueDate\n assignee {\n id\n user {\n id\n avatar\n name\n }\n }\n }\n": typeof types.IssuesItemFragmentDoc,
|
"\n fragment IssuesItem on Issue {\n id\n status\n title\n priority\n viewerState\n identifier\n resourceIdString\n activities(input: { limit: 1, sortDirection: asc }) {\n totalCount\n items {\n actor {\n id\n user {\n name\n id\n avatar\n }\n }\n eventType\n createdAt\n }\n }\n replies {\n totalCount\n items {\n id\n author {\n id\n user {\n name\n id\n avatar\n }\n }\n createdAt\n description {\n doc\n }\n }\n }\n description {\n doc\n }\n labels {\n hexColor\n id\n name\n }\n author {\n id\n user {\n id\n name\n avatar\n }\n }\n dueDate\n assignee {\n id\n user {\n id\n avatar\n name\n }\n }\n }\n": typeof types.IssuesItemFragmentDoc,
|
||||||
"\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n": typeof types.IssuesListDocument,
|
"\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n": typeof types.IssuesListDocument,
|
||||||
|
"\n query IssueResourceMetaSearch(\n $workspaceId: String!\n $resourceType: ResourceMetaType!\n $resourceId: String!\n $projectId: String\n $metaType: String\n ) {\n resourceMetaSearch(\n workspaceId: $workspaceId\n resourceType: $resourceType\n resourceId: $resourceId\n projectId: $projectId\n metaType: $metaType\n ) {\n data\n }\n }\n": typeof types.IssueResourceMetaSearchDocument,
|
||||||
"\n subscription WorkspacePlanUsageUpdated($input: WorkspacePlanUsageSubscriptionInput!) {\n workspacePlanUsageUpdated(input: $input)\n }\n": typeof types.WorkspacePlanUsageUpdatedDocument,
|
"\n subscription WorkspacePlanUsageUpdated($input: WorkspacePlanUsageSubscriptionInput!) {\n workspacePlanUsageUpdated(input: $input)\n }\n": typeof types.WorkspacePlanUsageUpdatedDocument,
|
||||||
};
|
};
|
||||||
const documents: Documents = {
|
const documents: Documents = {
|
||||||
@@ -117,6 +118,7 @@ const documents: Documents = {
|
|||||||
"\n subscription ProjectModelIngestionUpdated(\n $input: ProjectModelIngestionSubscriptionInput!\n ) {\n projectModelIngestionUpdated(input: $input) {\n type\n modelIngestion {\n id\n statusData {\n __typename\n ... on ModelIngestionSuccessStatus {\n status\n versionId\n }\n ... on ModelIngestionProcessingStatus {\n status\n progressMessage\n progress\n }\n ... on ModelIngestionFailedStatus {\n status\n errorReason\n }\n ... on ModelIngestionCancelledStatus {\n status\n cancellationMessage\n }\n ... on ModelIngestionQueuedStatus {\n status\n progressMessage\n }\n }\n }\n }\n }\n": types.ProjectModelIngestionUpdatedDocument,
|
"\n subscription ProjectModelIngestionUpdated(\n $input: ProjectModelIngestionSubscriptionInput!\n ) {\n projectModelIngestionUpdated(input: $input) {\n type\n modelIngestion {\n id\n statusData {\n __typename\n ... on ModelIngestionSuccessStatus {\n status\n versionId\n }\n ... on ModelIngestionProcessingStatus {\n status\n progressMessage\n progress\n }\n ... on ModelIngestionFailedStatus {\n status\n errorReason\n }\n ... on ModelIngestionCancelledStatus {\n status\n cancellationMessage\n }\n ... on ModelIngestionQueuedStatus {\n status\n progressMessage\n }\n }\n }\n }\n }\n": types.ProjectModelIngestionUpdatedDocument,
|
||||||
"\n fragment IssuesItem on Issue {\n id\n status\n title\n priority\n viewerState\n identifier\n resourceIdString\n activities(input: { limit: 1, sortDirection: asc }) {\n totalCount\n items {\n actor {\n id\n user {\n name\n id\n avatar\n }\n }\n eventType\n createdAt\n }\n }\n replies {\n totalCount\n items {\n id\n author {\n id\n user {\n name\n id\n avatar\n }\n }\n createdAt\n description {\n doc\n }\n }\n }\n description {\n doc\n }\n labels {\n hexColor\n id\n name\n }\n author {\n id\n user {\n id\n name\n avatar\n }\n }\n dueDate\n assignee {\n id\n user {\n id\n avatar\n name\n }\n }\n }\n": types.IssuesItemFragmentDoc,
|
"\n fragment IssuesItem on Issue {\n id\n status\n title\n priority\n viewerState\n identifier\n resourceIdString\n activities(input: { limit: 1, sortDirection: asc }) {\n totalCount\n items {\n actor {\n id\n user {\n name\n id\n avatar\n }\n }\n eventType\n createdAt\n }\n }\n replies {\n totalCount\n items {\n id\n author {\n id\n user {\n name\n id\n avatar\n }\n }\n createdAt\n description {\n doc\n }\n }\n }\n description {\n doc\n }\n labels {\n hexColor\n id\n name\n }\n author {\n id\n user {\n id\n name\n avatar\n }\n }\n dueDate\n assignee {\n id\n user {\n id\n avatar\n name\n }\n }\n }\n": types.IssuesItemFragmentDoc,
|
||||||
"\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n": types.IssuesListDocument,
|
"\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n": types.IssuesListDocument,
|
||||||
|
"\n query IssueResourceMetaSearch(\n $workspaceId: String!\n $resourceType: ResourceMetaType!\n $resourceId: String!\n $projectId: String\n $metaType: String\n ) {\n resourceMetaSearch(\n workspaceId: $workspaceId\n resourceType: $resourceType\n resourceId: $resourceId\n projectId: $projectId\n metaType: $metaType\n ) {\n data\n }\n }\n": types.IssueResourceMetaSearchDocument,
|
||||||
"\n subscription WorkspacePlanUsageUpdated($input: WorkspacePlanUsageSubscriptionInput!) {\n workspacePlanUsageUpdated(input: $input)\n }\n": types.WorkspacePlanUsageUpdatedDocument,
|
"\n subscription WorkspacePlanUsageUpdated($input: WorkspacePlanUsageSubscriptionInput!) {\n workspacePlanUsageUpdated(input: $input)\n }\n": types.WorkspacePlanUsageUpdatedDocument,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -334,6 +336,10 @@ export function graphql(source: "\n fragment IssuesItem on Issue {\n id\n
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n"): (typeof documents)["\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n"];
|
export function graphql(source: "\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n"): (typeof documents)["\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n query IssueResourceMetaSearch(\n $workspaceId: String!\n $resourceType: ResourceMetaType!\n $resourceId: String!\n $projectId: String\n $metaType: String\n ) {\n resourceMetaSearch(\n workspaceId: $workspaceId\n resourceType: $resourceType\n resourceId: $resourceId\n projectId: $projectId\n metaType: $metaType\n ) {\n data\n }\n }\n"): (typeof documents)["\n query IssueResourceMetaSearch(\n $workspaceId: String!\n $resourceType: ResourceMetaType!\n $resourceId: String!\n $projectId: String\n $metaType: String\n ) {\n resourceMetaSearch(\n workspaceId: $workspaceId\n resourceType: $resourceType\n resourceId: $resourceId\n projectId: $projectId\n metaType: $metaType\n ) {\n data\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -13,3 +13,23 @@ export const issuesListQuery = graphql(`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
export const issueResourceMetaSearchQuery = graphql(`
|
||||||
|
query IssueResourceMetaSearch(
|
||||||
|
$workspaceId: String!
|
||||||
|
$resourceType: ResourceMetaType!
|
||||||
|
$resourceId: String!
|
||||||
|
$projectId: String
|
||||||
|
$metaType: String
|
||||||
|
) {
|
||||||
|
resourceMetaSearch(
|
||||||
|
workspaceId: $workspaceId
|
||||||
|
resourceType: $resourceType
|
||||||
|
resourceId: $resourceId
|
||||||
|
projectId: $projectId
|
||||||
|
metaType: $metaType
|
||||||
|
) {
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
IAccountBindingKey,
|
IAccountBindingKey,
|
||||||
MockedAccountBinding
|
MockedAccountBinding
|
||||||
} from '~/lib/bindings/definitions/IAccountBinding'
|
} from '~/lib/bindings/definitions/IAccountBinding'
|
||||||
|
import type { IParametersBinding } from '~/lib/bindings/definitions/IParametersBinding'
|
||||||
|
|
||||||
import type { ITestBinding } from '~/lib/bindings/definitions/ITestBinding'
|
import type { ITestBinding } from '~/lib/bindings/definitions/ITestBinding'
|
||||||
import {
|
import {
|
||||||
@@ -132,6 +133,10 @@ export default defineNuxtPlugin(async () => {
|
|||||||
ITopLevelExpectionHandlerBindingKey
|
ITopLevelExpectionHandlerBindingKey
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const parametersBinding = await tryHoistBinding<IParametersBinding>(
|
||||||
|
'parametersBinding'
|
||||||
|
)
|
||||||
|
|
||||||
// Any binding implments these two methods below, we just choose one to
|
// Any binding implments these two methods below, we just choose one to
|
||||||
// expose globally to the app.
|
// expose globally to the app.
|
||||||
const showDevTools = () => {
|
const showDevTools = () => {
|
||||||
@@ -157,7 +162,8 @@ export default defineNuxtPlugin(async () => {
|
|||||||
topLevelExceptionHandlerBinding,
|
topLevelExceptionHandlerBinding,
|
||||||
showDevTools,
|
showDevTools,
|
||||||
openUrl,
|
openUrl,
|
||||||
revitMapperBinding
|
revitMapperBinding,
|
||||||
|
parametersBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user