Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Wikit Textarea with Codex Textarea component #771

Merged
merged 23 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4dd4db7
Replace Wikit Textarea with Codex Textarea component
guergana Nov 20, 2023
e4e5ff7
Fix v-model and add functionality
guergana Nov 21, 2023
0410cb1
Remove this.form.itemsInput in favor of new v-model syntax
guergana Nov 21, 2023
b62c91c
Fix errors
guergana Nov 21, 2023
9fd7600
Remove trailing comma
guergana Nov 21, 2023
22c83c6
Update browser tests
guergana Nov 21, 2023
9d70229
Update Home.vue
guergana Nov 22, 2023
9aa3703
Update Home.spec.js
guergana Nov 22, 2023
5021f51
Put textarea in a wrapper component
guergana Nov 30, 2023
242bf73
Adjust tests to new TextareaHome component
guergana Nov 30, 2023
6028a8f
Fix linting
guergana Nov 30, 2023
64e9048
Move MAX_NUM_IDS to TextArea component
guergana Dec 4, 2023
54cd3f7
Fix indentation
guergana Dec 4, 2023
97f4f8e
Rename component to ItemIdSearchTextarea
guergana Dec 4, 2023
fcf168c
[WiP] rewrite component using Composition API
guergana Dec 4, 2023
5dffb0c
Commit unsuccesful testing export of i18n :(
guergana Dec 11, 2023
94b4505
Adjust i18n plugin to composition API with useI18n
guergana Dec 13, 2023
fdb98aa
Refactor global variable MAX_NUM_IDS to vue3 format
guergana Dec 13, 2023
ea871ca
Fix typescript errors
guergana Dec 13, 2023
d50dd53
Update HomeState to use the new ValidationError type
guergana Dec 13, 2023
011a249
Add spaces between methods
guergana Dec 14, 2023
35af9ff
Change name of internationalizaton plugin variable
guergana Dec 18, 2023
e6ea197
Remove unneeded options in createI18n plugin
guergana Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions public/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"about-mismatch-finder-description": "The Mismatch Finder shows you data in Wikidata that differs from the data in another database, catalog or website (for example, someone's date of birth in Wikidata doesn't match the corresponding entry in the German National Library's catalog). Mismatches like this need fixing, and the Mismatch Finder helps you to do just that.",
"find-more": "Find out more",
"item-form-title": "Which Items should be checked?",
"item-form-progress-bar-aria-label": "Progress Bar indicating loading state when submittion Check Items",
"item-form-id-input-label": "Please add one Item identifier per line",
"item-form-id-input-placeholder": "For example:\nQ80378\nQ33602\nQ1459\nQ4524",
"item-form-submit": "Check Items",
Expand Down
1 change: 1 addition & 0 deletions public/i18n/qqq.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"about-mismatch-finder-description": "A short text to describe the Mismatch Finder tool",
"find-more": "A call to action for more information",
"item-form-title": "The title of the form that filters Mismatches by Item id",
"item-form-progress-bar-aria-label": "The aria label for screen reader for the Progress Bar indicating loading state when submittion Check Items",
"item-form-id-input-label": "The label for the Item id input",
"item-form-id-input-placeholder": "The placeholder for the Item id input",
"item-form-submit": "The call to action on the Item id form's submit button",
Expand Down
112 changes: 112 additions & 0 deletions resources/js/Components/ItemIdSearchTextarea.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<template>
<cdx-field
:status="validationError ? validationError.type : 'default'"
:messages="validationError ? validationError.message : null"
>
<div class="progress-bar-wrapper">
<cdx-progress-bar v-if="loading" :aria-label="$i18n('item-form-progress-bar-aria-label')" />
</div>
<cdx-text-area
:label="$i18n('item-form-id-input-label')"
:placeholder="$i18n('item-form-id-input-placeholder')"
:rows="8"
:status="validationError ? validationError.type : 'default'"
v-model="textareaInputValue"
/>
</cdx-field>
</template>

<script setup lang="ts">
import { ref, inject } from 'vue';
import { Ref } from 'vue';
import { useI18n } from 'vue-banana-i18n';
import { useStore } from '../store';
import { CdxTextArea, CdxField, CdxProgressBar } from "@wikimedia/codex";
import ValidationError from '../types/ValidationError';

// Run it with compat mode
// https://v3-migration.vuejs.org/breaking-changes/v-model.html
CdxTextArea.compatConfig = {
...CdxTextArea.compatConfig,
COMPONENT_V_MODEL: false,
};

const validationError: Ref<ValidationError> = ref(null);

const messages = useI18n();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!


const store = useStore();
const textareaInputValue = ref(store.lastSearchedIds);

const MAX_NUM_IDS = inject('MAX_NUM_IDS');

defineProps<{loading: boolean}>();

function splitInput(): Array<string> {
return textareaInputValue.value.split( '\n' );
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some spaces are needed in this line and after the next couple of functions. So close together is a bit messy on the eyes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some spaces.


function sanitizeArray(): Array<string> {
// this filter function removes all falsy values
// see: https://stackoverflow.com/a/281335/1619792
return splitInput().filter(x => x);
}

function serializeInput(): string {
return sanitizeArray().join('|');
}

function validate(): void {
validationError.value = null;

const typeError = 'error';

const rules = [{
check: (ids: Array<string>) => ids.length < 1,
type: typeError,
message: { [typeError]: messages.i18n('item-form-error-message-empty') as string }
},
{
check: (ids: Array<string>) => ids.length > (MAX_NUM_IDS as number),
type: typeError,
message: { [typeError]: messages.i18n('item-form-error-message-max', MAX_NUM_IDS) as string }
},
{
check: (ids: Array<string>) => !ids.every(value => /^[Qq]\d+$/.test( value.trim() )),
type: typeError,
message: { [typeError]: messages.i18n('item-form-error-message-invalid') as string }
}];

const sanitized = sanitizeArray();

for(const {check, type, message} of rules){
if(check(sanitized)){
validationError.value = { type, message };
return;
}
}
}

defineExpose({validate, serializeInput, validationError});

</script>

<style lang="scss">

.cdx-field__control {
position: relative;
width: 100%;

.progress-bar-wrapper {
position: absolute;
top: 50%;
width: 100%;

.cdx-progress-bar {
width: 50%;
margin: auto;
}
}
}

</style>
104 changes: 36 additions & 68 deletions resources/js/Pages/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,9 @@
</cdx-button>
</div>
<form id="items-form" @submit.prevent="send">
<text-area
:label="$i18n('item-form-id-input-label')"
:placeholder="$i18n('item-form-id-input-placeholder')"
:rows="8"
<item-id-search-textarea
:loading="loading"
:error="validationError"
v-model="form.itemsInput"
ref="textarea"
/>
<div class="form-buttons">
<cdx-button
Expand All @@ -106,20 +102,15 @@
import { Head as InertiaHead } from '@inertiajs/inertia-vue3';
import { mapState } from 'pinia';
import { useStore } from '../store';
import { TextArea } from '@wmde/wikit-vue-components';
import { CdxDialog, CdxButton, CdxIcon, CdxMessage } from "@wikimedia/codex";
import ItemIdSearchTextarea from '../Components/ItemIdSearchTextarea.vue';
import { cdxIconDie, cdxIconInfo } from '@wikimedia/codex-icons';
import { defineComponent } from 'vue';
import { defineComponent, ref } from 'vue';
import ValidationError from '../types/ValidationError';

interface HomeState {
form: {
itemsInput: string
},
validationError: null|{
type: string,
message: string
},
faqDialog: boolean
validationError: null|ValidationError,
faqDialog: boolean
}

interface ErrorMessages {
Expand All @@ -130,72 +121,37 @@
errors : { [ key : string ] : string }
}

export const MAX_NUM_IDS = 600;

export default defineComponent({
components: {
CdxDialog,
CdxButton,
CdxIcon,
CdxMessage,
InertiaHead,
TextArea,
ItemIdSearchTextarea,
InertiaHead
},
setup() {
const store = useStore();
const textareaInputValue = ref(store.lastSearchedIds);
guergana marked this conversation as resolved.
Show resolved Hide resolved

return {
cdxIconDie,
cdxIconInfo
cdxIconInfo,
textareaInputValue
};
},
methods: {
splitInput: function(): Array<string> {
return this.form.itemsInput.split( '\n' );
},
sanitizeArray: function(): Array<string> {
// this filter function removes all falsy values
// see: https://stackoverflow.com/a/281335/1619792
return this.splitInput().filter(x => x);
},
serializeInput: function(): string {
return this.sanitizeArray().join('|');
},
validate(): void {
this.validationError = null;

const rules = [{
check: (ids: Array<string>) => ids.length < 1,
type: 'warning',
message: this.$i18n('item-form-error-message-empty')
},
{
check: (ids: Array<string>) => ids.length > MAX_NUM_IDS,
type: 'error',
message: this.$i18n('item-form-error-message-max', MAX_NUM_IDS)
},
{
check: (ids: Array<string>) => !ids.every(value => /^[Qq]\d+$/.test( value.trim() )),
type: 'error',
message: this.$i18n('item-form-error-message-invalid')
}];

const sanitized = this.sanitizeArray();

for(const {check, type, message} of rules){
if(check(sanitized)){
this.validationError = { type, message };
return;
}
}
},
send(): void {
this.validate();
(this.$refs.textarea as InstanceType<typeof ItemIdSearchTextarea>).validate();

if(this.validationError) {
if((this.$refs.textarea as InstanceType<typeof ItemIdSearchTextarea>).validationError) {
return;
}
const store = useStore();
store.saveSearchedIds( this.form.itemsInput );
this.$inertia.get( '/results', { ids: this.serializeInput() } );
store.saveSearchedIds( this.textareaInputValue );
this.$inertia.get( '/results',
{ ids: (this.$refs.textarea as InstanceType<typeof ItemIdSearchTextarea>).serializeInput() }
);
},
showRandom(): void {
this.$inertia.get( '/random' );
Expand All @@ -216,11 +172,7 @@
...mapState(useStore, ['loading']),
},
data(): HomeState {
const store = useStore();
return {
form: {
itemsInput: store.lastSearchedIds
},
validationError: null,
faqDialog: false
}
Expand Down Expand Up @@ -272,5 +224,21 @@
.form-buttons {
text-align: end;
}

.cdx-field__control {
position: relative;
width: 100%;

.progress-bar-wrapper {
position: absolute;
top: 50%;
width: 100%;

.cdx-progress-bar {
width: 50%;
margin: auto;
}
}
}
}
</style>
5 changes: 3 additions & 2 deletions resources/js/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import './bootstrap';
import {createApp, h} from 'vue';
import {createPinia} from 'pinia';
import {createInertiaApp} from '@inertiajs/inertia-vue3';
import getI18nMessages, { I18nMessages } from './lib/i18n';
import {createI18n} from 'vue-banana-i18n'
import getI18nMessages from './lib/i18n';
import {createI18n} from 'vue-banana-i18n';
import bubble from './lib/bubble';
import Error from './Pages/Error.vue';
import Layout from './Pages/Layout.vue';
Expand Down Expand Up @@ -36,6 +36,7 @@ import Layout from './Pages/Layout.vue';
.use(i18nPlugin)
.use(pinia)
.use(plugin)
.provide('MAX_NUM_IDS', 600)
.mount(el)
}
});
Expand Down
6 changes: 6 additions & 0 deletions resources/js/types/ValidationError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type ValidationError = {
type: string,
message: { [key : string] : string }
}

export default ValidationError;
4 changes: 2 additions & 2 deletions tests/Browser/ItemsFormTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ public function test_can_submit_list_of_item_ids()
});
}

public function test_empty_item_list_yields_warning()
public function test_empty_item_list_yields_error()
{
$this->browse(function (Browser $browser) {
$browser->visit(new HomePage)
->press('.submit-ids')
->assertSee('Please provide the Item identifiers that should be checked.');

$this->assertStringContainsString(
'--warning',
'--error',
$browser->attribute('@items-input-validation-message', 'class')
);
});
Expand Down
2 changes: 1 addition & 1 deletion tests/Browser/Pages/HomePage.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function elements()
return [
'@form' => '#items-form',
'@items-input' => '@form textarea',
'@items-input-validation-message' => '@form .wikit-TextArea .wikit-ValidationMessage'
'@items-input-validation-message' => '@form .cdx-field__validation-message .cdx-message'
];
}
}
Loading