Skip to content

Commit a032909

Browse files
coddersjenkins-bot
authored andcommitted
Group statements by statement type in wbui2025
The current wbui2025 (MEX) implementation displays entity statements in a long, undifferentiated list, whereas the existing UI and the wbui2025 design require that Statements and Identifiers are grouped and displayed with a heading section. Update the wbui2025 entity view to group statements by statement type. Bug: T400085 Change-Id: I12fbf4373d5c25ffc1ab2a1553da6e4152cefdbd
1 parent 79c3b26 commit a032909

File tree

7 files changed

+140
-44
lines changed

7 files changed

+140
-44
lines changed

repo/includes/RepoHooks.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ public function onResourceLoaderRegisterModules( $rl ): void {
963963
'styles' => [
964964
'resources/wikibase.wbui2025/wikibase.wbui2025.qualifiers.less',
965965
'resources/wikibase.wbui2025/wikibase.wbui2025.statementDetailView.less',
966+
'resources/wikibase.wbui2025/wikibase.wbui2025.statementSections.less',
966967
'resources/wikibase.wbui2025/wikibase.wbui2025.statementView.less',
967968
'resources/wikibase.wbui2025/wikibase.wbui2025.references.less',
968969
'resources/wikibase.wbui2025/wikibase.wbui2025.mainSnak.less',
@@ -975,9 +976,11 @@ public function onResourceLoaderRegisterModules( $rl ): void {
975976
'resources/wikibase.wbui2025/wikibase.wbui2025.qualifiers.vue',
976977
'resources/wikibase.wbui2025/wikibase.wbui2025.references.vue',
977978
'resources/wikibase.wbui2025/wikibase.wbui2025.statementDetailView.vue',
979+
'resources/wikibase.wbui2025/wikibase.wbui2025.statementSections.vue',
978980
'resources/wikibase.wbui2025/wikibase.wbui2025.statementView.vue',
979981
'resources/wikibase.wbui2025/wikibase.wbui2025.propertyName.vue',
980982
'resources/wikibase.wbui2025/wikibase.wbui2025.mainSnak.vue',
983+
'resources/wikibase.wbui2025/wikibase.wbui2025.utils.js',
981984
'resources/wikibase.wbui2025/store/serverRenderedHtml.js',
982985
],
983986
'dependencies' => [
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import 'mediawiki.skin.variables.less';
2+
3+
.wikibase-wbui2025-statement-section-heading {
4+
h2 {
5+
padding-bottom: 0;
6+
}
7+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<template>
2+
<div class="wikibase-wbui2025-statement-section">
3+
<!-- eslint-disable vue/no-v-html -->
4+
<div class="wikibase-wbui2025-statement-section-heading" v-html="sectionHeadingHtml"></div>
5+
<!-- eslint-enable -->
6+
<div class="wikibase-wbui2025-statement-section-content">
7+
<div
8+
v-for="propertyId in propertyList"
9+
:id="concat( 'wikibase-wbui2025-statementwrapper-', propertyId )"
10+
:key="propertyId">
11+
<wbui2025-statement
12+
:statements="propertyStatementMap[propertyId]"
13+
:property-id="propertyId"
14+
></wbui2025-statement>
15+
</div>
16+
</div>
17+
</div>
18+
</template>
19+
20+
<script>
21+
const { defineComponent } = require( 'vue' );
22+
const { concat } = require( './wikibase.wbui2025.utils.js' );
23+
const Wbui2025Statement = require( './wikibase.wbui2025.statementView.vue' );
24+
25+
// @vue/component
26+
module.exports = exports = defineComponent( {
27+
name: 'WikibaseWbui2025StatementSections',
28+
components: {
29+
Wbui2025Statement
30+
},
31+
props: {
32+
sectionHeadingHtml: {
33+
type: String,
34+
required: true
35+
},
36+
propertyList: {
37+
type: Array,
38+
required: true
39+
},
40+
propertyStatementMap: {
41+
type: Object,
42+
required: true
43+
}
44+
},
45+
setup() {
46+
return {
47+
concat
48+
};
49+
}
50+
} );
51+
</script>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Utility functions for use within Vue templates.
2+
// For SSR elements, duplicate definitions must exist in
3+
// WMDE\VueJsTemplating\App::methods
4+
module.exports = exports = {
5+
concat: ( ...args ) => args.join()
6+
};

view/src/StatementSectionsView.php

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -130,44 +130,79 @@ private function populateQualifierSnakHtml( Statement $statement, array $stateme
130130
}
131131

132132
/**
133-
* @param string $propertyId
134-
* @param Statement[] $statements
133+
* @param StatementList[] $statementsLists
135134
* @param App $app
136135
* @param array &$snakHtmlLookup
137136
* @return string HTML
138137
*/
139-
private function getVueStatementHtml( string $propertyId, array $statements, App $app, array &$snakHtmlLookup ): string {
140-
$statementsData = [];
141-
foreach ( $statements as $statement ) {
142-
$mainSnak = $statement->getMainSnak();
143-
$statementSerializer = $this->serializerFactory->newStatementSerializer();
144-
$statementData = $statementSerializer->serialize( $statement );
145-
146-
$dataType = $this->propertyDataTypeLookup->getDataTypeIdForProperty( $mainSnak->getPropertyId() );
147-
$statementData['mainsnak']['datatype'] = $dataType;
148-
$this->populateReferenceSnakHtml( $statement, $statementData, $snakHtmlLookup );
149-
$this->populateQualifierSnakHtml( $statement, $statementData, $snakHtmlLookup );
150-
if ( array_key_exists( 'hash', $statementData['mainsnak'] ) ) {
151-
$snakHtmlLookup[$statementData['mainsnak']['hash']] = $this->snakFormatter->formatSnak( $mainSnak );
138+
private function getVueStatementHtml( array $statementsLists, App $app, array &$snakHtmlLookup ): string {
139+
$rendered = '';
140+
foreach ( $statementsLists as $key => $statementsList ) {
141+
if ( !is_string( $key ) || !( $statementsList instanceof StatementList ) ) {
142+
throw new InvalidArgumentException(
143+
'$statementLists must be an associative array of StatementList objects'
144+
);
152145
}
153-
$statementsData[] = $statementData;
154-
}
155146

156-
return $app->renderComponent( 'wbui2025-statement', [
157-
'statements' => $statementsData,
158-
'propertyId' => $propertyId,
159-
] );
147+
if ( $key !== 'statements' && $statementsList->isEmpty() ) {
148+
continue;
149+
}
150+
151+
$sectionHeadingHtml = $this->getHtmlForSectionHeading( $key );
152+
$propertyStatementMap = [];
153+
$propertyList = [];
154+
foreach ( $statementsList->getPropertyIds() as $propertyId ) {
155+
$propertyStatements = $statementsList->getByPropertyId( $propertyId )->toArray();
156+
$propertyList[] = $propertyId->getSerialization();
157+
158+
$statementsData = [];
159+
foreach ( $propertyStatements as $statement ) {
160+
$mainSnak = $statement->getMainSnak();
161+
$statementSerializer = $this->serializerFactory->newStatementSerializer();
162+
$statementData = $statementSerializer->serialize( $statement );
163+
164+
$dataType = $this->propertyDataTypeLookup->getDataTypeIdForProperty( $mainSnak->getPropertyId() );
165+
$statementData['mainsnak']['datatype'] = $dataType;
166+
$this->populateReferenceSnakHtml( $statement, $statementData, $snakHtmlLookup );
167+
$this->populateQualifierSnakHtml( $statement, $statementData, $snakHtmlLookup );
168+
if ( array_key_exists( 'hash', $statementData['mainsnak'] ) ) {
169+
$snakHtmlLookup[$statementData['mainsnak']['hash']] = $this->snakFormatter->formatSnak( $mainSnak );
170+
}
171+
$statementsData[] = $statementData;
172+
}
173+
$propertyStatementMap[$propertyId->getSerialization()] = $statementsData;
174+
}
175+
176+
$rendered .= $app->renderComponent( 'wbui2025-statement-sections', [
177+
'sectionHeadingHtml' => $sectionHeadingHtml,
178+
'propertyList' => $propertyList,
179+
'propertyStatementMap' => $propertyStatementMap,
180+
] );
181+
}
182+
return $rendered;
160183
}
161184

162-
/** @return string HTML */
163-
private function getVueStatementsHtml( StatementList $statementsList ): string {
185+
/**
186+
* @param StatementList[] $statementsLists
187+
* @return string HTML
188+
*/
189+
private function getVueStatementsHtml( array $statementsLists ): string {
164190
$snakHtmlLookup = [];
165-
$app = new App( [ 'snakHtml' => function ( $snak ) use ( &$snakHtmlLookup ) {
166-
if ( array_key_exists( $snak['hash'], $snakHtmlLookup ) ) {
167-
return $snakHtmlLookup[$snak['hash']];
168-
}
169-
return '<p>No server-side HTML stored for snak ' . $snak['hash'] . '</p>';
170-
} ] );
191+
$app = new App( [
192+
'snakHtml' => function ( $snak ) use ( &$snakHtmlLookup ) {
193+
if ( array_key_exists( $snak['hash'], $snakHtmlLookup ) ) {
194+
return $snakHtmlLookup[$snak['hash']];
195+
}
196+
return '<p>No server-side HTML stored for snak ' . $snak['hash'] . '</p>';
197+
},
198+
'concat' => function( ...$args ) {
199+
return implode( '', $args );
200+
},
201+
] );
202+
$app->registerComponentTemplate(
203+
'wbui2025-statement-sections',
204+
file_get_contents( __DIR__ . '/../../repo/resources/wikibase.wbui2025/wikibase.wbui2025.statementSections.vue' ),
205+
);
171206
$app->registerComponentTemplate(
172207
'wbui2025-statement',
173208
file_get_contents( __DIR__ . '/../../repo/resources/wikibase.wbui2025/wikibase.wbui2025.statementView.vue' ),
@@ -240,15 +275,9 @@ function ( array $data ): array {
240275
}
241276
);
242277

243-
$rendered = '';
244-
// Renders a placeholder statement element for each property, creating a mounting point for the client-side version
245-
foreach ( $statementsList->getPropertyIds() as $propertyId ) {
246-
$statements = $statementsList->getByPropertyId( $propertyId )->toArray();
247-
$renderedStatement = $this->getVueStatementHtml( $propertyId, $statements, $app, $snakHtmlLookup );
248-
$rendered .= "<div id='wikibase-wbui2025-statementwrapper-$propertyId'>$renderedStatement</div>";
249-
}
250-
251-
return "<div id='wikibase-wbui2025-statementgrouplistview'>$rendered</div>";
278+
return "<div id='wikibase-wbui2025-statementgrouplistview'>" .
279+
$this->getVueStatementHtml( $statementsLists, $app, $snakHtmlLookup ) .
280+
"</div>";
252281
}
253282

254283
/**
@@ -259,10 +288,10 @@ function ( array $data ): array {
259288
* @return string HTML
260289
*/
261290
public function getHtml( StatementList $statementList, bool $wbui2025Ready = false ) {
291+
$statementLists = $this->statementGrouper->groupStatements( $statementList );
262292
if ( $wbui2025Ready && $this->vueStatementsView ) {
263-
return $this->getVueStatementsHtml( $statementList );
293+
return $this->getVueStatementsHtml( $statementLists );
264294
}
265-
$statementLists = $this->statementGrouper->groupStatements( $statementList );
266295
$html = '';
267296

268297
foreach ( $statementLists as $key => $statements ) {

view/tests/phpunit/ItemViewTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use Wikibase\DataModel\Entity\NumericPropertyId;
1111
use Wikibase\DataModel\Serializers\SerializerFactory;
1212
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup;
13-
use Wikibase\DataModel\Services\Statement\Grouper\StatementGrouper;
13+
use Wikibase\DataModel\Services\Statement\Grouper\FilteringStatementGrouper;
1414
use Wikibase\DataModel\Snak\PropertyValueSnak;
1515
use Wikibase\DataModel\Statement\Statement;
1616
use Wikibase\DataModel\Statement\StatementList;
@@ -140,7 +140,7 @@ private function newItemView( $placeholders = [], bool $vueStatementsView = fals
140140
$textProvider = $this->createMock( LocalizedTextProvider::class );
141141
$statementSectionsView = new StatementSectionsView(
142142
$templateFactory,
143-
$this->createConfiguredMock( StatementGrouper::class, [ 'groupStatements' => [] ] ),
143+
new FilteringStatementGrouper( [ 'statement' => null ] ),
144144
$this->createMock( StatementGroupListView::class ),
145145
$textProvider,
146146
$this->createMock( SnakHtmlGenerator::class ),

view/tests/phpunit/PropertyViewTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use Wikibase\DataModel\Entity\Property;
1111
use Wikibase\DataModel\Serializers\SerializerFactory;
1212
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup;
13-
use Wikibase\DataModel\Services\Statement\Grouper\StatementGrouper;
13+
use Wikibase\DataModel\Services\Statement\Grouper\FilteringStatementGrouper;
1414
use Wikibase\DataModel\Snak\PropertyValueSnak;
1515
use Wikibase\DataModel\Statement\Statement;
1616
use Wikibase\DataModel\Statement\StatementList;
@@ -116,7 +116,7 @@ private function newPropertyView( $placeholders = [], bool $vueStatementsView =
116116
$textProvider = $this->createMock( LocalizedTextProvider::class );
117117
$statementSectionsView = new StatementSectionsView(
118118
$templateFactory,
119-
$this->createConfiguredMock( StatementGrouper::class, [ 'groupStatements' => [] ] ),
119+
new FilteringStatementGrouper( [ 'statement' => null ] ),
120120
$this->createMock( StatementGroupListView::class ),
121121
$textProvider,
122122
$this->createMock( SnakHtmlGenerator::class ),

0 commit comments

Comments
 (0)