@quadrel-enterprise-ui/framework 20.6.1 → 20.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/quadrel-enterprise-ui-framework.mjs +155 -110
- package/fesm2022/quadrel-enterprise-ui-framework.mjs.map +1 -1
- package/index.d.ts +76 -46
- package/package.json +1 -1
- package/src/assets/styles/components/_components.all.scss +0 -1
- package/src/assets/styles/components/_components.filter.scss +0 -52
|
@@ -6855,185 +6855,230 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
6855
6855
|
}] });
|
|
6856
6856
|
|
|
6857
6857
|
/**
|
|
6858
|
-
*
|
|
6858
|
+
* Manages a server-sent event (SSE) connection with automatic reconnection and heartbeat monitoring.
|
|
6859
6859
|
*
|
|
6860
|
-
*
|
|
6860
|
+
* All service endpoints — including SSE — must be protected. The connection is therefore secured
|
|
6861
|
+
* via Quadrel Auth (Bearer token) by default. When the access token refreshes, the connection is
|
|
6862
|
+
* transparently rebuilt. Only disable authentication for endpoints that are explicitly public.
|
|
6861
6863
|
*
|
|
6862
|
-
*
|
|
6863
|
-
*
|
|
6864
|
-
* - **
|
|
6865
|
-
* - **
|
|
6864
|
+
* ### Reconnection behavior
|
|
6865
|
+
*
|
|
6866
|
+
* - **Heartbeat timeout**: If no HEARTBEAT event arrives within the expected interval, the service reconnects.
|
|
6867
|
+
* - **401 Unauthorized**: Triggers exponential-backoff reconnection (max 5 attempts, capped at 30 s).
|
|
6868
|
+
* - **Other errors**: Reconnects immediately when the EventSource transitions to CLOSED.
|
|
6869
|
+
*
|
|
6870
|
+
* Existing `observe()` subscriptions are preserved across reconnections.
|
|
6866
6871
|
*
|
|
6867
6872
|
* ### Usage
|
|
6868
6873
|
*
|
|
6869
6874
|
* ```ts
|
|
6870
|
-
*
|
|
6871
|
-
* pushEventsService.connect('http://service-endpint/events');
|
|
6872
|
-
* // or start without authentication in case you don't need:
|
|
6873
|
-
* pushEventsService.connect('http://service-endpint/events', { disableAuthentication: true });
|
|
6874
|
-
*
|
|
6875
|
-
* // Subscribe to the event (Side Effect)
|
|
6876
|
-
* const subscription = pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleEvent(event));
|
|
6875
|
+
* pushEventsService.connect('https://api.example.com/events');
|
|
6877
6876
|
*
|
|
6878
|
-
*
|
|
6879
|
-
* subscription.unsubscribe();
|
|
6877
|
+
* const sub = pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleEvent(event));
|
|
6880
6878
|
*
|
|
6881
|
-
*
|
|
6879
|
+
* sub.unsubscribe();
|
|
6882
6880
|
* pushEventsService.disconnect();
|
|
6883
6881
|
* ```
|
|
6884
6882
|
*/
|
|
6885
6883
|
class QdPushEventsService {
|
|
6886
6884
|
authenticationService = inject('QdAuthenticationService', { optional: true });
|
|
6887
6885
|
_eventSource;
|
|
6888
|
-
|
|
6886
|
+
_subjects = new Map();
|
|
6889
6887
|
_listeners = [];
|
|
6890
|
-
_heartbeatTimeout;
|
|
6891
|
-
_reconnectDelayTime = 10000;
|
|
6892
|
-
_heartbeatReconnectDelayTime = 100;
|
|
6893
6888
|
_accessTokenSub;
|
|
6894
6889
|
_options;
|
|
6890
|
+
_heartbeatTimeout;
|
|
6891
|
+
_heartbeatGracePeriod = 100;
|
|
6892
|
+
_initialHeartbeatTimeout = 10000;
|
|
6895
6893
|
_isUnauthorized = false;
|
|
6894
|
+
_reconnectAttempts = 0;
|
|
6895
|
+
_maxReconnectAttempts = 5;
|
|
6896
|
+
_backoffTimer;
|
|
6896
6897
|
/**
|
|
6897
|
-
*
|
|
6898
|
-
* Automatically reconnects if heartbeat fails or is delayed.
|
|
6899
|
-
* Subscribers are retained across reconnections.
|
|
6898
|
+
* Opens an SSE connection to the given URL.
|
|
6900
6899
|
*
|
|
6901
|
-
*
|
|
6902
|
-
*
|
|
6900
|
+
* With authentication enabled (default), the service subscribes to the `accessToken$` observable
|
|
6901
|
+
* provided by Quadrel Auth and rebuilds the connection whenever the token changes.
|
|
6902
|
+
* No-op if already connected.
|
|
6903
|
+
*
|
|
6904
|
+
* @param url The SSE endpoint URL.
|
|
6905
|
+
* @param options Set `{ disableAuthentication: true }` only for explicitly public endpoints.
|
|
6906
|
+
*
|
|
6907
|
+
* @example
|
|
6908
|
+
* ```ts
|
|
6909
|
+
* // Authenticated (default — requires Quadrel Auth)
|
|
6910
|
+
* pushEventsService.connect('https://api.example.com/events');
|
|
6911
|
+
*
|
|
6912
|
+
* // Without authentication (only for public endpoints)
|
|
6913
|
+
* pushEventsService.connect('https://api.example.com/public-events', { disableAuthentication: true });
|
|
6914
|
+
* ```
|
|
6903
6915
|
*/
|
|
6904
6916
|
connect(url, options) {
|
|
6905
6917
|
if (this.isConnectedOrConnecting())
|
|
6906
6918
|
return;
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
return;
|
|
6911
|
-
}
|
|
6912
|
-
if (this._accessTokenSub)
|
|
6913
|
-
this._accessTokenSub.unsubscribe();
|
|
6914
|
-
this._accessTokenSub = this.authenticationService.accessToken$.subscribe((token) => {
|
|
6915
|
-
this._options = { url, options };
|
|
6916
|
-
this.connectEventSource(url, {
|
|
6917
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
6918
|
-
}, true);
|
|
6919
|
-
});
|
|
6919
|
+
this._options = { url, options };
|
|
6920
|
+
if (options?.disableAuthentication) {
|
|
6921
|
+
this.openEventSource(url);
|
|
6920
6922
|
}
|
|
6921
6923
|
else {
|
|
6922
|
-
this.
|
|
6923
|
-
this.connectEventSource(url);
|
|
6924
|
+
this.connectWithAuth(url);
|
|
6924
6925
|
}
|
|
6925
6926
|
}
|
|
6926
6927
|
/**
|
|
6927
|
-
* Closes the EventSource connection
|
|
6928
|
-
*
|
|
6928
|
+
* Closes the EventSource connection, clears all event listeners, and cancels pending backoff timers.
|
|
6929
|
+
* Subscription subjects are preserved so that a subsequent `connect()` re-attaches them.
|
|
6930
|
+
*
|
|
6931
|
+
* @example
|
|
6932
|
+
* ```ts
|
|
6933
|
+
* pushEventsService.disconnect();
|
|
6934
|
+
* // Subjects survive — a new connect() will re-attach existing observe() subscriptions.
|
|
6935
|
+
* ```
|
|
6929
6936
|
*/
|
|
6930
6937
|
disconnect() {
|
|
6931
6938
|
if (!this._eventSource) {
|
|
6932
6939
|
this.logWarn('No active connection to disconnect.');
|
|
6933
6940
|
return;
|
|
6934
6941
|
}
|
|
6935
|
-
this.
|
|
6942
|
+
if (this._accessTokenSub) {
|
|
6943
|
+
this._accessTokenSub.unsubscribe();
|
|
6944
|
+
this._accessTokenSub = undefined;
|
|
6945
|
+
}
|
|
6946
|
+
if (this._heartbeatTimeout)
|
|
6947
|
+
clearTimeout(this._heartbeatTimeout);
|
|
6948
|
+
if (this._backoffTimer) {
|
|
6949
|
+
clearTimeout(this._backoffTimer);
|
|
6950
|
+
this._backoffTimer = undefined;
|
|
6951
|
+
}
|
|
6952
|
+
this.removeAllListeners();
|
|
6936
6953
|
this._eventSource.close();
|
|
6937
6954
|
}
|
|
6938
6955
|
/**
|
|
6939
|
-
* Returns an Observable
|
|
6940
|
-
*
|
|
6941
|
-
*
|
|
6956
|
+
* Returns an Observable that emits whenever the server sends an event of the given type.
|
|
6957
|
+
*
|
|
6958
|
+
* Lazily registers an EventSource listener on first call per event name.
|
|
6959
|
+
* Returns `NEVER` and logs an error if no connection exists.
|
|
6942
6960
|
*
|
|
6943
|
-
* @param eventName The event type
|
|
6944
|
-
*
|
|
6961
|
+
* @param eventName The SSE event type to listen for.
|
|
6962
|
+
*
|
|
6963
|
+
* @example
|
|
6964
|
+
* ```ts
|
|
6965
|
+
* pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleUpdate(event));
|
|
6966
|
+
* ```
|
|
6945
6967
|
*/
|
|
6946
6968
|
observe(eventName) {
|
|
6947
6969
|
if (!this._eventSource) {
|
|
6948
|
-
this.
|
|
6970
|
+
this.logWarn('Cannot observe events without a connection. Call connect() first.');
|
|
6949
6971
|
return NEVER;
|
|
6950
6972
|
}
|
|
6951
|
-
if (!this.
|
|
6952
|
-
this.
|
|
6953
|
-
this.
|
|
6973
|
+
if (!this._subjects.has(eventName)) {
|
|
6974
|
+
this._subjects.set(eventName, new Subject());
|
|
6975
|
+
this.addListener(eventName, (event) => this._subjects.get(eventName).next(event));
|
|
6954
6976
|
}
|
|
6955
|
-
return this.
|
|
6977
|
+
return this._subjects.get(eventName).asObservable();
|
|
6956
6978
|
}
|
|
6957
6979
|
/**
|
|
6958
|
-
* Removes all listeners and clears all
|
|
6959
|
-
*
|
|
6980
|
+
* Removes all event listeners and clears all subscription subjects. The connection stays open.
|
|
6981
|
+
* Use this to reset all subscriptions without disconnecting the SSE stream.
|
|
6982
|
+
*
|
|
6983
|
+
* @example
|
|
6984
|
+
* ```ts
|
|
6985
|
+
* pushEventsService.unobserveAll();
|
|
6986
|
+
* // Connection remains open, but no events are forwarded until observe() is called again.
|
|
6987
|
+
* ```
|
|
6960
6988
|
*/
|
|
6961
6989
|
unobserveAll() {
|
|
6962
|
-
this.
|
|
6963
|
-
this.
|
|
6990
|
+
this.removeAllListeners();
|
|
6991
|
+
this._subjects.clear();
|
|
6964
6992
|
}
|
|
6965
|
-
/**
|
|
6966
|
-
* Checks if the EventSource is connected or in the process of connecting.
|
|
6967
|
-
*/
|
|
6993
|
+
/** Returns `true` when the EventSource is in state OPEN or CONNECTING. */
|
|
6968
6994
|
isConnectedOrConnecting() {
|
|
6969
6995
|
return (this._eventSource &&
|
|
6970
6996
|
(this._eventSource.readyState === EventSource.OPEN || this._eventSource.readyState === EventSource.CONNECTING));
|
|
6971
6997
|
}
|
|
6972
|
-
|
|
6973
|
-
if (this.
|
|
6998
|
+
connectWithAuth(url) {
|
|
6999
|
+
if (!this.authenticationService) {
|
|
7000
|
+
this.logError("Can't connect to SSE without Quadrel Auth as the connection has to be secured. Please install Quadrel Auth or disable authentication when connecting.");
|
|
6974
7001
|
return;
|
|
6975
|
-
|
|
7002
|
+
}
|
|
7003
|
+
this._accessTokenSub = this.authenticationService.accessToken$.subscribe((token) => {
|
|
7004
|
+
this.openEventSource(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
7005
|
+
});
|
|
7006
|
+
}
|
|
7007
|
+
openEventSource(url, options = {}) {
|
|
7008
|
+
this._isUnauthorized = false;
|
|
7009
|
+
if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED)
|
|
7010
|
+
this._eventSource.close();
|
|
7011
|
+
this._eventSource = new EventSourcePolyfill(url, options);
|
|
7012
|
+
this._eventSource.onerror = (err) => this.handleError(err);
|
|
7013
|
+
this._eventSource.addEventListener('HEARTBEAT', (message) => this.handleHeartbeat(message));
|
|
7014
|
+
if (this._heartbeatTimeout)
|
|
7015
|
+
clearTimeout(this._heartbeatTimeout);
|
|
7016
|
+
this._heartbeatTimeout = setTimeout(() => this.reconnect(), this._initialHeartbeatTimeout);
|
|
7017
|
+
if (this._backoffTimer) {
|
|
7018
|
+
clearTimeout(this._backoffTimer);
|
|
7019
|
+
this._backoffTimer = undefined;
|
|
7020
|
+
}
|
|
7021
|
+
this._listeners = [];
|
|
7022
|
+
this.reattachListeners();
|
|
7023
|
+
}
|
|
7024
|
+
reconnect() {
|
|
7025
|
+
if (this.isConnectedOrConnecting() || this._isUnauthorized)
|
|
6976
7026
|
return;
|
|
6977
7027
|
this.disconnect();
|
|
6978
7028
|
this.connect(this._options.url, this._options.options);
|
|
6979
7029
|
}
|
|
6980
|
-
|
|
6981
|
-
const
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
7030
|
+
handleError(err) {
|
|
7031
|
+
const status = err?.status || err?.target?.status;
|
|
7032
|
+
if (status === 401) {
|
|
7033
|
+
this._isUnauthorized = true;
|
|
7034
|
+
this.logError('SSE connection unauthorized (401):', err);
|
|
7035
|
+
this._eventSource.close();
|
|
7036
|
+
this.scheduleRetry();
|
|
7037
|
+
return;
|
|
7038
|
+
}
|
|
7039
|
+
if (this._eventSource.readyState === EventSource.CLOSED)
|
|
7040
|
+
this.reconnect();
|
|
7041
|
+
this.logError('SSE connection error:', err);
|
|
6988
7042
|
}
|
|
6989
|
-
|
|
6990
|
-
this.
|
|
7043
|
+
scheduleRetry() {
|
|
7044
|
+
if (this._reconnectAttempts >= this._maxReconnectAttempts) {
|
|
7045
|
+
this.logError(`SSE reconnect aborted after ${this._maxReconnectAttempts} failed attempts.`);
|
|
7046
|
+
return;
|
|
7047
|
+
}
|
|
7048
|
+
const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), 30000);
|
|
7049
|
+
this._reconnectAttempts++;
|
|
7050
|
+
this._backoffTimer = setTimeout(() => {
|
|
7051
|
+
this._isUnauthorized = false;
|
|
7052
|
+
this.reconnect();
|
|
7053
|
+
}, delay);
|
|
7054
|
+
}
|
|
7055
|
+
handleHeartbeat(message) {
|
|
7056
|
+
if (this._isUnauthorized)
|
|
7057
|
+
return;
|
|
7058
|
+
if (this._heartbeatTimeout)
|
|
7059
|
+
clearTimeout(this._heartbeatTimeout);
|
|
7060
|
+
this._reconnectAttempts = 0;
|
|
7061
|
+
const interval = JSON.parse(message.data).interval;
|
|
7062
|
+
this._heartbeatTimeout = setTimeout(() => this.reconnect(), interval + this._heartbeatGracePeriod);
|
|
6991
7063
|
}
|
|
6992
|
-
|
|
7064
|
+
addListener(eventName, callback) {
|
|
6993
7065
|
this._eventSource.addEventListener(eventName, callback);
|
|
6994
7066
|
this._listeners.push([eventName, callback]);
|
|
6995
7067
|
}
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
7068
|
+
reattachListeners() {
|
|
7069
|
+
this._subjects.forEach((subject, eventName) => this.addListener(eventName, (event) => subject.next(event)));
|
|
7070
|
+
}
|
|
7071
|
+
removeAllListeners() {
|
|
7072
|
+
if (!this._eventSource)
|
|
6999
7073
|
return;
|
|
7000
|
-
}
|
|
7001
7074
|
this._listeners.forEach(([eventName, callback]) => this._eventSource.removeEventListener(eventName, callback));
|
|
7002
7075
|
this._listeners = [];
|
|
7003
7076
|
}
|
|
7004
7077
|
logWarn(message) {
|
|
7005
|
-
console.warn(`QD-UI |
|
|
7078
|
+
console.warn(`QD-UI | QdPushEvents - ${message}`);
|
|
7006
7079
|
}
|
|
7007
7080
|
logError(message, err) {
|
|
7008
|
-
console.error(`QD-UI |
|
|
7009
|
-
}
|
|
7010
|
-
connectEventSource(url, options = {}, reconnect) {
|
|
7011
|
-
if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED)
|
|
7012
|
-
this._eventSource.close();
|
|
7013
|
-
if (!this._eventSource || this._eventSource.readyState === EventSource.CLOSED || reconnect)
|
|
7014
|
-
this._eventSource = new EventSourcePolyfill(url, options);
|
|
7015
|
-
this._eventSource.onerror = (err) => {
|
|
7016
|
-
const status = err?.status || err?.target?.status;
|
|
7017
|
-
if (status === 401) {
|
|
7018
|
-
this._isUnauthorized = true;
|
|
7019
|
-
this.logError('SSE connection unauthorized (401):', err);
|
|
7020
|
-
this._eventSource.close();
|
|
7021
|
-
return;
|
|
7022
|
-
}
|
|
7023
|
-
if (this._eventSource.readyState === EventSource.CLOSED)
|
|
7024
|
-
this.reconnect();
|
|
7025
|
-
this.logError('SSE connection error:', err);
|
|
7026
|
-
};
|
|
7027
|
-
this._eventSource.addEventListener('HEARTBEAT', (message) => {
|
|
7028
|
-
if (this._isUnauthorized)
|
|
7029
|
-
return;
|
|
7030
|
-
if (this._heartbeatTimeout)
|
|
7031
|
-
clearTimeout(this._heartbeatTimeout);
|
|
7032
|
-
const interval = JSON.parse(message.data).interval;
|
|
7033
|
-
this._heartbeatTimeout = setTimeout(() => this.reconnect(), interval + this._heartbeatReconnectDelayTime);
|
|
7034
|
-
});
|
|
7035
|
-
this._heartbeatTimeout = setTimeout(() => this.reconnect(), this._reconnectDelayTime);
|
|
7036
|
-
this.addEventListenersForExistingSubscriptions();
|
|
7081
|
+
console.error(`QD-UI | QdPushEvents - ${message}`, err);
|
|
7037
7082
|
}
|
|
7038
7083
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
7039
7084
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, providedIn: 'root' });
|
|
@@ -20736,11 +20781,11 @@ class QdFilterItemSelectCategoryComponent {
|
|
|
20736
20781
|
}));
|
|
20737
20782
|
}
|
|
20738
20783
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdFilterItemSelectCategoryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20739
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdFilterItemSelectCategoryComponent, isStandalone: false, selector: "qd-filter-category-select", inputs: { filterId: "filterId", categoryIndex: "categoryIndex", testId: ["data-test-id", "testId"] }, host: { classAttribute: "qd-filter__category-select" }, viewQueries: [{ propertyName: "popoverDirective", first: true, predicate: QdPopoverOnClickDirective, descendants: true }], ngImport: i0, template: "<div\n *ngIf=\"showSelectButton$ | async\"\n [class]=\"buttonClassName\"\n [qdPopoverOnClick]=\"filterLayer\"\n [qdPopoverCloseStrategy]=\"'onOutsideClick'\"\n [qdPopoverStopPropagation]=\"true\"\n [qdPopoverMaxHeight]=\"maxFlyoutHeight\"\n [positionStrategy]=\"positionStrategy\"\n (opened)=\"onLayerOpened()\"\n (closed)=\"onLayerClosed()\"\n [attr.data-test-id]=\"testId + '-select-button'\"\n>\n <qd-icon\n *ngIf=\"!open\"\n [icon]=\"'ctrlDown'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--closed'\"\n [attr.data-test-id]=\"testId + '-closed'\"\n ></qd-icon>\n <qd-icon\n *ngIf=\"open\"\n [icon]=\"'ctrlTop'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--open'\"\n [attr.data-test-id]=\"testId + '-opened'\"\n ></qd-icon>\n\n <div class=\"qd-filter__category-button-caption\">\n <span>\n {{ i18n | translate }}\n </span>\n </div>\n\n <ng-container *ngTemplateOutlet=\"SelectedChip\"></ng-container>\n</div>\n\n<ng-template #filterLayer>\n <div [class]=\"layerContentClassName\">\n <qd-icon\n *ngIf=\"closeButton\"\n [class]=\"'qd-filter__category-layer-close'\"\n (click)=\"closeLayer()\"\n [icon]=\"'timesLargeLight'\"\n [attr.data-test-id]=\"testId + '-layer-close'\"\n ></qd-icon>\n\n <ng-container [ngSwitch]=\"type\">\n <ng-container *ngSwitchCase=\"'multiSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-multi-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-multi-select>\n </ng-container>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'singleSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-single-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n (closeEventEmitter)=\"closeLayer()\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-single-select>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #SelectedChip>\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <!-- TODO: Add tooltip-->\n <qd-chip\n *ngIf=\"item.active\"\n [state]=\"'filter'\"\n [close]=\"true\"\n (closeClickEmitter)=\"close($event)\"\n [data]=\"itemIndex\"\n [data-test-id]=\"testId + '-selected-chip-' + item.item\"\n >{{ item.i18n | translate }}</qd-chip\n >\n </ng-container>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: QdChipComponent, selector: "qd-chip", inputs: ["state", "close", "data", "data-test-id"], outputs: ["closeClickEmitter"] }, { kind: "component", type: QdFilterFormItemsComponent, selector: "qd-filter-form-items", inputs: ["inputFilterValue", "data-test-id"], outputs: ["filterValueChange"] }, { kind: "component", type: QdIconComponent, selector: "qd-icon", inputs: ["icon"] }, { kind: "directive", type: QdPopoverOnClickDirective, selector: "[qdPopoverOnClick]", inputs: ["qdPopoverOnClick", "positionStrategy", "qdPopoverCloseStrategy", "qdPopoverDisabled", "qdPopoverStopPropagation", "qdPopoverBackgroundColor", "qdPopoverMaxHeight", "qdPopoverMinWidth", "qdPopoverMaxWidth", "qdPopoverAutoSize", "qdPopoverEnableKeyControl"], outputs: ["opened", "closed"], exportAs: ["qdPopoverOnClick"] }, { kind: "component", type: QdFilterItemMultiSelectComponent, selector: "qd-filter-item-multi-select", inputs: ["filterId", "categoryIndex", "itemIndex", "data-test-id"] }, { kind: "component", type: QdFilterItemSingleSelectComponent, selector: "qd-filter-item-single-select", inputs: ["filterId", "categoryIndex", "itemIndex", "data-test-id"], outputs: ["closeEventEmitter"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
20784
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdFilterItemSelectCategoryComponent, isStandalone: false, selector: "qd-filter-category-select", inputs: { filterId: "filterId", categoryIndex: "categoryIndex", testId: ["data-test-id", "testId"] }, host: { classAttribute: "qd-filter__category-select" }, viewQueries: [{ propertyName: "popoverDirective", first: true, predicate: QdPopoverOnClickDirective, descendants: true }], ngImport: i0, template: "<div\n *ngIf=\"showSelectButton$ | async\"\n [class]=\"buttonClassName\"\n [qdPopoverOnClick]=\"filterLayer\"\n [qdPopoverCloseStrategy]=\"'onOutsideClick'\"\n [qdPopoverStopPropagation]=\"true\"\n [qdPopoverMaxHeight]=\"maxFlyoutHeight\"\n [positionStrategy]=\"positionStrategy\"\n (opened)=\"onLayerOpened()\"\n (closed)=\"onLayerClosed()\"\n [attr.data-test-id]=\"testId + '-select-button'\"\n>\n <qd-icon\n *ngIf=\"!open\"\n [icon]=\"'ctrlDown'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--closed'\"\n [attr.data-test-id]=\"testId + '-closed'\"\n ></qd-icon>\n <qd-icon\n *ngIf=\"open\"\n [icon]=\"'ctrlTop'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--open'\"\n [attr.data-test-id]=\"testId + '-opened'\"\n ></qd-icon>\n\n <div class=\"qd-filter__category-button-caption\">\n <span>\n {{ i18n | translate }}\n </span>\n </div>\n\n <ng-container *ngTemplateOutlet=\"SelectedChip\"></ng-container>\n</div>\n\n<ng-template #filterLayer>\n <div [class]=\"layerContentClassName\">\n <qd-icon\n *ngIf=\"closeButton\"\n [class]=\"'qd-filter__category-layer-close'\"\n (click)=\"closeLayer()\"\n [icon]=\"'timesLargeLight'\"\n [attr.data-test-id]=\"testId + '-layer-close'\"\n ></qd-icon>\n\n <ng-container [ngSwitch]=\"type\">\n <ng-container *ngSwitchCase=\"'multiSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-multi-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-multi-select>\n </ng-container>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'singleSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-single-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n (closeEventEmitter)=\"closeLayer()\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-single-select>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #SelectedChip>\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <!-- TODO: Add tooltip-->\n <qd-chip\n *ngIf=\"item.active\"\n [state]=\"'filter'\"\n [close]=\"true\"\n (closeClickEmitter)=\"close($event)\"\n [data]=\"itemIndex\"\n [data-test-id]=\"testId + '-selected-chip-' + item.item\"\n >{{ item.i18n | translate }}</qd-chip\n >\n </ng-container>\n</ng-template>\n", styles: ["::ng-deep .qd-filter__category-layer{display:flex;overflow:hidden;min-width:16.25rem;max-width:56.25rem;height:100%;flex-direction:column;padding:1rem 0 0;border:.0625rem solid rgb(151,151,151);background:#fff;box-shadow:#d5d5d5 .125rem .25rem .4375rem}::ng-deep .qd-filter__category-layer .qd-filter-form-items__filter{flex-shrink:0;margin-bottom:0}::ng-deep .qd-filter__category-layer .qd-checkbox__label{display:flex;height:2.5rem}::ng-deep .qd-filter__category-layer .qd-checkbox__indicator,::ng-deep .qd-filter__category-layer .qd-radio-buttons__indicator{transform:translateY(-.0625rem)}::ng-deep .qd-filter__category-layer-items{flex:1;overflow-y:auto}::ng-deep .qd-filter__category-layer-container{position:relative}::ng-deep .qd-filter__category-layer-close{position:absolute;z-index:1;top:1rem;right:1rem;color:#757575;cursor:pointer}::ng-deep .qd-filter__category-layer-close:before{position:absolute;content:\"\";inset:-.5rem}::ng-deep .qd-filter__category-layer-close:hover,::ng-deep .qd-filter__category-layer-close:focus{color:#171717}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: QdChipComponent, selector: "qd-chip", inputs: ["state", "close", "data", "data-test-id"], outputs: ["closeClickEmitter"] }, { kind: "component", type: QdFilterFormItemsComponent, selector: "qd-filter-form-items", inputs: ["inputFilterValue", "data-test-id"], outputs: ["filterValueChange"] }, { kind: "component", type: QdIconComponent, selector: "qd-icon", inputs: ["icon"] }, { kind: "directive", type: QdPopoverOnClickDirective, selector: "[qdPopoverOnClick]", inputs: ["qdPopoverOnClick", "positionStrategy", "qdPopoverCloseStrategy", "qdPopoverDisabled", "qdPopoverStopPropagation", "qdPopoverBackgroundColor", "qdPopoverMaxHeight", "qdPopoverMinWidth", "qdPopoverMaxWidth", "qdPopoverAutoSize", "qdPopoverEnableKeyControl"], outputs: ["opened", "closed"], exportAs: ["qdPopoverOnClick"] }, { kind: "component", type: QdFilterItemMultiSelectComponent, selector: "qd-filter-item-multi-select", inputs: ["filterId", "categoryIndex", "itemIndex", "data-test-id"] }, { kind: "component", type: QdFilterItemSingleSelectComponent, selector: "qd-filter-item-single-select", inputs: ["filterId", "categoryIndex", "itemIndex", "data-test-id"], outputs: ["closeEventEmitter"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
20740
20785
|
}
|
|
20741
20786
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdFilterItemSelectCategoryComponent, decorators: [{
|
|
20742
20787
|
type: Component,
|
|
20743
|
-
args: [{ selector: 'qd-filter-category-select', host: { class: 'qd-filter__category-select' }, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div\n *ngIf=\"showSelectButton$ | async\"\n [class]=\"buttonClassName\"\n [qdPopoverOnClick]=\"filterLayer\"\n [qdPopoverCloseStrategy]=\"'onOutsideClick'\"\n [qdPopoverStopPropagation]=\"true\"\n [qdPopoverMaxHeight]=\"maxFlyoutHeight\"\n [positionStrategy]=\"positionStrategy\"\n (opened)=\"onLayerOpened()\"\n (closed)=\"onLayerClosed()\"\n [attr.data-test-id]=\"testId + '-select-button'\"\n>\n <qd-icon\n *ngIf=\"!open\"\n [icon]=\"'ctrlDown'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--closed'\"\n [attr.data-test-id]=\"testId + '-closed'\"\n ></qd-icon>\n <qd-icon\n *ngIf=\"open\"\n [icon]=\"'ctrlTop'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--open'\"\n [attr.data-test-id]=\"testId + '-opened'\"\n ></qd-icon>\n\n <div class=\"qd-filter__category-button-caption\">\n <span>\n {{ i18n | translate }}\n </span>\n </div>\n\n <ng-container *ngTemplateOutlet=\"SelectedChip\"></ng-container>\n</div>\n\n<ng-template #filterLayer>\n <div [class]=\"layerContentClassName\">\n <qd-icon\n *ngIf=\"closeButton\"\n [class]=\"'qd-filter__category-layer-close'\"\n (click)=\"closeLayer()\"\n [icon]=\"'timesLargeLight'\"\n [attr.data-test-id]=\"testId + '-layer-close'\"\n ></qd-icon>\n\n <ng-container [ngSwitch]=\"type\">\n <ng-container *ngSwitchCase=\"'multiSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-multi-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-multi-select>\n </ng-container>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'singleSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-single-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n (closeEventEmitter)=\"closeLayer()\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-single-select>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #SelectedChip>\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <!-- TODO: Add tooltip-->\n <qd-chip\n *ngIf=\"item.active\"\n [state]=\"'filter'\"\n [close]=\"true\"\n (closeClickEmitter)=\"close($event)\"\n [data]=\"itemIndex\"\n [data-test-id]=\"testId + '-selected-chip-' + item.item\"\n >{{ item.i18n | translate }}</qd-chip\n >\n </ng-container>\n</ng-template>\n" }]
|
|
20788
|
+
args: [{ selector: 'qd-filter-category-select', host: { class: 'qd-filter__category-select' }, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div\n *ngIf=\"showSelectButton$ | async\"\n [class]=\"buttonClassName\"\n [qdPopoverOnClick]=\"filterLayer\"\n [qdPopoverCloseStrategy]=\"'onOutsideClick'\"\n [qdPopoverStopPropagation]=\"true\"\n [qdPopoverMaxHeight]=\"maxFlyoutHeight\"\n [positionStrategy]=\"positionStrategy\"\n (opened)=\"onLayerOpened()\"\n (closed)=\"onLayerClosed()\"\n [attr.data-test-id]=\"testId + '-select-button'\"\n>\n <qd-icon\n *ngIf=\"!open\"\n [icon]=\"'ctrlDown'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--closed'\"\n [attr.data-test-id]=\"testId + '-closed'\"\n ></qd-icon>\n <qd-icon\n *ngIf=\"open\"\n [icon]=\"'ctrlTop'\"\n [class]=\"'qd-filter__category-icon qd-filter__category-icon--open'\"\n [attr.data-test-id]=\"testId + '-opened'\"\n ></qd-icon>\n\n <div class=\"qd-filter__category-button-caption\">\n <span>\n {{ i18n | translate }}\n </span>\n </div>\n\n <ng-container *ngTemplateOutlet=\"SelectedChip\"></ng-container>\n</div>\n\n<ng-template #filterLayer>\n <div [class]=\"layerContentClassName\">\n <qd-icon\n *ngIf=\"closeButton\"\n [class]=\"'qd-filter__category-layer-close'\"\n (click)=\"closeLayer()\"\n [icon]=\"'timesLargeLight'\"\n [attr.data-test-id]=\"testId + '-layer-close'\"\n ></qd-icon>\n\n <ng-container [ngSwitch]=\"type\">\n <ng-container *ngSwitchCase=\"'multiSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-multi-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-multi-select>\n </ng-container>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'singleSelect'\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n [inputFilterValue]=\"filterCategoryValue$ | async\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId\"\n ></qd-filter-form-items>\n\n <div class=\"qd-filter__category-layer-items\">\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <qd-filter-item-single-select\n *ngIf=\"!item.hidden\"\n [categoryIndex]=\"categoryIndex\"\n [itemIndex]=\"itemIndex\"\n (closeEventEmitter)=\"closeLayer()\"\n [filterId]=\"filterId\"\n [data-test-id]=\"testId + '-item-' + itemIndex + '-' + item.item\"\n >\n </qd-filter-item-single-select>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #SelectedChip>\n <ng-container *ngFor=\"let item of items; let itemIndex = index\">\n <!-- TODO: Add tooltip-->\n <qd-chip\n *ngIf=\"item.active\"\n [state]=\"'filter'\"\n [close]=\"true\"\n (closeClickEmitter)=\"close($event)\"\n [data]=\"itemIndex\"\n [data-test-id]=\"testId + '-selected-chip-' + item.item\"\n >{{ item.i18n | translate }}</qd-chip\n >\n </ng-container>\n</ng-template>\n", styles: ["::ng-deep .qd-filter__category-layer{display:flex;overflow:hidden;min-width:16.25rem;max-width:56.25rem;height:100%;flex-direction:column;padding:1rem 0 0;border:.0625rem solid rgb(151,151,151);background:#fff;box-shadow:#d5d5d5 .125rem .25rem .4375rem}::ng-deep .qd-filter__category-layer .qd-filter-form-items__filter{flex-shrink:0;margin-bottom:0}::ng-deep .qd-filter__category-layer .qd-checkbox__label{display:flex;height:2.5rem}::ng-deep .qd-filter__category-layer .qd-checkbox__indicator,::ng-deep .qd-filter__category-layer .qd-radio-buttons__indicator{transform:translateY(-.0625rem)}::ng-deep .qd-filter__category-layer-items{flex:1;overflow-y:auto}::ng-deep .qd-filter__category-layer-container{position:relative}::ng-deep .qd-filter__category-layer-close{position:absolute;z-index:1;top:1rem;right:1rem;color:#757575;cursor:pointer}::ng-deep .qd-filter__category-layer-close:before{position:absolute;content:\"\";inset:-.5rem}::ng-deep .qd-filter__category-layer-close:hover,::ng-deep .qd-filter__category-layer-close:focus{color:#171717}\n"] }]
|
|
20744
20789
|
}], propDecorators: { filterId: [{
|
|
20745
20790
|
type: Input
|
|
20746
20791
|
}], categoryIndex: [{
|