Skip to content

Commit

Permalink
Add hover card to show a submission
Browse files Browse the repository at this point in the history
  • Loading branch information
matthew-white committed Dec 3, 2024
1 parent 61e5df9 commit b84a874
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 24 deletions.
18 changes: 5 additions & 13 deletions src/components/entity/feed-entry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ except according to the terms contained in the LICENSE file.
<i18n-t v-if="submission.currentVersion != null"
keypath="title.submission.create.notDeleted">
<template #instanceName>
<router-link :to="sourceSubmissionPath">
{{ submission.currentVersion.instanceName ?? submission.instanceId }}
</router-link>
<submission-link :project-id="projectId"
:xml-form-id="submission.xmlFormId" :submission="submission"/>
</template>
<template #submitter><actor-link :actor="submission.submitter"/></template>
</i18n-t>
Expand Down Expand Up @@ -99,9 +98,8 @@ except according to the terms contained in the LICENSE file.
<i18n-t v-if="submission.currentVersion != null"
keypath="title.entity.update_version.submission.notDeleted">
<template #instanceName>
<router-link :to="sourceSubmissionPath">
{{ submission.currentVersion.instanceName ?? submission.instanceId }}
</router-link>
<submission-link :project-id="projectId"
:xml-form-id="submission.xmlFormId" :submission="submission"/>
</template>
</i18n-t>
<i18n-t v-else keypath="title.entity.update_version.submission.deleted.full">
Expand Down Expand Up @@ -147,9 +145,9 @@ import ActorLink from '../actor-link.vue';
import DatasetLink from '../dataset/link.vue';
import EntityDiff from './diff.vue';
import FeedEntry from '../feed-entry.vue';
import SubmissionLink from '../submission/link.vue';

import useReviewState from '../../composables/review-state';
import useRoutes from '../../composables/routes';
import { useRequestData } from '../../request-data';

