Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -429,86 +429,6 @@ $root: ".widget-datagrid";
display: contents;
}

&-refresh-container {
grid-column: 1 / -1;
padding: 0;
position: relative;
}

&-refresh-indicator {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: var(--border-color-default, #ced0d3);
border: none;
border-radius: 2px;
color: var(--brand-primary, $dg-brand-primary);
height: 4px;
width: 100%;
position: absolute;
left: 0;
right: 0;

&::-webkit-progress-bar {
background-color: transparent;
}

&::-webkit-progress-value {
background-color: currentColor;
transition: all 0.2s;
}

&::-moz-progress-bar {
background-color: currentColor;
transition: all 0.2s;
}

&::-ms-fill {
border: none;
background-color: currentColor;
transition: all 0.2s;
}

&:indeterminate {
background-size: 200% 100%;
background-image: linear-gradient(
to right,
transparent 50%,
currentColor 50%,
currentColor 60%,
transparent 60%,
transparent 71.5%,
currentColor 71.5%,
currentColor 84%,
transparent 84%
);
animation: progress-linear 3s infinite linear;
}

&:indeterminate::-moz-progress-bar {
background-color: transparent;
}

&:indeterminate::-ms-fill {
animation-name: none;
}

@keyframes progress-linear {
0% {
background-size: 200% 100%;
background-position: left -31.25% top 0%;
}
50% {
background-size: 800% 100%;
background-position: left -49% top 0%;
}
100% {
background-size: 400% 100%;
background-position: left -102% top 0%;
}
}
}

&.widget-datagrid-selection-method-click {
.tr.tr-selected .td {
background-color: $dg-grid-selected-row-background;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.mx-refresh-container {
grid-column: 1 / -1;
padding: 0;
position: relative;

&-padding {
padding: var(--spacing-small) 0;
}
}

.mx-refresh-indicator {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: var(--border-color-default, #ced0d3);
border: none;
border-radius: 2px;
color: var(--brand-primary, $dg-brand-primary);
height: 4px;
width: 100%;
position: absolute;
left: 0;
right: 0;

&::-webkit-progress-bar {
background-color: transparent;
}

&::-webkit-progress-value {
background-color: currentColor;
transition: all 0.2s;
}

&::-moz-progress-bar {
background-color: currentColor;
transition: all 0.2s;
}

&::-ms-fill {
border: none;
background-color: currentColor;
transition: all 0.2s;
}

&:indeterminate {
background-size: 200% 100%;
background-image: linear-gradient(
to right,
transparent 50%,
currentColor 50%,
currentColor 60%,
transparent 60%,
transparent 71.5%,
currentColor 71.5%,
currentColor 84%,
transparent 84%
);
animation: progress-linear 3s infinite linear;
}

&:indeterminate::-moz-progress-bar {
background-color: transparent;
}

&:indeterminate::-ms-fill {
animation-name: none;
}

@keyframes progress-linear {
0% {
background-size: 200% 100%;
background-position: left -31.25% top 0%;
}
50% {
background-size: 800% 100%;
background-position: left -49% top 0%;
}
100% {
background-size: 400% 100%;
background-position: left -102% top 0%;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@import "drop-down-sort";
@import "gallery";
@import "gallery-design-properties";
@import "refresh-indicator";
@import "three-state-checkbox";
@import "tree-node";
@import "tree-node-design-properties";

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RefreshIndicator } from "@mendix/widget-plugin-component-kit/RefreshIndicator";
import { Pagination } from "@mendix/widget-plugin-grid/components/Pagination";
import { SelectionStatus } from "@mendix/widget-plugin-grid/selection";
import classNames from "classnames";
Expand Down Expand Up @@ -25,7 +26,6 @@ import { FocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navig
import { observer } from "mobx-react-lite";
import { RowsRenderer } from "./RowsRenderer";
import { GridHeader } from "./GridHeader";
import { RefreshIndicator } from "./RefreshIndicator";

export interface WidgetProps<C extends GridColumn, T extends ObjectItem = ObjectItem> {
CellComponent: CellComponent<C>;
Expand Down
4 changes: 4 additions & 0 deletions packages/pluggableWidgets/gallery-web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- We implemented a new property to show a refresh indicator. With the refresh indicator, any datasource change shows a progress bar on top of Gallery.

## [3.2.0] - 2025-08-18

### Changed
Expand Down
2 changes: 1 addition & 1 deletion packages/pluggableWidgets/gallery-web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@mendix/gallery-web",
"widgetName": "Gallery",
"version": "3.2.0",
"version": "3.3.0",
"description": "A flexible gallery widget that renders columns, rows and layouts.",
"copyright": "© Mendix Technology BV 2025. All rights reserved.",
"license": "Apache-2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ function Preview(props: GalleryPreviewProps): ReactElement {
itemEventsController={itemEventsController}
focusController={focusController}
getPosition={getPositionCallback}
showRefreshIndicator={false}
preview
/>
);
Expand Down
1 change: 1 addition & 0 deletions packages/pluggableWidgets/gallery-web/src/Gallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const Container = observer(function GalleryContainer(props: GalleryContainerProp
focusController={focusController}
getPosition={getPositionCallback}
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
showRefreshIndicator={rootStore.loaderCtrl.showRefreshIndicator}
/>
);
});
Expand Down
4 changes: 4 additions & 0 deletions packages/pluggableWidgets/gallery-web/src/Gallery.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
<caption>Content placeholder</caption>
<description />
</property>
<property key="refreshIndicator" type="boolean" defaultValue="false">
<caption>Show refresh indicator</caption>
<description>Show a refresh indicator when the data is being loaded.</description>
</property>
</propertyGroup>
<propertyGroup caption="Columns">
<property key="desktopItems" type="integer" defaultValue="1">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RefreshIndicator } from "@mendix/widget-plugin-component-kit/RefreshIndicator";
import { Pagination } from "@mendix/widget-plugin-grid/components/Pagination";
import { KeyNavProvider } from "@mendix/widget-plugin-grid/keyboard-navigation/context";
import { FocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/FocusTargetController";
Expand Down Expand Up @@ -51,6 +52,7 @@ export interface GalleryProps<T extends ObjectItem> {
selectHelper: SelectActionHandler;
getPosition: (index: number) => PositionInGrid;
loadMoreButtonCaption?: string;
showRefreshIndicator: boolean;
}

export function Gallery<T extends ObjectItem>(props: GalleryProps<T>): ReactElement {
Expand Down Expand Up @@ -86,6 +88,7 @@ export function Gallery<T extends ObjectItem>(props: GalleryProps<T>): ReactElem
>
<GalleryTopBar>{showTopPagination && pagination}</GalleryTopBar>
{props.showHeader && <GalleryHeader aria-label={props.headerTitle}>{props.header}</GalleryHeader>}
{props.showRefreshIndicator ? <RefreshIndicator className="mx-refresh-container-padding" /> : null}
<GalleryContent
hasMoreItems={props.hasMoreItems}
setPage={props.setPage}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DatasourceController } from "@mendix/widget-plugin-grid/query/DatasourceController";
import { makeObservable, computed } from "mobx";

export class DerivedLoaderController {
constructor(
private datasourceController: DatasourceController,
private refreshIndicator: boolean
) {
makeObservable(this, {
isRefreshing: computed,
showRefreshIndicator: computed
});
}

get isRefreshing(): boolean {
const { isSilentRefresh, isRefreshing } = this.datasourceController;
return !isSilentRefresh && isRefreshing;
}

get showRefreshIndicator(): boolean {
return this.refreshIndicator && this.isRefreshing;
}
}
2 changes: 1 addition & 1 deletion packages/pluggableWidgets/gallery-web/src/package.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<package xmlns="http://www.mendix.com/package/1.0/">
<clientModule name="Gallery" version="3.2.0" xmlns="http://www.mendix.com/clientModule/1.0/">
<clientModule name="Gallery" version="3.3.0" xmlns="http://www.mendix.com/clientModule/1.0/">
<widgetFiles>
<widgetFile path="Gallery.xml" />
</widgetFiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { SortAPI } from "@mendix/widget-plugin-sorting/react/context";
import { SortStoreHost } from "@mendix/widget-plugin-sorting/stores/SortStoreHost";
import { EditableValue, ListValue } from "mendix";
import { PaginationEnum, StateStorageTypeEnum } from "../../typings/GalleryProps";
import { DerivedLoaderController } from "../controllers/DerivedLoaderController";
import { QueryParamsController } from "../controllers/QueryParamsController";
import { ObservableStorage } from "../typings/storage";
import { AttributeStorage } from "./AttributeStorage";
Expand All @@ -31,6 +32,7 @@ interface StaticProps {
stateStorageType: StateStorageTypeEnum;
storeFilters: boolean;
storeSort: boolean;
refreshIndicator: boolean;
}

export type GalleryPropsGate = DerivedPropsGate<DynamicProps>;
Expand All @@ -50,6 +52,7 @@ export class GalleryStore extends BaseControllerHost {
readonly paging: PaginationController;
readonly filterAPI: FilterAPI;
readonly sortAPI: SortAPI;
loaderCtrl: DerivedLoaderController;

constructor(spec: GalleryStoreSpec) {
super();
Expand Down Expand Up @@ -86,6 +89,8 @@ export class GalleryStore extends BaseControllerHost {
host: this._sortHost
};

this.loaderCtrl = new DerivedLoaderController(this._query, spec.refreshIndicator);

new RefreshController(this, {
delay: 0,
query: this._query.derivedQuery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export function createMockGalleryContext(): GalleryRootScope {
onClickTrigger: "single",
stateStorageType: "localStorage",
storeFilters: false,
storeSort: false
storeSort: false,
refreshIndicator: false
};

// Create a proper gate provider and gate
Expand All @@ -72,7 +73,8 @@ export function createMockGalleryContext(): GalleryRootScope {
pageSize: 10,
stateStorageType: "localStorage",
storeFilters: false,
storeSort: false
storeSort: false,
refreshIndicator: false
});

const mockSelectHelper = new SelectActionHandler("None", undefined);
Expand Down Expand Up @@ -148,6 +150,7 @@ export function mockProps(params: Helpers & Mocks = {}): GalleryProps<ObjectItem
header: <input />,
itemEventsController,
focusController,
getPosition: (index: number) => getColumnAndRowBasedOnIndex(3, 3, index)
getPosition: (index: number) => getColumnAndRowBasedOnIndex(3, 3, index),
showRefreshIndicator: false
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface GalleryContainerProps {
itemSelection?: SelectionSingleValue | SelectionMultiValue;
itemSelectionMode: ItemSelectionModeEnum;
content?: ListWidgetValue;
refreshIndicator: boolean;
desktopItems: number;
tabletItems: number;
phoneItems: number;
Expand Down Expand Up @@ -71,6 +72,7 @@ export interface GalleryPreviewProps {
itemSelection: "None" | "Single" | "Multi";
itemSelectionMode: ItemSelectionModeEnum;
content: { widgetCount: number; renderer: ComponentType<{ children: ReactNode; caption?: string }> };
refreshIndicator: boolean;
desktopItems: number | null;
tabletItems: number | null;
phoneItems: number | null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import classNames from "classnames";
import { createElement, ReactElement } from "react";

type RefreshIndicatorProps = {
className?: string;
};

export function RefreshIndicator({ className }: RefreshIndicatorProps): ReactElement {
return (
<div className="tr" role="row">
<div className={classNames("th mx-refresh-container", className)}>
<progress className="mx-refresh-indicator" />
</div>
</div>
);
}
Loading