@yugabytedb/perf-advisor-ui 1.0.160 → 1.0.162

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.
@@ -979,4 +979,153 @@ export interface QueryPlanData {
979
979
  totalTime: number;
980
980
  universeId: string;
981
981
  }
982
+ export declare enum HaMemberRole {
983
+ LEADER = "LEADER",
984
+ FOLLOWER = "FOLLOWER"
985
+ }
986
+ /**
987
+ * Lifecycle state of an HA member. Mirrors {@code HaMember.State} on the backend:
988
+ * <ul>
989
+ * <li>{@code PENDING} - freshly added; bootstrap not started yet.</li>
990
+ * <li>{@code JOINING} - bootstrap streaming in progress; not eligible for promotion.</li>
991
+ * <li>{@code READY} - bootstrap done and change feed caught up; eligible for promotion.</li>
992
+ * <li>{@code FAILED} - bootstrap retry budget exhausted; requires operator to hit the
993
+ * "Retry Bootstrap" action ({@code POST /api/ha/member/bootstrap/restart}) after
994
+ * resolving the underlying cause. Not eligible for promotion.</li>
995
+ * </ul>
996
+ * The Promote button in the members table is disabled for anything other than {@code READY}.
997
+ */
998
+ export declare enum HaMemberLifecycleState {
999
+ PENDING = "PENDING",
1000
+ JOINING = "JOINING",
1001
+ READY = "READY",
1002
+ FAILED = "FAILED",
1003
+ /**
1004
+ * Bootstrap completed cleanly at some point, but one or more CONFIG-class change entries
1005
+ * or bootstrap rows failed to apply locally because of schema drift the follower can't
1006
+ * heal on its own (typically a NOT NULL column on the follower that the newer leader
1007
+ * stopped emitting, or the reverse across an N-1 to N+1 upgrade). The promotion gate
1008
+ * refuses this state unless the operator confirms via the "Force Promote" dialog and
1009
+ * accepts the possibly-lossy handover. Auto-clears back to READY on the next successful
1010
+ * full-or-CONFIG bootstrap.
1011
+ */
1012
+ STALE_CONFIG = "STALE_CONFIG"
1013
+ }
1014
+ export interface HaMemberSpec {
1015
+ uuid: string;
1016
+ paEndpoint: string;
1017
+ isLocal?: boolean;
1018
+ }
1019
+ export interface HaMemberState {
1020
+ uuid: string;
1021
+ paEndpoint: string;
1022
+ role: HaMemberRole;
1023
+ /**
1024
+ * Lifecycle state carried on every {@code GET /api/ha/state} response. Undefined only when
1025
+ * talking to a pre-lifecycle backend - treat as {@code READY} in that case to preserve the
1026
+ * old behavior where every present member was implicitly promotable.
1027
+ */
1028
+ state?: HaMemberLifecycleState | null;
1029
+ lastAppliedSeq: number;
1030
+ lastSeen?: string | null;
1031
+ isLocal: boolean;
1032
+ /**
1033
+ * Number of consecutive failed bootstrap attempts. Zero on a healthy member; non-zero while
1034
+ * the follower is retrying and mid-JOINING. Renders as "N failed attempts" alongside the
1035
+ * state badge in the HA members table. Undefined against pre-retry-tracking backends.
1036
+ */
1037
+ bootstrapAttempts?: number | null;
1038
+ /**
1039
+ * Timestamp of the last bootstrap attempt (success or failure). Combined with the server's
1040
+ * retry interval this lets the UI show "next retry in ~Xm" while a bootstrap is in flight
1041
+ * with a non-zero attempt count.
1042
+ */
1043
+ bootstrapLastAttemptAt?: string | null;
1044
+ /**
1045
+ * Short human-readable reason attached to the most recent bootstrap failure. Present only
1046
+ * while state is JOINING with pending retries or {@code FAILED}. Rendered as a tooltip on
1047
+ * the state badge so operators can triage from the UI without opening server logs.
1048
+ */
1049
+ bootstrapLastError?: string | null;
1050
+ /**
1051
+ * PA release string the peer is currently running, as observed via the {@code X-PA-HA-Version}
1052
+ * wire header (leader-side) or {@code HaChangesResponse.leaderVersion} (follower-side). Null
1053
+ * against pre-V84 backends or on freshly-added members before the first heartbeat has landed.
1054
+ * Rendered in the "PA Version" column of the members table so operators can spot version
1055
+ * drift during a rolling upgrade at a glance; the backend uses it to refuse promotion of a
1056
+ * peer whose version is strictly older than the current leader's (unless force=true).
1057
+ */
1058
+ paVersion?: string | null;
1059
+ /**
1060
+ * Wall-clock timestamp of the READY -> STALE_CONFIG transition on this member. Rendered
1061
+ * in the state cell tooltip so operators can tell "we just noticed this drift" from
1062
+ * "we've been stuck for 15 minutes". Cleared to null when the state auto-clears back to
1063
+ * READY after a successful full-or-CONFIG bootstrap. Null on any member that has not
1064
+ * entered STALE_CONFIG in the current lifecycle.
1065
+ */
1066
+ staleConfigSince?: string | null;
1067
+ }
1068
+ export interface HaState {
1069
+ groupConfigured: boolean;
1070
+ groupUuid?: string | null;
1071
+ currentTerm: number;
1072
+ leaderMemberUuid?: string | null;
1073
+ localMemberUuid?: string | null;
1074
+ members: HaMemberState[];
1075
+ /**
1076
+ * Computed "is this PA currently scraping" bit. Sourced from
1077
+ * {@code HaService.isScrapingEnabled()} on the backend: {@code true} when this PA is not part
1078
+ * of an HA group at all, when it's the LEADER inside one, or when the deployment runs with
1079
+ * {@code yb.cloud.enabled=true}. Exposed for read-only display in the HA page's status card;
1080
+ * the UI does not toggle it directly (the retired {@code POST /api/ha/scraper} endpoint used
1081
+ * to serve that role, but that persistent override was removed once follower-side leave
1082
+ * started wiping leader-owned config).
1083
+ */
1084
+ scraperEnabled: boolean;
1085
+ /**
1086
+ * Cluster key from the local {@code ha_group} row. Present on the admin-token
1087
+ * {@code GET /api/ha/state} surface only - the UI uses it to power the "Copy cluster key"
1088
+ * affordance so operators can add another standby at any time without regenerating the key
1089
+ * and invalidating existing peers. Absent (undefined) when no group is configured.
1090
+ */
1091
+ clusterKey?: string | null;
1092
+ }
1093
+ export declare enum HaGroupMode {
1094
+ ACTIVE = "ACTIVE",
1095
+ STANDBY = "STANDBY"
1096
+ }
1097
+ export interface HaGroupRequest {
1098
+ groupUuid: string;
1099
+ clusterKey: string;
1100
+ members: HaMemberSpec[];
1101
+ initialLeaderUuid?: string | null;
1102
+ term: number;
1103
+ /**
1104
+ * Bootstrap flavor. Defaults to {@link HaGroupMode.ACTIVE} on the backend for backward
1105
+ * compatibility. Use {@link HaGroupMode.STANDBY} to register as a follower - the local PA
1106
+ * fetches the authoritative topology from {@link HaGroupRequest.remoteLeaderEndpoint} before
1107
+ * persisting anything, so it lands on the same {@code groupUuid} / {@code currentTerm} /
1108
+ * leader as the active PA.
1109
+ */
1110
+ mode?: HaGroupMode;
1111
+ /**
1112
+ * Required for {@link HaGroupMode.STANDBY}: base URL of the active PA (e.g.
1113
+ * {@code https://active-pa.example.com:8080}). The backend calls {@code
1114
+ * <remoteLeaderEndpoint>/api/ha/topology} with the shared cluster key at bootstrap; if the
1115
+ * fetch fails the whole {@code POST /api/ha/group} call fails and the standby stays
1116
+ * unconfigured, matching the "no half-configured state" invariant the leader-push flow
1117
+ * relies on. Ignored in {@link HaGroupMode.ACTIVE}.
1118
+ */
1119
+ remoteLeaderEndpoint?: string;
1120
+ }
1121
+ export interface HaPromoteRequest {
1122
+ memberUuid: string;
1123
+ term: number;
1124
+ /**
1125
+ * When true, bypass the promote gates (version-order and STALE_CONFIG). Defaults to false
1126
+ * on the backend if omitted. The UI only sends true after the operator confirms in the
1127
+ * "Force Promote" dialog and accepts the possibly-lossy handover semantics.
1128
+ */
1129
+ force?: boolean;
1130
+ }
982
1131
  export {};
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Result of `useHaStandby`. Kept as a plain object (not a class) so callers can destructure at
3
+ * the point of use without repeated hook fields; the JSDoc on each field is the source of
4
+ * truth for what "standby" means.
5
+ */
6
+ export interface HaStandbyStatus {
7
+ /**
8
+ * `true` iff this PA is currently a FOLLOWER in an HA group. `false` for LEADER and for the
9
+ * (much more common) case of a PA that is not in any HA group at all. Callers should treat
10
+ * `false` as "you are on the correct PA to make mutations" - the primary consumer is the
11
+ * per-page mutation-button disable logic which grays out actions and points operators at
12
+ * the leader when this is `true`.
13
+ *
14
+ * <p>Deliberately conservative: while the initial `/api/ha/state` fetch is in flight (or has
15
+ * errored), we return `false`. Reasoning: (a) blocking every action on a network round-trip
16
+ * would regress every dev/single-node deploy; (b) the server-side {@code
17
+ * HaService.requireLeaderOrStandalone} refuses on the wire anyway, so a UI that "leaks" a
18
+ * click through will still get a 409 with a helpful message, not a silent write. The banner
19
+ * appearing after the fetch resolves is a strictly-better failure mode than the whole app
20
+ * locking up on load.
21
+ */
22
+ isStandby: boolean;
23
+ /**
24
+ * When {@link #isStandby} is `true`, the {@code pa_endpoint} of the current leader as
25
+ * reported by `/api/ha/state`. Null when we can't identify a leader (e.g. group has no
26
+ * leader elected, or the leader row is missing an endpoint). The standby banner uses this
27
+ * to render a "go to <endpoint>" link so operators can jump to the correct PA in one
28
+ * click; button tooltips also embed this string when non-null.
29
+ */
30
+ leaderEndpoint: string | null;
31
+ /** `true` while the underlying HA state fetch has not yet resolved once. */
32
+ isLoading: boolean;
33
+ }
34
+ /**
35
+ * React hook that resolves to the current PA's HA-standby status.
36
+ *
37
+ * <p>Design notes:
38
+ *
39
+ * <ul>
40
+ * <li>Shares the {@code QUERY_KEY.fetchHaState} key with the HA UI page, so on a session
41
+ * where the operator opens both a regular page and the HA UI page we only hit
42
+ * `/api/ha/state` once every 30s (react-query dedupes by key).
43
+ * <li>The 30s refetch interval matches the follower poll cadence: any role change on the
44
+ * server appears in the UI within one poll cycle even without any operator action.
45
+ * <li>Errors during fetch are absorbed: we return {@code isStandby: false} so a temporary
46
+ * network hiccup doesn't lock down mutation controls on a healthy leader.
47
+ * </ul>
48
+ *
49
+ * @param apiUrl Optional API URL prefix (e.g. when this PA is served behind YBA at a
50
+ * non-root path). If omitted, relative `/api/ha/state` is used.
51
+ */
52
+ export declare const useHaStandby: (apiUrl?: string) => HaStandbyStatus;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yugabytedb/perf-advisor-ui",
3
- "version": "1.0.160",
3
+ "version": "1.0.162",
4
4
  "type": "module",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",