@oondemand/oon-core-front 0.3.35 → 0.3.36

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/dist/index.js CHANGED
@@ -2979,7 +2979,7 @@ function CoreDocument({ model, label, endpoint, columns, form }) {
2979
2979
  }
2980
2980
 
2981
2981
  // src/components/CorePipeline.tsx
2982
- import { useState as useState11 } from "react";
2982
+ import { useEffect as useEffect7, useRef as useRef2, useState as useState11 } from "react";
2983
2983
  import { Badge as Badge4, Box as Box10, Button as Button9, Flex as Flex8, Heading as Heading5, Input as Input6, NativeSelect as NativeSelect5, Stack as Stack5, Text as Text12 } from "@chakra-ui/react";
2984
2984
  import { useMutation as useMutation3, useQuery as useQuery7, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
2985
2985
 
@@ -3108,6 +3108,19 @@ function groupPipelineActions(actions) {
3108
3108
  };
3109
3109
  }
3110
3110
 
3111
+ // src/components/internal/pipelineBoardScroll.ts
3112
+ var EDGE_TOLERANCE = 2;
3113
+ function resolveHorizontalScrollState(metrics) {
3114
+ const maxScrollLeft = Math.max(0, metrics.scrollWidth - metrics.clientWidth);
3115
+ return {
3116
+ canScrollLeft: metrics.scrollLeft > EDGE_TOLERANCE,
3117
+ canScrollRight: metrics.scrollLeft < maxScrollLeft - EDGE_TOLERANCE
3118
+ };
3119
+ }
3120
+ function pipelineBoardScrollStep(clientWidth) {
3121
+ return Math.max(280, Math.round(clientWidth * 0.75));
3122
+ }
3123
+
3111
3124
  // src/components/CorePipeline.tsx
3112
3125
  import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
