mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-22 16:27:22 +00:00
Requests inbox (#3125)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
d435dbfa2e
commit
f24e3e6743
@ -34,6 +34,8 @@
|
|||||||
"@hcengineering/model-view": "^0.6.0",
|
"@hcengineering/model-view": "^0.6.0",
|
||||||
"@hcengineering/model-chunter": "^0.6.0",
|
"@hcengineering/model-chunter": "^0.6.0",
|
||||||
"@hcengineering/request": "^0.6.0",
|
"@hcengineering/request": "^0.6.0",
|
||||||
|
"@hcengineering/notification": "^0.6.10",
|
||||||
|
"@hcengineering/model-notification": "^0.6.0",
|
||||||
"@hcengineering/activity": "^0.6.0",
|
"@hcengineering/activity": "^0.6.0",
|
||||||
"@hcengineering/chunter": "^0.6.5",
|
"@hcengineering/chunter": "^0.6.5",
|
||||||
"@hcengineering/request-resources": "^0.6.0"
|
"@hcengineering/request-resources": "^0.6.0"
|
||||||
|
@ -37,6 +37,8 @@ import view from '@hcengineering/model-view'
|
|||||||
import { Request, RequestDecisionComment, RequestPresenter, RequestStatus } from '@hcengineering/request'
|
import { Request, RequestDecisionComment, RequestPresenter, RequestStatus } from '@hcengineering/request'
|
||||||
import { AnyComponent } from '@hcengineering/ui'
|
import { AnyComponent } from '@hcengineering/ui'
|
||||||
import request from './plugin'
|
import request from './plugin'
|
||||||
|
import notification from '@hcengineering/notification'
|
||||||
|
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
|
||||||
|
|
||||||
export { requestId } from '@hcengineering/request'
|
export { requestId } from '@hcengineering/request'
|
||||||
export { default } from './plugin'
|
export { default } from './plugin'
|
||||||
@ -89,10 +91,54 @@ export function createModel (builder: Builder): void {
|
|||||||
presenter: request.component.RequestPresenter
|
presenter: request.component.RequestPresenter
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(request.class.Request, core.class.Class, notification.mixin.NotificationObjectPresenter, {
|
||||||
|
presenter: request.component.NotificationRequestView
|
||||||
|
})
|
||||||
|
|
||||||
builder.mixin(request.class.Request, core.class.Class, request.mixin.RequestPresenter, {
|
builder.mixin(request.class.Request, core.class.Class, request.mixin.RequestPresenter, {
|
||||||
presenter: request.component.RequestView
|
presenter: request.component.RequestView
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(request.class.Request, core.class.Class, notification.mixin.ClassCollaborators, {
|
||||||
|
fields: ['requested', 'createdBy']
|
||||||
|
})
|
||||||
|
|
||||||
|
builder.createDoc(
|
||||||
|
notification.class.NotificationGroup,
|
||||||
|
core.space.Model,
|
||||||
|
{
|
||||||
|
label: request.string.Requests,
|
||||||
|
icon: request.icon.Requests,
|
||||||
|
objectClass: request.class.Request
|
||||||
|
},
|
||||||
|
request.ids.RequestNotificationGroup
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.createDoc(
|
||||||
|
notification.class.NotificationType,
|
||||||
|
core.space.Model,
|
||||||
|
{
|
||||||
|
hidden: false,
|
||||||
|
objectClass: request.class.Request,
|
||||||
|
txClasses: [core.class.TxCreateDoc],
|
||||||
|
generated: false,
|
||||||
|
group: request.ids.RequestNotificationGroup,
|
||||||
|
label: request.string.Requested,
|
||||||
|
providers: {
|
||||||
|
[notification.providers.PlatformNotification]: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
request.ids.CreateRequestNotification
|
||||||
|
)
|
||||||
|
|
||||||
|
generateClassNotificationTypes(
|
||||||
|
builder,
|
||||||
|
request.class.Request,
|
||||||
|
request.ids.RequestNotificationGroup,
|
||||||
|
[],
|
||||||
|
['comments', 'approved', 'rejected', 'status']
|
||||||
|
)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
activity.class.TxViewlet,
|
activity.class.TxViewlet,
|
||||||
core.space.Model,
|
core.space.Model,
|
||||||
|
@ -20,6 +20,7 @@ import { requestId } from '@hcengineering/request'
|
|||||||
import request from '@hcengineering/request-resources/src/plugin'
|
import request from '@hcengineering/request-resources/src/plugin'
|
||||||
import { AnyComponent } from '@hcengineering/ui'
|
import { AnyComponent } from '@hcengineering/ui'
|
||||||
import type { TxViewlet } from '@hcengineering/activity'
|
import type { TxViewlet } from '@hcengineering/activity'
|
||||||
|
import type { NotificationGroup, NotificationType } from '@hcengineering/notification'
|
||||||
|
|
||||||
export default mergeIds(requestId, request, {
|
export default mergeIds(requestId, request, {
|
||||||
activity: {
|
activity: {
|
||||||
@ -27,10 +28,13 @@ export default mergeIds(requestId, request, {
|
|||||||
RequestLabel: '' as AnyComponent
|
RequestLabel: '' as AnyComponent
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
EditRequest: '' as AnyComponent
|
EditRequest: '' as AnyComponent,
|
||||||
|
NotificationRequestView: '' as AnyComponent
|
||||||
},
|
},
|
||||||
ids: {
|
ids: {
|
||||||
TxRequestCreate: '' as Ref<TxViewlet>
|
TxRequestCreate: '' as Ref<TxViewlet>,
|
||||||
|
RequestNotificationGroup: '' as Ref<NotificationGroup>,
|
||||||
|
CreateRequestNotification: '' as Ref<NotificationType>
|
||||||
},
|
},
|
||||||
string: {
|
string: {
|
||||||
Status: '' as IntlString,
|
Status: '' as IntlString,
|
||||||
|
@ -747,6 +747,7 @@ a.no-line {
|
|||||||
.font-semi-bold { font-weight: 600; }
|
.font-semi-bold { font-weight: 600; }
|
||||||
.fs-bold { font-weight: 500; }
|
.fs-bold { font-weight: 500; }
|
||||||
.uppercase { text-transform: uppercase; }
|
.uppercase { text-transform: uppercase; }
|
||||||
|
.lower { text-transform: lowercase; }
|
||||||
.text-left { text-align: left; }
|
.text-left { text-align: left; }
|
||||||
|
|
||||||
.over-underline {
|
.over-underline {
|
||||||
|
@ -202,7 +202,9 @@ export async function resolveLocation (loc: Location): Promise<ResolvedLocation
|
|||||||
}
|
}
|
||||||
|
|
||||||
const id = loc.path[3] as Ref<Contact>
|
const id = loc.path[3] as Ref<Contact>
|
||||||
|
if (id !== undefined) {
|
||||||
return await generateLocation(loc, id)
|
return await generateLocation(loc, id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateLocation (loc: Location, id: Ref<Contact>): Promise<ResolvedLocation | undefined> {
|
async function generateLocation (loc: Location, id: Ref<Contact>): Promise<ResolvedLocation | undefined> {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"Request": "Request",
|
"Request": "Request",
|
||||||
"Approve": "Approve",
|
"Approve": "Approve",
|
||||||
"Approved": "Approved",
|
"Approved": "Approved",
|
||||||
"CreatedRequest": "Created a request",
|
"CreatedRequest": "Created a ",
|
||||||
"For": "For",
|
"For": "For",
|
||||||
"Change": "Change",
|
"Change": "Change",
|
||||||
"Add": "Add",
|
"Add": "Add",
|
||||||
@ -16,6 +16,8 @@
|
|||||||
"Rejected": "Rejected",
|
"Rejected": "Rejected",
|
||||||
"Comment": "Comment",
|
"Comment": "Comment",
|
||||||
"PleaseTypeMessage": "Please type comment message to continue...",
|
"PleaseTypeMessage": "Please type comment message to continue...",
|
||||||
"NoRequests": "No requests"
|
"NoRequests": "No requests",
|
||||||
|
"Cancel": "Cancel",
|
||||||
|
"Cancelled": "Cancelled"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@
|
|||||||
"Request": "Запрос",
|
"Request": "Запрос",
|
||||||
"Approve": "Одобрить",
|
"Approve": "Одобрить",
|
||||||
"Approved": "Одобрено",
|
"Approved": "Одобрено",
|
||||||
"CreatedRequest": "Создал запрос",
|
"CreatedRequest": "Создал(а)",
|
||||||
"For": "Для",
|
"For": "Для",
|
||||||
"Change": "Изменить",
|
"Change": "Изменить",
|
||||||
"Add": "Добавить",
|
"Add": "Добавить",
|
||||||
@ -16,6 +16,8 @@
|
|||||||
"Rejected": "Отклонен",
|
"Rejected": "Отклонен",
|
||||||
"Comment": "Комментировать",
|
"Comment": "Комментировать",
|
||||||
"PleaseTypeMessage": "Пожалуйста оставьте коментарий чтобы продолжить...",
|
"PleaseTypeMessage": "Пожалуйста оставьте коментарий чтобы продолжить...",
|
||||||
"NoRequests": "Нет запросов"
|
"NoRequests": "Нет запросов",
|
||||||
|
"Cancel": "Отменить",
|
||||||
|
"Cancelled": "Отменен"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,12 +15,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Request } from '@hcengineering/request'
|
import { Request } from '@hcengineering/request'
|
||||||
import { Label } from '@hcengineering/ui'
|
import { Label } from '@hcengineering/ui'
|
||||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
import { DocNavLink, ObjectPresenter } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import request from '../plugin'
|
import request from '../plugin'
|
||||||
import RequestActions from './RequestActions.svelte'
|
import RequestActions from './RequestActions.svelte'
|
||||||
import RequestDetail from './RequestDetail.svelte'
|
import RequestDetail from './RequestDetail.svelte'
|
||||||
import TxView from './TxView.svelte'
|
import TxView from './TxView.svelte'
|
||||||
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
|
import { Doc } from '@hcengineering/core'
|
||||||
|
|
||||||
export let object: Request
|
export let object: Request
|
||||||
|
|
||||||
@ -28,16 +30,28 @@
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
dispatch('open', {
|
dispatch('open', {
|
||||||
ignoreKeys: ['comments', 'status', 'rejected', 'approved', 'requested'],
|
ignoreKeys: ['status'],
|
||||||
activityOptions: { enabled: true, showInput: false }
|
activityOptions: { enabled: true, showInput: false }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
let doc: Doc | undefined = undefined
|
||||||
|
|
||||||
|
const query = createQuery()
|
||||||
|
query.query(object.attachedToClass, { _id: object.attachedTo }, (res) => {
|
||||||
|
;[doc] = res
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if object !== undefined}
|
{#if object !== undefined}
|
||||||
<div class="flex-row-center gap-1 mb-2">
|
<div class="flex-row-center gap-1 mb-2">
|
||||||
<span class="mr-1"><Label label={request.string.For} /></span>
|
<span class="mr-1"><Label label={request.string.For} /></span>
|
||||||
<span class="mr-1"><ObjectPresenter objectId={object.tx.objectId} _class={object.tx.objectClass} /></span>
|
{#if doc}
|
||||||
|
<span class="mr-1">
|
||||||
|
<DocNavLink object={doc}>
|
||||||
|
<ObjectPresenter value={doc} />
|
||||||
|
</DocNavLink>
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
<TxView tx={object.tx} />
|
<TxView tx={object.tx} />
|
||||||
</div>
|
</div>
|
||||||
<RequestDetail value={object} />
|
<RequestDetail value={object} />
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { Doc } from '@hcengineering/core'
|
||||||
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
|
import { Request } from '@hcengineering/request'
|
||||||
|
import { Label } from '@hcengineering/ui'
|
||||||
|
import { DocNavLink, ObjectPresenter } from '@hcengineering/view-resources'
|
||||||
|
import requests from '../plugin'
|
||||||
|
import RequestLabel from './RequestLabel.svelte'
|
||||||
|
|
||||||
|
export let value: Request
|
||||||
|
let doc: Doc | undefined = undefined
|
||||||
|
|
||||||
|
const query = createQuery()
|
||||||
|
query.query(value.attachedToClass, { _id: value.attachedTo }, (res) => {
|
||||||
|
;[doc] = res
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="inline-presenter">
|
||||||
|
<RequestLabel {value} size={'inline'} />
|
||||||
|
<span class="lower mx-1">
|
||||||
|
<Label label={requests.string.For} />
|
||||||
|
</span>
|
||||||
|
{#if doc}
|
||||||
|
<DocNavLink object={doc}>
|
||||||
|
<ObjectPresenter value={doc} />
|
||||||
|
</DocNavLink>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.lower {
|
||||||
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
|
</style>
|
@ -21,6 +21,7 @@
|
|||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { Request, RequestStatus } from '@hcengineering/request'
|
import { Request, RequestStatus } from '@hcengineering/request'
|
||||||
import type { RefAction } from '@hcengineering/text-editor'
|
import type { RefAction } from '@hcengineering/text-editor'
|
||||||
|
import { Button } from '@hcengineering/ui'
|
||||||
import request from '../plugin'
|
import request from '../plugin'
|
||||||
import Comments from './icons/Comments.svelte'
|
import Comments from './icons/Comments.svelte'
|
||||||
import DocFail from './icons/DocFail.svelte'
|
import DocFail from './icons/DocFail.svelte'
|
||||||
@ -70,7 +71,18 @@
|
|||||||
|
|
||||||
// We need to update backlinks before and after.
|
// We need to update backlinks before and after.
|
||||||
await updateBacklinks(client, value.attachedTo, value.attachedToClass, value._id, message)
|
await updateBacklinks(client, value.attachedTo, value.attachedToClass, value._id, message)
|
||||||
refInput.submit()
|
refInput.createAttachments()
|
||||||
|
loading = false
|
||||||
|
}
|
||||||
|
|
||||||
|
async function comment (): Promise<void> {
|
||||||
|
await client.addCollection(chunter.class.Comment, value.space, value._id, value._class, 'comments', {
|
||||||
|
message,
|
||||||
|
attachments
|
||||||
|
})
|
||||||
|
|
||||||
|
// We need to update backlinks before and after.
|
||||||
|
await updateBacklinks(client, value.attachedTo, value.attachedToClass, value._id, message)
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,9 +111,20 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
let loading = false
|
let loading = false
|
||||||
|
|
||||||
|
async function cancel () {
|
||||||
|
await client.update(value, {
|
||||||
|
status: RequestStatus.Cancelled
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if value.status === RequestStatus.Active}
|
{#if value.status === RequestStatus.Active}
|
||||||
|
{#if value.createdBy === me}
|
||||||
|
<div class="mt-2">
|
||||||
|
<Button label={request.string.Cancel} on:click={cancel} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<AttachmentRefInput
|
<AttachmentRefInput
|
||||||
bind:this={refInput}
|
bind:this={refInput}
|
||||||
@ -110,6 +133,7 @@
|
|||||||
objectId={value._id}
|
objectId={value._id}
|
||||||
iconSend={Comments}
|
iconSend={Comments}
|
||||||
labelSend={request.string.Comment}
|
labelSend={request.string.Comment}
|
||||||
|
on:message={comment}
|
||||||
on:update={onUpdate}
|
on:update={onUpdate}
|
||||||
placeholder={request.string.PleaseTypeMessage}
|
placeholder={request.string.PleaseTypeMessage}
|
||||||
extraActions={approvable ? extraActions : undefined}
|
extraActions={approvable ? extraActions : undefined}
|
||||||
|
@ -14,15 +14,32 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Request, RequestStatus } from '@hcengineering/request'
|
import { Request, RequestStatus } from '@hcengineering/request'
|
||||||
import { Button, eventToHTMLElement, ProgressCircle, showPopup } from '@hcengineering/ui'
|
import { Button, ButtonSize, Label, ProgressCircle, eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||||
import RequestStatusPresenter from './RequestStatusPresenter.svelte'
|
import { DocNavLink } from '@hcengineering/view-resources'
|
||||||
|
import request from '../plugin'
|
||||||
import RequestDetailPopup from './RequestDetailPopup.svelte'
|
import RequestDetailPopup from './RequestDetailPopup.svelte'
|
||||||
|
import RequestStatusPresenter from './RequestStatusPresenter.svelte'
|
||||||
|
|
||||||
export let value: Request
|
export let value: Request
|
||||||
|
export let isOwnTx: boolean = false
|
||||||
|
export let size: ButtonSize = 'inline'
|
||||||
|
export let inline: boolean = true
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex">
|
||||||
|
{#if isOwnTx}
|
||||||
|
<div class="lower" class:inline-presenter={inline}>
|
||||||
|
<Label label={request.string.Request} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<DocNavLink {inline} object={value}>
|
||||||
|
<div class="flex-presenter lower" class:inline-presenter={inline}>
|
||||||
|
<Label label={request.string.Request} />
|
||||||
|
</div>
|
||||||
|
</DocNavLink>
|
||||||
<Button
|
<Button
|
||||||
|
{size}
|
||||||
|
kind="link"
|
||||||
on:click={(ev) => {
|
on:click={(ev) => {
|
||||||
ev.stopPropagation()
|
ev.stopPropagation()
|
||||||
showPopup(RequestDetailPopup, { value }, eventToHTMLElement(ev))
|
showPopup(RequestDetailPopup, { value }, eventToHTMLElement(ev))
|
||||||
@ -30,7 +47,7 @@
|
|||||||
>
|
>
|
||||||
<svelte:fragment slot="content">
|
<svelte:fragment slot="content">
|
||||||
{#if value.status !== RequestStatus.Active}
|
{#if value.status !== RequestStatus.Active}
|
||||||
<RequestStatusPresenter value={value.status === RequestStatus.Completed} />
|
<RequestStatusPresenter value={value.status} />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex-row-center content-color text-sm pointer-events-none">
|
<div class="flex-row-center content-color text-sm pointer-events-none">
|
||||||
<div class="mr-1">
|
<div class="mr-1">
|
||||||
@ -41,4 +58,5 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Button>
|
</Button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,33 +13,13 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Request, RequestStatus } from '@hcengineering/request'
|
import { Request } from '@hcengineering/request'
|
||||||
import { Icon, IconCheck, IconClose, IconInfo } from '@hcengineering/ui'
|
|
||||||
import { DocNavLink } from '@hcengineering/view-resources'
|
|
||||||
import TxView from './TxView.svelte'
|
import TxView from './TxView.svelte'
|
||||||
|
|
||||||
export let value: Request
|
export let value: Request
|
||||||
export let inline: boolean = false
|
export let inline: boolean = false
|
||||||
|
|
||||||
$: dte = new Date(value.tx.modifiedOn)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<DocNavLink {inline} object={value}>
|
|
||||||
<div class="flex-presenter mr-1" class:inline-presenter={inline}>
|
|
||||||
<div class="flex flex-row-center">
|
|
||||||
<div class="mr-2">
|
|
||||||
{#if value.status === RequestStatus.Completed || value.status === RequestStatus.Rejected}
|
|
||||||
<Icon icon={value.status === RequestStatus.Completed ? IconCheck : IconClose} size={'small'} />
|
|
||||||
{:else}
|
|
||||||
<Icon icon={IconInfo} size={'small'} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<span class="label nowrap">
|
|
||||||
{dte.getMonth() + 1}/{dte.getDay() + 1}-{(dte.getHours() * 60 + dte.getMinutes()).toString(7)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DocNavLink>
|
|
||||||
<TxView tx={value.tx} />
|
<TxView tx={value.tx} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,22 +16,19 @@
|
|||||||
import { IntlString } from '@hcengineering/platform'
|
import { IntlString } from '@hcengineering/platform'
|
||||||
import { BooleanIcon, Label } from '@hcengineering/ui'
|
import { BooleanIcon, Label } from '@hcengineering/ui'
|
||||||
import request from '../plugin'
|
import request from '../plugin'
|
||||||
|
import { RequestStatus } from '@hcengineering/request'
|
||||||
|
|
||||||
export let value: boolean
|
export let value: RequestStatus
|
||||||
|
|
||||||
function getBooleanLabel (value: boolean): IntlString {
|
function getBooleanLabel (value: RequestStatus): IntlString {
|
||||||
if (value) return request.string.Completed
|
if (value === RequestStatus.Completed) return request.string.Completed
|
||||||
return request.string.Rejected
|
if (value === RequestStatus.Rejected) return request.string.Rejected
|
||||||
|
return request.string.Cancelled
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div class="flex-row-center yesno-container">
|
||||||
class="flex-row-center yesno-container"
|
<BooleanIcon value={value === RequestStatus.Completed} />
|
||||||
class:yes={value === true}
|
|
||||||
class:no={value === false}
|
|
||||||
class:unknown={value === undefined}
|
|
||||||
>
|
|
||||||
<BooleanIcon {value} />
|
|
||||||
<span><Label label={getBooleanLabel(value)} /></span>
|
<span><Label label={getBooleanLabel(value)} /></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
import RequestPresenter from '../RequestPresenter.svelte'
|
import RequestPresenter from '../RequestPresenter.svelte'
|
||||||
|
|
||||||
export let value: Request
|
export let value: Request
|
||||||
|
export let isOwnTx: boolean
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<RequestPresenter {value} />
|
{#if !isOwnTx}
|
||||||
|
<RequestPresenter {value} />
|
||||||
|
{/if}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import RequestLabel from '../RequestLabel.svelte'
|
import RequestLabel from '../RequestLabel.svelte'
|
||||||
|
|
||||||
export let value: Request
|
export let value: Request
|
||||||
|
export let isOwnTx: boolean
|
||||||
let request: Request | undefined = undefined
|
let request: Request | undefined = undefined
|
||||||
|
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
@ -25,7 +26,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if request}
|
{#if request}
|
||||||
<div class="ml-1">
|
<RequestLabel value={request} {isOwnTx} />
|
||||||
<RequestLabel value={request} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { Resources } from '@hcengineering/platform'
|
import { Resources } from '@hcengineering/platform'
|
||||||
import RequestsPopup from './components/RequestsPopup.svelte'
|
|
||||||
import TxCreateRequest from './components/activity/TxCreateRequest.svelte'
|
import TxCreateRequest from './components/activity/TxCreateRequest.svelte'
|
||||||
import RequestLabel from './components/activity/TxRequestLabel.svelte'
|
import RequestLabel from './components/activity/TxRequestLabel.svelte'
|
||||||
import EditRequest from './components/EditRequest.svelte'
|
import EditRequest from './components/EditRequest.svelte'
|
||||||
import RequestPresenter from './components/RequestPresenter.svelte'
|
import RequestPresenter from './components/RequestPresenter.svelte'
|
||||||
import RequestView from './components/RequestView.svelte'
|
import RequestView from './components/RequestView.svelte'
|
||||||
|
import NotificationRequestView from './components/NotificationRequestView.svelte'
|
||||||
|
|
||||||
export default async (): Promise<Resources> => ({
|
export default async (): Promise<Resources> => ({
|
||||||
activity: {
|
activity: {
|
||||||
@ -27,9 +27,9 @@ export default async (): Promise<Resources> => ({
|
|||||||
TxCreateRequest
|
TxCreateRequest
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
RequestsPopup,
|
|
||||||
EditRequest,
|
EditRequest,
|
||||||
RequestPresenter,
|
RequestPresenter,
|
||||||
RequestView
|
RequestView,
|
||||||
|
NotificationRequestView
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -22,6 +22,7 @@ export default mergeIds(requestId, request, {
|
|||||||
Approve: '' as IntlString,
|
Approve: '' as IntlString,
|
||||||
Approved: '' as IntlString,
|
Approved: '' as IntlString,
|
||||||
CreatedRequest: '' as IntlString,
|
CreatedRequest: '' as IntlString,
|
||||||
|
Cancel: '' as IntlString,
|
||||||
For: '' as IntlString,
|
For: '' as IntlString,
|
||||||
Change: '' as IntlString,
|
Change: '' as IntlString,
|
||||||
Add: '' as IntlString,
|
Add: '' as IntlString,
|
||||||
@ -32,6 +33,7 @@ export default mergeIds(requestId, request, {
|
|||||||
Rejected: '' as IntlString,
|
Rejected: '' as IntlString,
|
||||||
Comment: '' as IntlString,
|
Comment: '' as IntlString,
|
||||||
PleaseTypeMessage: '' as IntlString,
|
PleaseTypeMessage: '' as IntlString,
|
||||||
NoRequests: '' as IntlString
|
NoRequests: '' as IntlString,
|
||||||
|
Cancelled: '' as IntlString
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -44,7 +44,8 @@ export interface RequestDecisionComment extends Comment {}
|
|||||||
export enum RequestStatus {
|
export enum RequestStatus {
|
||||||
Active = 'Active',
|
Active = 'Active',
|
||||||
Completed = 'Completed',
|
Completed = 'Completed',
|
||||||
Rejected = 'Rejected'
|
Rejected = 'Rejected',
|
||||||
|
Cancelled = 'Cancelled'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,7 +72,6 @@ const request = plugin(requestId, {
|
|||||||
RequestPresenter: '' as Ref<Mixin<RequestPresenter>>
|
RequestPresenter: '' as Ref<Mixin<RequestPresenter>>
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
RequestsPopup: '' as AnyComponent,
|
|
||||||
RequestPresenter: '' as AnyComponent,
|
RequestPresenter: '' as AnyComponent,
|
||||||
RequestView: '' as AnyComponent
|
RequestView: '' as AnyComponent
|
||||||
},
|
},
|
||||||
|
@ -20,8 +20,7 @@
|
|||||||
import notification, { notificationId } from '@hcengineering/notification'
|
import notification, { notificationId } from '@hcengineering/notification'
|
||||||
import { BrowserNotificatator, NotificationClientImpl } from '@hcengineering/notification-resources'
|
import { BrowserNotificatator, NotificationClientImpl } from '@hcengineering/notification-resources'
|
||||||
import { IntlString, getMetadata, getResource } from '@hcengineering/platform'
|
import { IntlString, getMetadata, getResource } from '@hcengineering/platform'
|
||||||
import { createQuery, getClient, configurationStore } from '@hcengineering/presentation'
|
import { configurationStore, createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import request, { RequestStatus, requestId } from '@hcengineering/request'
|
|
||||||
import {
|
import {
|
||||||
AnyComponent,
|
AnyComponent,
|
||||||
CompAndProps,
|
CompAndProps,
|
||||||
@ -60,11 +59,11 @@
|
|||||||
import AccountPopup from './AccountPopup.svelte'
|
import AccountPopup from './AccountPopup.svelte'
|
||||||
import AppItem from './AppItem.svelte'
|
import AppItem from './AppItem.svelte'
|
||||||
import Applications from './Applications.svelte'
|
import Applications from './Applications.svelte'
|
||||||
|
import Logo from './Logo.svelte'
|
||||||
import NavHeader from './NavHeader.svelte'
|
import NavHeader from './NavHeader.svelte'
|
||||||
import Navigator from './Navigator.svelte'
|
import Navigator from './Navigator.svelte'
|
||||||
import SpaceView from './SpaceView.svelte'
|
import SpaceView from './SpaceView.svelte'
|
||||||
import Settings from './icons/Settings.svelte'
|
import Settings from './icons/Settings.svelte'
|
||||||
import Logo from './Logo.svelte'
|
|
||||||
import TopMenu from './icons/TopMenu.svelte'
|
import TopMenu from './icons/TopMenu.svelte'
|
||||||
|
|
||||||
let contentPanel: HTMLElement
|
let contentPanel: HTMLElement
|
||||||
@ -159,24 +158,6 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let hasRequests = false
|
|
||||||
const requestQuery = createQuery()
|
|
||||||
|
|
||||||
$: $configurationStore.has(requestId) ||
|
|
||||||
requestQuery.query(
|
|
||||||
request.class.Request,
|
|
||||||
{
|
|
||||||
requested: account._id,
|
|
||||||
status: RequestStatus.Active
|
|
||||||
},
|
|
||||||
(res) =>
|
|
||||||
(hasRequests =
|
|
||||||
res.filter(
|
|
||||||
(p) =>
|
|
||||||
p.requested.filter((a) => a === account._id).length > p.approved.filter((a) => a === account._id).length
|
|
||||||
).length > 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
onDestroy(
|
onDestroy(
|
||||||
location.subscribe(async (loc) => {
|
location.subscribe(async (loc) => {
|
||||||
closeTooltip()
|
closeTooltip()
|
||||||
@ -606,14 +587,6 @@
|
|||||||
on:click={() => showPopup(calendar.component.RemindersPopup, {}, notifyPosition)}
|
on:click={() => showPopup(calendar.component.RemindersPopup, {}, notifyPosition)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $configurationStore.has(requestId)}
|
|
||||||
<AppItem
|
|
||||||
icon={request.icon.Requests}
|
|
||||||
label={request.string.Requests}
|
|
||||||
on:click={() => showPopup(request.component.RequestsPopup, {}, notifyPosition)}
|
|
||||||
notify={hasRequests}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
<div class="divider" />
|
<div class="divider" />
|
||||||
<Applications
|
<Applications
|
||||||
apps={getApps(apps)}
|
apps={getApps(apps)}
|
||||||
|
@ -31,6 +31,7 @@ export async function OnRequestUpdate (tx: Tx, control: TriggerControl): Promise
|
|||||||
const collectionTx = control.txFactory.createTxUpdateDoc(ctx.objectClass, ctx.objectSpace, ctx.objectId, {
|
const collectionTx = control.txFactory.createTxUpdateDoc(ctx.objectClass, ctx.objectSpace, ctx.objectId, {
|
||||||
status: RequestStatus.Completed
|
status: RequestStatus.Completed
|
||||||
})
|
})
|
||||||
|
collectionTx.space = core.space.Tx
|
||||||
const resTx = control.txFactory.createTxCollectionCUD(
|
const resTx = control.txFactory.createTxCollectionCUD(
|
||||||
ptx.objectClass,
|
ptx.objectClass,
|
||||||
ptx.objectId,
|
ptx.objectId,
|
||||||
@ -38,13 +39,9 @@ export async function OnRequestUpdate (tx: Tx, control: TriggerControl): Promise
|
|||||||
'requests',
|
'requests',
|
||||||
collectionTx
|
collectionTx
|
||||||
)
|
)
|
||||||
return [
|
resTx.space = core.space.Tx
|
||||||
{
|
|
||||||
...request.tx,
|
await control.apply([resTx], true)
|
||||||
modifiedOn: resTx.modifiedOn
|
|
||||||
},
|
|
||||||
resTx
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user