defineOptions({
Expand Down Expand Up @@ -181,12 +179,6 @@ const wrapTitle = computed(() => {
});

// submission.create, entity.update.version
const { submissionPath } = useRoutes();
const sourceSubmissionPath = computed(() => submissionPath(
projectId,
props.submission.xmlFormId,
props.submission.instanceId
));
const { t } = useI18n();
const deletedSubmission = (key) => t(key, { id: props.submission.instanceId });

Expand Down
52 changes: 52 additions & 0 deletions src/components/hover-card/submission.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!--
Copyright 2024 ODK Central Developers
See the NOTICE file at the top-level directory of this distribution and at
https://github.com/getodk/central-frontend/blob/master/NOTICE.

This file is part of ODK Central. It is subject to the license terms in
the LICENSE file found in the top-level directory of this distribution and at
https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central,
including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
-->
<template>
<hover-card icon="file">
<template #title>{{ submission.instanceNameOrId }}</template>
<template #subtitle>{{ $t('resource.submission') }}</template>
<template #body>
<dl class="dl-horizontal dl-horizontal-fixed">
<dt>{{ $t('resource.form') }}</dt>
<dd>{{ form.nameOrId }}</dd>

<dt>{{ $t('header.submitterName') }}</dt>
<dd>{{ submission.__system.submitterName }}</dd>

<dt>{{ $t('header.submissionDate') }}</dt>
<dd><date-time :iso="submission.__system.submissionDate"/></dd>

<dt>{{ $t('common.lastUpdate') }}</dt>
<dd><date-time :iso="updatedOrCreatedAt"/></dd>
</dl>
</template>
</hover-card>
</template>

<script setup>
import { computed } from 'vue';

import DateTime from '../date-time.vue';
import HoverCard from '../hover-card.vue';

import { useRequestData } from '../../request-data';

defineOptions({
name: 'HoverCardSubmission'
});

const { form, submission } = useRequestData();

const updatedOrCreatedAt = computed(() => {
const { __system } = submission;
return __system.updatedAt ?? __system.submissionDate;
});
</script>
12 changes: 12 additions & 0 deletions src/components/hover-cards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { inject, nextTick, ref, shallowRef, watch } from 'vue';
import HoverCardDataset from './hover-card/dataset.vue';
import HoverCardEntity from './hover-card/entity.vue';
import HoverCardForm from './hover-card/form.vue';
import HoverCardSubmission from './hover-card/submission.vue';
import Popover from './popover.vue';

import useHoverCardResources from '../request-data/hover-card';
Expand All @@ -47,6 +48,17 @@ const types = {
form: { url: apiPaths.form(projectId, xmlFormId), extended: true }
})
},
submission: {
component: HoverCardSubmission,
requests: ({ projectId, xmlFormId, instanceId }) => ({
form: { url: apiPaths.form(projectId, xmlFormId) },
submission: {
url: apiPaths.odataSubmission(projectId, xmlFormId, instanceId, {
$select: '__id,__system,meta'
})
}
})
},
dataset: {
component: HoverCardDataset,
requests: ({ projectId, name }) => ({
Expand Down
53 changes: 53 additions & 0 deletions src/components/submission/link.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!--
Copyright 2024 ODK Central Developers
See the NOTICE file at the top-level directory of this distribution and at
https://github.com/getodk/central-frontend/blob/master/NOTICE.

This file is part of ODK Central. It is subject to the license terms in
the LICENSE file found in the top-level directory of this distribution and at
https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central,
including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
-->
<template>
<router-link ref="link" :key="to" :to="to">
{{ submission.currentVersion.instanceName ?? submission.instanceId }}
</router-link>
</template>

<script setup>
import { computed, ref } from 'vue';

import useHoverCard from '../../composables/hover-card';
import useRoutes from '../../composables/routes';

defineOptions({
name: 'SubmissionLink'
});
const props = defineProps({
projectId: {
type: [Number, String],
required: true
},
xmlFormId: {
type: String,
required: true
},
// A submission in the format of a REST API response (not OData)
submission: {
type: Object,
required: true
}
});

const { submissionPath } = useRoutes();
const to = computed(() =>
submissionPath(props.projectId, props.xmlFormId, props.submission.instanceId));

const link = ref(null);
useHoverCard(computed(() => link.value?.$el), 'submission', () => ({
projectId: props.projectId,
xmlFormId: props.xmlFormId,
instanceId: props.submission.instanceId
}));
</script>
1 change: 1 addition & 0 deletions src/locales/en.json5
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
"webUser": "Web User",
"webUsers": "Web Users",
"session": "Session",
"submission": "Submission",
"submissions": "Submissions",
"projectRoles": "Project Roles",
"formPreview": "Form Preview"
Expand Down
3 changes: 3 additions & 0 deletions src/request-data/hover-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ except according to the terms contained in the LICENSE file.
// e.g., `form`. For simplicity, we want the hover card resources to be
// independent of resources used in other components.

import useSubmission from './submission';
import { transformForm } from './util';
import { useRequestData } from './index';

export default () => {
const { createResource } = useRequestData();
const { submission } = useSubmission();
return {
form: createResource('form', () => ({
transformResponse: ({ data }) => transformForm(data)
})),
submission,
dataset: createResource('dataset'),
entity: createResource('entity')
};
Expand Down
34 changes: 23 additions & 11 deletions test/components/entity/feed-entry.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import DatasetLink from '../../../src/components/dataset/link.vue';
import EntityDiff from '../../../src/components/entity/diff.vue';
import EntityFeedEntry from '../../../src/components/entity/feed-entry.vue';
import FeedEntry from '../../../src/components/feed-entry.vue';
import SubmissionLink from '../../../src/components/submission/link.vue';

import useEntity from '../../../src/request-data/entity';
import useEntityVersions from '../../../src/request-data/entity-versions';
Expand Down Expand Up @@ -99,10 +100,17 @@ describe('EntityFeedEntry', () => {
});

it('links to the submission', () => {
const component = mountComponent({ props: createSubmission() });
const component = mountComponent({
props: createSubmission({
meta: { instanceName: 'Some Name' }
})
});
const title = component.get('.feed-entry-title');
const { to } = title.getComponent(RouterLinkStub).props();
to.should.equal('/projects/1/forms/f/submissions/s');
const link = title.getComponent(SubmissionLink).props();
link.projectId.should.equal('1');
link.xmlFormId.should.equal('f');
link.submission.instanceId.should.equal('s');
link.submission.currentVersion.instanceName.should.equal('Some Name');
});

it('links to the submitter', () => {
Expand Down Expand Up @@ -135,9 +143,7 @@ describe('EntityFeedEntry', () => {
const component = mountComponent({
props: createSubmission({ deleted: true })
});
const links = component.findAllComponents(RouterLinkStub);
links.length.should.equal(1);
links[0].props().to.should.startWith('/users/');
component.findComponent(SubmissionLink).exists().should.be.false;
});
});
});
Expand Down Expand Up @@ -382,10 +388,17 @@ describe('EntityFeedEntry', () => {
});

it('links to the submission', () => {
const component = mountComponent({ props: updateEntityFromSubmission() });
const component = mountComponent({
props: updateEntityFromSubmission({
meta: { instanceName: 'Some Name' }
})
});
const title = component.get('.feed-entry-title');
const { to } = title.getComponent(RouterLinkStub).props();
to.should.equal('/projects/1/forms/f/submissions/s');
const link = title.getComponent(SubmissionLink).props();
link.projectId.should.equal('1');
link.xmlFormId.should.equal('f');
link.submission.instanceId.should.equal('s');
link.submission.currentVersion.instanceName.should.equal('Some Name');
});

it('shows the correct text with deleted submission instance id', () => {
Expand All @@ -399,8 +412,7 @@ describe('EntityFeedEntry', () => {
const component = mountComponent({
props: updateEntityFromSubmission({ deleted: true })
});
const links = component.findAllComponents(RouterLinkStub);
links.length.should.equal(1); // only link is anchor link on version tag
component.findComponent(SubmissionLink).exists().should.be.false;
});
});
});
Expand Down
4 changes: 4 additions & 0 deletions transifex/strings_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,10 @@
"string": "Session",
"developer_comment": "This text appears on its own and is not part of a longer sentence. It may be shown as a title, for example, at the top of the page."
},
"submission": {
"string": "Submission",
"developer_comment": "This text appears on its own and is not part of a longer sentence. It may be shown as a title, for example, at the top of the page."
},
"submissions": {
"string": "Submissions",
"developer_comment": "This text appears on its own and is not part of a longer sentence. It may be shown as a title, for example, at the top of the page."
Expand Down

0 comments on commit b84a874

Please sign in to comment.