3113
3126
  function ticketId(row) {
@@ -3131,6 +3144,10 @@ function workStatusColor(value) {
3131
3144
  if (/revisar|revisao|review/.test(normalized2)) return "#DC2626";
3132
3145
  return "#94A3B8";
3133
3146
  }
3147
+ function PipelineArrowIcon({ direction }) {
3148
+ const path = direction === "left" ? "M12.5 5 7.5 10l5 5" : "m7.5 5 5 5-5 5";
3149
+ return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 20 20", width: "18", height: "18", "aria-hidden": "true", children: /* @__PURE__ */ jsx18("path", { d: path, fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) });
3150
+ }
3134
3151
  function PipelineFilterControl({
3135
3152
  filter,
3136
3153
  value,
@@ -3206,6 +3223,8 @@ function CorePipeline({
3206
3223
  const [selectedTicket, setSelectedTicket] = useState11(null);
3207
3224
  const [creating, setCreating] = useState11(false);
3208
3225
  const [formError, setFormError] = useState11(null);
3226
+ const boardRef = useRef2(null);
3227
+ const [boardScrollState, setBoardScrollState] = useState11({ canScrollLeft: false, canScrollRight: false });
3209
3228
  const effectiveFilters = Object.fromEntries(
3210
3229
  Object.entries(filterValues).filter(([, value]) => value !== "" && value != null)
3211
3230
  );
@@ -3214,6 +3233,23 @@ function CorePipeline({
3214
3233
  queryFn: () => resource.list({ pageSize: 200, ...effectiveFilters }),
3215
3234
  enabled: !!schema && viewMode === "board"
3216
3235
  });
3236
+ useEffect7(() => {
3237
+ if (viewMode !== "board") return void 0;
3238
+ const board = boardRef.current;
3239
+ if (!board) return void 0;
3240
+ const sync = () => setBoardScrollState(resolveHorizontalScrollState(board));
3241
+ sync();
3242
+ board.addEventListener("scroll", sync, { passive: true });
3243
+ window.addEventListener("resize", sync);
3244
+ const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(sync) : void 0;
3245
+ resizeObserver?.observe(board);
3246
+ Array.from(board.children).forEach((child) => resizeObserver?.observe(child));
3247
+ return () => {
3248
+ board.removeEventListener("scroll", sync);
3249
+ window.removeEventListener("resize", sync);
3250
+ resizeObserver?.disconnect();
3251
+ };
3252
+ }, [viewMode, listQuery.data?.results?.length, stages?.length, schema?.fields.length]);
3217
3253
  const invalidate = async () => {
3218
3254
  await Promise.all([
3219
3255
  queryClient.invalidateQueries({ queryKey: ["oon", "pipeline", basePath] }),
@@ -3270,6 +3306,12 @@ function CorePipeline({
3270
3306
  ...defaultStage ? { [stageField]: defaultStage } : {}
3271
3307
  });
3272
3308
  };
3309
+ const scrollBoard = (direction) => {
3310
+ const board = boardRef.current;
3311
+ if (!board) return;
3312
+ const step = pipelineBoardScrollStep(board.clientWidth);
3313
+ board.scrollBy({ left: direction === "left" ? -step : step, behavior: "smooth" });
3314
+ };
3273
3315
  const renderModalAction = (action, index) => selectedTicket ? /* @__PURE__ */ jsx18(
3274
3316
  CoreRowAction,
3275
3317
  {
@@ -3345,69 +3387,143 @@ function CorePipeline({
3345
3387
  setSelectedTicket(row);
3346
3388
  }
3347
3389
  }
3348
- ) : /* @__PURE__ */ jsx18(Flex8, { gap: 4, align: "stretch", overflowX: "auto", pb: 3, minH: "420px", children: Array.from(byStage.entries()).map(([stageId, items]) => {
3349
- const stageLabel = resolvedStages.find((stage) => stage.id === stageId)?.label ?? (stageId || "Sem etapa");
3350
- return /* @__PURE__ */ jsxs13(Box10, { minW: "300px", maxW: "340px", flex: "1 0 300px", bg: "#E8ECEF", borderRadius: "12px", p: 3, borderWidth: "1px", borderColor: "#DDE3E7", children: [
3351
- /* @__PURE__ */ jsxs13(Flex8, { align: "center", justify: "space-between", mb: 3, px: 1, children: [
3352
- /* @__PURE__ */ jsx18(Text12, { fontWeight: "700", fontSize: "12px", color: "#33434C", textTransform: "uppercase", letterSpacing: "0.03em", children: stageLabel }),
3353
- /* @__PURE__ */ jsx18(Badge4, { colorPalette: "brand", variant: "solid", borderRadius: "full", minW: "24px", justifyContent: "center", children: items.length })
3354
- ] }),
3355
- /* @__PURE__ */ jsx18(Stack5, { gap: 2, children: items.length === 0 ? /* @__PURE__ */ jsx18(Box10, { borderWidth: "1px", borderStyle: "dashed", borderColor: "#C8D0D5", borderRadius: "10px", p: 5, textAlign: "center", children: /* @__PURE__ */ jsx18(Text12, { fontSize: "12px", color: "gray.500", children: "Nenhum ticket nesta etapa." }) }) : items.map((row, index) => {
3356
- const ticketTitle = formatCell(row[resolvedTitleField], "string");
3357
- return /* @__PURE__ */ jsxs13(
3358
- Button9,
3359
- {
3360
- type: "button",
3361
- variant: "plain",
3362
- display: "block",
3363
- w: "100%",
3364
- h: "auto",
3365
- minH: "auto",
3366
- p: 3,
3367
- bg: "white",
3368
- borderRadius: "10px",
3369
- borderWidth: "1px",
3370
- borderColor: "#DDE3E7",
3371
- boxShadow: "0 3px 10px rgba(7, 38, 46, 0.05)",
3372
- textAlign: "left",
3373
- whiteSpace: "normal",
3374
- "aria-label": `Abrir ticket ${ticketTitle}`,
3375
- onClick: () => {
3376
- setFormError(null);
3377
- setCreating(false);
3378
- setSelectedTicket(row);
3379
- },
3380
- _hover: { borderColor: "brand.300", transform: "translateY(-1px)", boxShadow: "0 7px 18px rgba(7, 38, 46, 0.09)" },
3381
- children: [
3382
- /* @__PURE__ */ jsxs13(Flex8, { align: "flex-start", justify: "space-between", gap: "8px", mb: 2, children: [
3383
- /* @__PURE__ */ jsx18(Text12, { fontSize: "13px", fontWeight: "700", color: "#24323A", lineClamp: 2, children: ticketTitle }),
3384
- /* @__PURE__ */ jsx18(
3385
- Box10,
3386
- {
3387
- as: "span",
3388
- title: `Status da atividade: ${String(row[workStatusField] ?? "N\xE3o informado")}`,
3389
- "aria-label": `Status da atividade: ${String(row[workStatusField] ?? "N\xE3o informado")}`,
3390
- flex: "0 0 auto",
3391
- w: "10px",
3392
- h: "10px",
3393
- mt: "4px",
3394
- borderRadius: "full",
3395
- bg: workStatusColor(row[workStatusField]),
3396
- boxShadow: "0 0 0 3px white, 0 0 0 4px #E2E8F0"
3397
- }
3398
- )
3399
- ] }),
3400
- /* @__PURE__ */ jsx18(Stack5, { gap: 1, children: detailFields.map((field) => /* @__PURE__ */ jsxs13(Flex8, { gap: 2, align: "baseline", justify: "space-between", children: [
3401
- /* @__PURE__ */ jsx18(Text12, { fontSize: "10px", color: "gray.500", textTransform: "uppercase", letterSpacing: "0.03em", children: fieldLabel(field) }),
3402
- /* @__PURE__ */ jsx18(Text12, { fontSize: "11px", color: "#46545C", fontWeight: "500", textAlign: "right", lineClamp: 1, children: formatCell(row[field.name], field.kind) })
3403
- ] }, field.name)) })
3404
- ]
3405
- },
3406
- ticketId(row) ?? index
3407
- );
3408
- }) })
3409
- ] }, stageId);
3410
- }) }),
3390
+ ) : /* @__PURE__ */ jsxs13(Box10, { position: "relative", children: [
3391
+ /* @__PURE__ */ jsx18(
3392
+ Flex8,
3393
+ {
3394
+ ref: boardRef,
3395
+ "data-oon-pipeline-board": "true",
3396
+ gap: 4,
3397
+ align: "stretch",
3398
+ overflowX: "auto",
3399
+ overflowY: "auto",
3400
+ h: "clamp(420px, calc(100vh - 250px), 760px)",
3401
+ minH: "420px",
3402
+ pb: "18px",
3403
+ pr: "2px",
3404
+ scrollBehavior: "smooth",
3405
+ scrollbarGutter: "stable both-edges",
3406
+ overscrollBehaviorX: "contain",
3407
+ children: Array.from(byStage.entries()).map(([stageId, items]) => {
3408
+ const stageLabel = resolvedStages.find((stage) => stage.id === stageId)?.label ?? (stageId || "Sem etapa");
3409
+ return /* @__PURE__ */ jsxs13(Box10, { minW: "300px", maxW: "340px", flex: "1 0 300px", bg: "#E8ECEF", borderRadius: "12px", p: 3, borderWidth: "1px", borderColor: "#DDE3E7", children: [
3410
+ /* @__PURE__ */ jsxs13(Flex8, { align: "center", justify: "space-between", mb: 3, px: 1, children: [
3411
+ /* @__PURE__ */ jsx18(Text12, { fontWeight: "700", fontSize: "12px", color: "#33434C", textTransform: "uppercase", letterSpacing: "0.03em", children: stageLabel }),
3412
+ /* @__PURE__ */ jsx18(Badge4, { colorPalette: "brand", variant: "solid", borderRadius: "full", minW: "24px", justifyContent: "center", children: items.length })
3413
+ ] }),
3414
+ /* @__PURE__ */ jsx18(Stack5, { gap: 2, children: items.length === 0 ? /* @__PURE__ */ jsx18(Box10, { borderWidth: "1px", borderStyle: "dashed", borderColor: "#C8D0D5", borderRadius: "10px", p: 5, textAlign: "center", children: /* @__PURE__ */ jsx18(Text12, { fontSize: "12px", color: "gray.500", children: "Nenhum ticket nesta etapa." }) }) : items.map((row, index) => {
3415
+ const ticketTitle = formatCell(row[resolvedTitleField], "string");
3416
+ return /* @__PURE__ */ jsxs13(
3417
+ Button9,
3418
+ {
3419
+ type: "button",
3420
+ variant: "plain",
3421
+ display: "block",
3422
+ w: "100%",
3423
+ h: "auto",
3424
+ minH: "auto",
3425
+ p: 3,
3426
+ bg: "white",
3427
+ borderRadius: "10px",
3428
+ borderWidth: "1px",
3429
+ borderColor: "#DDE3E7",
3430
+ boxShadow: "0 3px 10px rgba(7, 38, 46, 0.05)",
3431
+ textAlign: "left",
3432
+ whiteSpace: "normal",
3433
+ "aria-label": `Abrir ticket ${ticketTitle}`,
3434
+ onClick: () => {
3435
+ setFormError(null);
3436
+ setCreating(false);
3437
+ setSelectedTicket(row);
3438
+ },
3439
+ _hover: { borderColor: "brand.300", transform: "translateY(-1px)", boxShadow: "0 7px 18px rgba(7, 38, 46, 0.09)" },
3440
+ children: [
3441
+ /* @__PURE__ */ jsxs13(Flex8, { align: "flex-start", justify: "space-between", gap: "8px", mb: 2, children: [
3442
+ /* @__PURE__ */ jsx18(Text12, { fontSize: "13px", fontWeight: "700", color: "#24323A", lineClamp: 2, children: ticketTitle }),
3443
+ /* @__PURE__ */ jsx18(
3444
+ Box10,
3445
+ {
3446
+ as: "span",
3447
+ title: `Status da atividade: ${String(row[workStatusField] ?? "N\xE3o informado")}`,
3448
+ "aria-label": `Status da atividade: ${String(row[workStatusField] ?? "N\xE3o informado")}`,
3449
+ flex: "0 0 auto",
3450
+ w: "10px",
3451
+ h: "10px",
3452
+ mt: "4px",
3453
+ borderRadius: "full",
3454
+ bg: workStatusColor(row[workStatusField]),
3455
+ boxShadow: "0 0 0 3px white, 0 0 0 4px #E2E8F0"
3456
+ }
3457
+ )
3458
+ ] }),
3459
+ /* @__PURE__ */ jsx18(Stack5, { gap: 1, children: detailFields.map((field) => /* @__PURE__ */ jsxs13(Flex8, { gap: 2, align: "baseline", justify: "space-between", children: [
3460
+ /* @__PURE__ */ jsx18(Text12, { fontSize: "10px", color: "gray.500", textTransform: "uppercase", letterSpacing: "0.03em", children: fieldLabel(field) }),
3461
+ /* @__PURE__ */ jsx18(Text12, { fontSize: "11px", color: "#46545C", fontWeight: "500", textAlign: "right", lineClamp: 1, children: formatCell(row[field.name], field.kind) })
3462
+ ] }, field.name)) })
3463
+ ]
3464
+ },
3465
+ ticketId(row) ?? index
3466
+ );
3467
+ }) })
3468
+ ] }, stageId);
3469
+ })
3470
+ }
3471
+ ),
3472
+ /* @__PURE__ */ jsx18(
3473
+ Button9,
3474
+ {
3475
+ type: "button",
3476
+ "aria-label": "Deslizar quadro para a esquerda",
3477
+ title: "Deslizar para a esquerda",
3478
+ position: "absolute",
3479
+ left: "8px",
3480
+ top: "50%",
3481
+ transform: "translateY(-50%)",
3482
+ zIndex: 3,
3483
+ minW: "34px",
3484
+ w: "34px",
3485
+ h: "34px",
3486
+ p: 0,
3487
+ borderRadius: "full",
3488
+ variant: "outline",
3489
+ bg: "rgba(255,255,255,.96)",
3490
+ borderColor: "#CBD5E1",
3491
+ boxShadow: "0 5px 16px rgba(15,23,42,.16)",
3492
+ disabled: !boardScrollState.canScrollLeft,
3493
+ onClick: () => scrollBoard("left"),
3494
+ _hover: { bg: "white", borderColor: "brand.400" },
3495
+ _disabled: { opacity: 0.25, cursor: "not-allowed" },
3496
+ children: /* @__PURE__ */ jsx18(PipelineArrowIcon, { direction: "left" })
3497
+ }
3498
+ ),
3499
+ /* @__PURE__ */ jsx18(
3500
+ Button9,
3501
+ {
3502
+ type: "button",
3503
+ "aria-label": "Deslizar quadro para a direita",
3504
+ title: "Deslizar para a direita",
3505
+ position: "absolute",
3506
+ right: "8px",
3507
+ top: "50%",
3508
+ transform: "translateY(-50%)",
3509
+ zIndex: 3,
3510
+ minW: "34px",
3511
+ w: "34px",
3512
+ h: "34px",
3513
+ p: 0,
3514
+ borderRadius: "full",
3515
+ variant: "outline",
3516
+ bg: "rgba(255,255,255,.96)",
3517
+ borderColor: "#CBD5E1",
3518
+ boxShadow: "0 5px 16px rgba(15,23,42,.16)",
3519
+ disabled: !boardScrollState.canScrollRight,
3520
+ onClick: () => scrollBoard("right"),
3521
+ _hover: { bg: "white", borderColor: "brand.400" },
3522
+ _disabled: { opacity: 0.25, cursor: "not-allowed" },
3523
+ children: /* @__PURE__ */ jsx18(PipelineArrowIcon, { direction: "right" })
3524
+ }
3525
+ )
3526
+ ] }),
3411
3527
  selectedTicket && ticketModal && ticketModal.enabled !== false ? /* @__PURE__ */ jsx18(
3412
3528
  CoreDetailModal,
3413
3529
  {
@@ -4212,7 +4328,7 @@ function LoginPage({ app }) {
4212
4328
  }
4213
4329
 
4214
4330
  // src/security/ActivationPage.tsx
4215
- import { useEffect as useEffect7, useState as useState13 } from "react";
4331
+ import { useEffect as useEffect8, useState as useState13 } from "react";
4216
4332
  import { Box as Box19, Button as Button14, Heading as Heading11, Input as Input8, Text as Text21, VStack as VStack3 } from "@chakra-ui/react";
4217
4333
  import { Fragment as Fragment6, jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
4218
4334
  function encodeBasicCredentials2(email, password) {
@@ -4239,7 +4355,7 @@ function ActivationPage() {
4239
4355
  const [devResult, setDevResult] = useState13(null);
4240
4356
  const [error, setError] = useState13(null);
4241
4357
  const [submitting, setSubmitting] = useState13(false);
4242
- useEffect7(() => {
4358
+ useEffect8(() => {
4243
4359
  http.get("/ativacao/configuracao").then((response) => {
4244
4360
  setConfig(response.data);
4245
4361
  setGlobal(response.data.defaults || {});
@@ -4247,7 +4363,7 @@ function ActivationPage() {
4247
4363
  () => setError("N\xE3o foi poss\xEDvel carregar a configura\xE7\xE3o de ativa\xE7\xE3o.")
4248
4364
  );
4249
4365
  }, [http]);
4250
- useEffect7(() => {
4366
+ useEffect8(() => {
4251
4367
  if (activation.status === "active") {
4252
4368
  window.location.replace("/login");
4253
4369
  }