@gbdx/devis 1.0.0 → 1.0.1

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.
@@ -28482,104 +28482,120 @@ const createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
28482
28482
  * This source code is licensed under the MIT license.
28483
28483
  * See the LICENSE file in the root directory of this source tree.
28484
28484
  */
28485
- const __iconNode$c = [["path", { "d": "M13 3l0 7l6 0l-8 11l0 -7l-6 0l8 -11", "key": "svg-0" }]];
28486
- const IconBolt = createReactComponent("outline", "bolt", "Bolt", __iconNode$c);
28485
+ const __iconNode$e = [["path", { "d": "M13 3l0 7l6 0l-8 11l0 -7l-6 0l8 -11", "key": "svg-0" }]];
28486
+ const IconBolt = createReactComponent("outline", "bolt", "Bolt", __iconNode$e);
28487
28487
  /**
28488
28488
  * @license @tabler/icons-react v3.44.0 - MIT
28489
28489
  *
28490
28490
  * This source code is licensed under the MIT license.
28491
28491
  * See the LICENSE file in the root directory of this source tree.
28492
28492
  */
28493
- const __iconNode$b = [["path", { "d": "M16 3v18l4 -2.5v-13l-4 -2.5", "key": "svg-0" }], ["path", { "d": "M9.165 13.903l-4.165 3.597l-2 -1l4.333 -4.5m1.735 -1.802l6.932 -7.198v5l-4.795 4.141", "key": "svg-1" }], ["path", { "d": "M16 16.5l-11 -10l-2 1l13 13.5", "key": "svg-2" }]];
28494
- const IconBrandVscode = createReactComponent("outline", "brand-vscode", "BrandVscode", __iconNode$b);
28493
+ const __iconNode$d = [["path", { "d": "M16 3v18l4 -2.5v-13l-4 -2.5", "key": "svg-0" }], ["path", { "d": "M9.165 13.903l-4.165 3.597l-2 -1l4.333 -4.5m1.735 -1.802l6.932 -7.198v5l-4.795 4.141", "key": "svg-1" }], ["path", { "d": "M16 16.5l-11 -10l-2 1l13 13.5", "key": "svg-2" }]];
28494
+ const IconBrandVscode = createReactComponent("outline", "brand-vscode", "BrandVscode", __iconNode$d);
28495
28495
  /**
28496
28496
  * @license @tabler/icons-react v3.44.0 - MIT
28497
28497
  *
28498
28498
  * This source code is licensed under the MIT license.
28499
28499
  * See the LICENSE file in the root directory of this source tree.
28500
28500
  */
28501
- const __iconNode$a = [["path", { "d": "M6 9l6 6l6 -6", "key": "svg-0" }]];
28502
- const IconChevronDown = createReactComponent("outline", "chevron-down", "ChevronDown", __iconNode$a);
28501
+ const __iconNode$c = [["path", { "d": "M6 9l6 6l6 -6", "key": "svg-0" }]];
28502
+ const IconChevronDown = createReactComponent("outline", "chevron-down", "ChevronDown", __iconNode$c);
28503
28503
  /**
28504
28504
  * @license @tabler/icons-react v3.44.0 - MIT
28505
28505
  *
28506
28506
  * This source code is licensed under the MIT license.
28507
28507
  * See the LICENSE file in the root directory of this source tree.
28508
28508
  */
28509
- const __iconNode$9 = [["path", { "d": "M14 3v4a1 1 0 0 0 1 1h4", "key": "svg-0" }], ["path", { "d": "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2", "key": "svg-1" }], ["path", { "d": "M9 9l1 0", "key": "svg-2" }], ["path", { "d": "M9 13l6 0", "key": "svg-3" }], ["path", { "d": "M9 17l6 0", "key": "svg-4" }]];
28510
- const IconFileText = createReactComponent("outline", "file-text", "FileText", __iconNode$9);
28509
+ const __iconNode$b = [["path", { "d": "M6 15l6 -6l6 6", "key": "svg-0" }]];
28510
+ const IconChevronUp = createReactComponent("outline", "chevron-up", "ChevronUp", __iconNode$b);
28511
28511
  /**
28512
28512
  * @license @tabler/icons-react v3.44.0 - MIT
28513
28513
  *
28514
28514
  * This source code is licensed under the MIT license.
28515
28515
  * See the LICENSE file in the root directory of this source tree.
28516
28516
  */
28517
- const __iconNode$8 = [["path", { "d": "M5 19l2.757 -7.351a1 1 0 0 1 .936 -.649h12.307a1 1 0 0 1 .986 1.164l-.996 5.211a2 2 0 0 1 -1.964 1.625h-14.026a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2h4l3 3h7a2 2 0 0 1 2 2v2", "key": "svg-0" }]];
28518
- const IconFolderOpen = createReactComponent("outline", "folder-open", "FolderOpen", __iconNode$8);
28517
+ const __iconNode$a = [["path", { "d": "M14 3v4a1 1 0 0 0 1 1h4", "key": "svg-0" }], ["path", { "d": "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2", "key": "svg-1" }], ["path", { "d": "M9 9l1 0", "key": "svg-2" }], ["path", { "d": "M9 13l6 0", "key": "svg-3" }], ["path", { "d": "M9 17l6 0", "key": "svg-4" }]];
28518
+ const IconFileText = createReactComponent("outline", "file-text", "FileText", __iconNode$a);
28519
28519
  /**
28520
28520
  * @license @tabler/icons-react v3.44.0 - MIT
28521
28521
  *
28522
28522
  * This source code is licensed under the MIT license.
28523
28523
  * See the LICENSE file in the root directory of this source tree.
28524
28524
  */
28525
- const __iconNode$7 = [["path", { "d": "M12 19h-7a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2h4l3 3h7a2 2 0 0 1 2 2v3.5", "key": "svg-0" }], ["path", { "d": "M16 19h6", "key": "svg-1" }], ["path", { "d": "M19 16v6", "key": "svg-2" }]];
28526
- const IconFolderPlus = createReactComponent("outline", "folder-plus", "FolderPlus", __iconNode$7);
28525
+ const __iconNode$9 = [["path", { "d": "M5 19l2.757 -7.351a1 1 0 0 1 .936 -.649h12.307a1 1 0 0 1 .986 1.164l-.996 5.211a2 2 0 0 1 -1.964 1.625h-14.026a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2h4l3 3h7a2 2 0 0 1 2 2v2", "key": "svg-0" }]];
28526
+ const IconFolderOpen = createReactComponent("outline", "folder-open", "FolderOpen", __iconNode$9);
28527
28527
  /**
28528
28528
  * @license @tabler/icons-react v3.44.0 - MIT
28529
28529
  *
28530
28530
  * This source code is licensed under the MIT license.
28531
28531
  * See the LICENSE file in the root directory of this source tree.
28532
28532
  */
28533
- const __iconNode$6 = [["path", { "d": "M4 6l16 0", "key": "svg-0" }], ["path", { "d": "M4 12l16 0", "key": "svg-1" }], ["path", { "d": "M4 18l16 0", "key": "svg-2" }]];
28534
- const IconMenu2 = createReactComponent("outline", "menu-2", "Menu2", __iconNode$6);
28533
+ const __iconNode$8 = [["path", { "d": "M12 19h-7a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2h4l3 3h7a2 2 0 0 1 2 2v3.5", "key": "svg-0" }], ["path", { "d": "M16 19h6", "key": "svg-1" }], ["path", { "d": "M19 16v6", "key": "svg-2" }]];
28534
+ const IconFolderPlus = createReactComponent("outline", "folder-plus", "FolderPlus", __iconNode$8);
28535
28535
  /**
28536
28536
  * @license @tabler/icons-react v3.44.0 - MIT
28537
28537
  *
28538
28538
  * This source code is licensed under the MIT license.
28539
28539
  * See the LICENSE file in the root directory of this source tree.
28540
28540
  */
28541
- const __iconNode$5 = [["path", { "d": "M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454l0 .008", "key": "svg-0" }]];
28542
- const IconMoon = createReactComponent("outline", "moon", "Moon", __iconNode$5);
28541
+ const __iconNode$7 = [["path", { "d": "M4 6l16 0", "key": "svg-0" }], ["path", { "d": "M4 12l16 0", "key": "svg-1" }], ["path", { "d": "M4 18l16 0", "key": "svg-2" }]];
28542
+ const IconMenu2 = createReactComponent("outline", "menu-2", "Menu2", __iconNode$7);
28543
28543
  /**
28544
28544
  * @license @tabler/icons-react v3.44.0 - MIT
28545
28545
  *
28546
28546
  * This source code is licensed under the MIT license.
28547
28547
  * See the LICENSE file in the root directory of this source tree.
28548
28548
  */
28549
- const __iconNode$4 = [["path", { "d": "M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4", "key": "svg-0" }], ["path", { "d": "M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4", "key": "svg-1" }]];
28550
- const IconRefresh = createReactComponent("outline", "refresh", "Refresh", __iconNode$4);
28549
+ const __iconNode$6 = [["path", { "d": "M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454l0 .008", "key": "svg-0" }]];
28550
+ const IconMoon = createReactComponent("outline", "moon", "Moon", __iconNode$6);
28551
28551
  /**
28552
28552
  * @license @tabler/icons-react v3.44.0 - MIT
28553
28553
  *
28554
28554
  * This source code is licensed under the MIT license.
28555
28555
  * See the LICENSE file in the root directory of this source tree.
28556
28556
  */
28557
- const __iconNode$3 = [["path", { "d": "M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0", "key": "svg-0" }], ["path", { "d": "M21 21l-6 -6", "key": "svg-1" }]];
28558
- const IconSearch = createReactComponent("outline", "search", "Search", __iconNode$3);
28557
+ const __iconNode$5 = [["path", { "d": "M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4", "key": "svg-0" }], ["path", { "d": "M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4", "key": "svg-1" }]];
28558
+ const IconRefresh = createReactComponent("outline", "refresh", "Refresh", __iconNode$5);
28559
28559
  /**
28560
28560
  * @license @tabler/icons-react v3.44.0 - MIT
28561
28561
  *
28562
28562
  * This source code is licensed under the MIT license.
28563
28563
  * See the LICENSE file in the root directory of this source tree.
28564
28564
  */
28565
- const __iconNode$2 = [["path", { "d": "M8 12a4 4 0 1 0 8 0a4 4 0 1 0 -8 0", "key": "svg-0" }], ["path", { "d": "M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7", "key": "svg-1" }]];
28566
- const IconSun = createReactComponent("outline", "sun", "Sun", __iconNode$2);
28565
+ const __iconNode$4 = [["path", { "d": "M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0", "key": "svg-0" }], ["path", { "d": "M21 21l-6 -6", "key": "svg-1" }]];
28566
+ const IconSearch = createReactComponent("outline", "search", "Search", __iconNode$4);
28567
28567
  /**
28568
28568
  * @license @tabler/icons-react v3.44.0 - MIT
28569
28569
  *
28570
28570
  * This source code is licensed under the MIT license.
28571
28571
  * See the LICENSE file in the root directory of this source tree.
28572
28572
  */
28573
- const __iconNode$1 = [["path", { "d": "M8 9l3 3l-3 3", "key": "svg-0" }], ["path", { "d": "M13 15l3 0", "key": "svg-1" }], ["path", { "d": "M3 6a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2l0 -12", "key": "svg-2" }]];
28574
- const IconTerminal2 = createReactComponent("outline", "terminal-2", "Terminal2", __iconNode$1);
28573
+ const __iconNode$3 = [["path", { "d": "M8 12a4 4 0 1 0 8 0a4 4 0 1 0 -8 0", "key": "svg-0" }], ["path", { "d": "M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7", "key": "svg-1" }]];
28574
+ const IconSun = createReactComponent("outline", "sun", "Sun", __iconNode$3);
28575
28575
  /**
28576
28576
  * @license @tabler/icons-react v3.44.0 - MIT
28577
28577
  *
28578
28578
  * This source code is licensed under the MIT license.
28579
28579
  * See the LICENSE file in the root directory of this source tree.
28580
28580
  */
28581
- const __iconNode = [["path", { "d": "M4 7l16 0", "key": "svg-0" }], ["path", { "d": "M10 11l0 6", "key": "svg-1" }], ["path", { "d": "M14 11l0 6", "key": "svg-2" }], ["path", { "d": "M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12", "key": "svg-3" }], ["path", { "d": "M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3", "key": "svg-4" }]];
28582
- const IconTrash = createReactComponent("outline", "trash", "Trash", __iconNode);
28581
+ const __iconNode$2 = [["path", { "d": "M8 9l3 3l-3 3", "key": "svg-0" }], ["path", { "d": "M13 15l3 0", "key": "svg-1" }], ["path", { "d": "M3 6a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2l0 -12", "key": "svg-2" }]];
28582
+ const IconTerminal2 = createReactComponent("outline", "terminal-2", "Terminal2", __iconNode$2);
28583
+ /**
28584
+ * @license @tabler/icons-react v3.44.0 - MIT
28585
+ *
28586
+ * This source code is licensed under the MIT license.
28587
+ * See the LICENSE file in the root directory of this source tree.
28588
+ */
28589
+ const __iconNode$1 = [["path", { "d": "M4 7l16 0", "key": "svg-0" }], ["path", { "d": "M10 11l0 6", "key": "svg-1" }], ["path", { "d": "M14 11l0 6", "key": "svg-2" }], ["path", { "d": "M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12", "key": "svg-3" }], ["path", { "d": "M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3", "key": "svg-4" }]];
28590
+ const IconTrash = createReactComponent("outline", "trash", "Trash", __iconNode$1);
28591
+ /**
28592
+ * @license @tabler/icons-react v3.44.0 - MIT
28593
+ *
28594
+ * This source code is licensed under the MIT license.
28595
+ * See the LICENSE file in the root directory of this source tree.
28596
+ */
28597
+ const __iconNode = [["path", { "d": "M18 6l-12 12", "key": "svg-0" }], ["path", { "d": "M6 6l12 12", "key": "svg-1" }]];
28598
+ const IconX = createReactComponent("outline", "x", "X", __iconNode);
28583
28599
  const header$2 = "_header_1cfdg_1";
28584
28600
  const headerInner = "_headerInner_1cfdg_6";
28585
28601
  const brand = "_brand_1cfdg_12";
@@ -31506,6 +31522,60 @@ function segStyle(seg) {
31506
31522
  textDecoration: d.includes("underline") ? "underline" : void 0
31507
31523
  };
31508
31524
  }
31525
+ const MATCH_STYLE = { background: "var(--mantine-color-yellow-4)", color: "#000" };
31526
+ const ACTIVE_MATCH_STYLE = { background: "var(--mantine-color-orange-5)", color: "#000" };
31527
+ function highlightSegments(entry, query, activeStart) {
31528
+ const lower = entry.text.toLowerCase();
31529
+ const ranges = [];
31530
+ let from = 0;
31531
+ while (query) {
31532
+ const idx = lower.indexOf(query, from);
31533
+ if (idx === -1) break;
31534
+ ranges.push([idx, idx + query.length]);
31535
+ from = idx + query.length;
31536
+ }
31537
+ if (ranges.length === 0) {
31538
+ return entry.segments.map((seg, i) => (
31539
+ // biome-ignore lint/suspicious/noArrayIndexKey: 파싱된 로그 줄은 불변
31540
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: segStyle(seg), children: seg.content }, i)
31541
+ ));
31542
+ }
31543
+ const nodes = [];
31544
+ let offset2 = 0;
31545
+ let key = 0;
31546
+ for (const seg of entry.segments) {
31547
+ const base = segStyle(seg);
31548
+ const text = seg.content;
31549
+ const segStart = offset2;
31550
+ const segEnd = offset2 + text.length;
31551
+ let pos = segStart;
31552
+ while (pos < segEnd) {
31553
+ const range = ranges.find(([, e]) => e > pos);
31554
+ if (!range || range[0] >= segEnd) {
31555
+ nodes.push(
31556
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: base, children: text.slice(pos - segStart) }, `s${key++}`)
31557
+ );
31558
+ break;
31559
+ }
31560
+ const [ms, me] = range;
31561
+ if (pos < ms) {
31562
+ nodes.push(
31563
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: base, children: text.slice(pos - segStart, ms - segStart) }, `s${key++}`)
31564
+ );
31565
+ pos = ms;
31566
+ } else {
31567
+ const end = Math.min(me, segEnd);
31568
+ const mark = ms === activeStart ? ACTIVE_MATCH_STYLE : MATCH_STYLE;
31569
+ nodes.push(
31570
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { ...base, ...mark }, children: text.slice(pos - segStart, end - segStart) }, `s${key++}`)
31571
+ );
31572
+ pos = end;
31573
+ }
31574
+ }
31575
+ offset2 = segEnd;
31576
+ }
31577
+ return nodes;
31578
+ }
31509
31579
  const ANSER_OPTS = { json: true, remove_empty: true, use_classes: false };
31510
31580
  const TS_PREFIX = /^\d{4}-\d{2}-\d{2}T\d{2}:/;
31511
31581
  function parseLine(raw, timestamped) {
@@ -31514,13 +31584,17 @@ function parseLine(raw, timestamped) {
31514
31584
  if (sp > 0) {
31515
31585
  const ts = raw.slice(0, sp);
31516
31586
  if (TS_PREFIX.test(ts)) {
31517
- return { timestamp: ts, segments: Anser.ansiToJson(raw.slice(sp + 1), ANSER_OPTS) };
31587
+ return makeEntry(raw.slice(sp + 1), ts);
31518
31588
  }
31519
31589
  }
31520
31590
  }
31521
- return { segments: Anser.ansiToJson(raw, ANSER_OPTS) };
31591
+ return makeEntry(raw);
31592
+ }
31593
+ function makeEntry(content, timestamp) {
31594
+ const segments = Anser.ansiToJson(content, ANSER_OPTS);
31595
+ return { timestamp, segments, text: segments.map((s) => s.content).join("") };
31522
31596
  }
31523
- function LogStream({ openStream, clearSignal, timestamped, loadHistory }) {
31597
+ const LogStream = reactExports.forwardRef(function LogStream2({ openStream, clearSignal, timestamped, loadHistory, query = "", onMatchState }, ref) {
31524
31598
  const [lines, setLines] = reactExports.useState([]);
31525
31599
  const [reachedStart, setReachedStart] = reactExports.useState(false);
31526
31600
  const [loadingHistory, setLoadingHistory] = reactExports.useState(false);
@@ -31572,12 +31646,59 @@ function LogStream({ openStream, clearSignal, timestamped, loadHistory }) {
31572
31646
  estimateSize: () => LINE_HEIGHT,
31573
31647
  overscan: 24
31574
31648
  });
31649
+ const q = query.trim().toLowerCase();
31650
+ const matches = reactExports.useMemo(() => {
31651
+ if (!q) return [];
31652
+ const out = [];
31653
+ for (let i = 0; i < lines.length; i++) {
31654
+ const lower = lines[i].text.toLowerCase();
31655
+ let pos = lower.indexOf(q);
31656
+ while (pos !== -1) {
31657
+ out.push({ line: i, start: pos });
31658
+ pos = lower.indexOf(q, pos + q.length);
31659
+ }
31660
+ }
31661
+ return out;
31662
+ }, [lines, q]);
31663
+ const matchLineSet = reactExports.useMemo(() => new Set(matches.map((m) => m.line)), [matches]);
31664
+ const matchesRef = reactExports.useRef(matches);
31665
+ matchesRef.current = matches;
31666
+ const [cursor, setCursor] = reactExports.useState(0);
31667
+ const total = matches.length;
31668
+ const safeCursor = total === 0 ? 0 : Math.min(cursor, total - 1);
31669
+ const activeMatch = total === 0 ? null : matches[safeCursor];
31670
+ const cursorRef = reactExports.useRef(safeCursor);
31671
+ cursorRef.current = safeCursor;
31672
+ reactExports.useEffect(() => {
31673
+ onMatchState == null ? void 0 : onMatchState({ current: total === 0 ? 0 : safeCursor + 1, total });
31674
+ }, [total, safeCursor, onMatchState]);
31675
+ reactExports.useEffect(() => {
31676
+ cursorRef.current = 0;
31677
+ setCursor(0);
31678
+ if (q && matchesRef.current.length > 0) {
31679
+ stick.current = false;
31680
+ virtualizer.scrollToIndex(matchesRef.current[0].line, { align: "center" });
31681
+ }
31682
+ }, [q]);
31683
+ const navigate = reactExports.useCallback(
31684
+ (dir) => {
31685
+ const items = matchesRef.current;
31686
+ if (items.length === 0) return;
31687
+ const nextC = (cursorRef.current + dir + items.length) % items.length;
31688
+ cursorRef.current = nextC;
31689
+ stick.current = false;
31690
+ setCursor(nextC);
31691
+ virtualizer.scrollToIndex(items[nextC].line, { align: "center" });
31692
+ },
31693
+ [virtualizer]
31694
+ );
31695
+ reactExports.useImperativeHandle(ref, () => ({ next: () => navigate(1), prev: () => navigate(-1) }), [navigate]);
31575
31696
  reactExports.useEffect(() => {
31576
31697
  if (restoreToIndex.current !== null) return;
31577
- if (stick.current && lines.length > 0) {
31698
+ if (!q && stick.current && lines.length > 0) {
31578
31699
  virtualizer.scrollToIndex(lines.length - 1, { align: "end" });
31579
31700
  }
31580
- }, [lines.length, virtualizer]);
31701
+ }, [lines.length, virtualizer, q]);
31581
31702
  reactExports.useEffect(() => {
31582
31703
  if (restoreToIndex.current === null) return;
31583
31704
  const idx = restoreToIndex.current;
@@ -31657,35 +31778,69 @@ function LogStream({ openStream, clearSignal, timestamped, loadHistory }) {
31657
31778
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "↑ 위로 스크롤하면 과거 로그를 불러옵니다" })
31658
31779
  }
31659
31780
  ) : null,
31660
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: virtualizer.getTotalSize(), position: "relative" }, children: virtualizer.getVirtualItems().map((vi) => (
31661
- // data-index + measureElement ref 줄바꿈된 로그의 실제 높이를 측정해
31662
- // 가상 스크롤 위치를 맞춘다 (고정 높이로 두면 긴 줄이 겹쳐 보인다).
31663
- /* @__PURE__ */ jsxRuntimeExports.jsx(
31664
- "div",
31665
- {
31666
- "data-index": vi.index,
31667
- ref: virtualizer.measureElement,
31668
- style: {
31669
- position: "absolute",
31670
- top: 0,
31671
- left: 0,
31672
- width: "100%",
31673
- transform: `translateY(${vi.start}px)`,
31674
- whiteSpace: "pre-wrap",
31675
- wordBreak: "break-all",
31676
- padding: "0 12px"
31781
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: virtualizer.getTotalSize(), position: "relative" }, children: virtualizer.getVirtualItems().map((vi) => {
31782
+ const activeStart = activeMatch && activeMatch.line === vi.index ? activeMatch.start : -1;
31783
+ return (
31784
+ // data-index + measureElement ref — 줄바꿈된 긴 로그의 실제 높이를 측정해
31785
+ // 가상 스크롤 위치를 맞춘다 (고정 높이로 두면 긴 줄이 겹쳐 보인다).
31786
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31787
+ "div",
31788
+ {
31789
+ "data-index": vi.index,
31790
+ ref: virtualizer.measureElement,
31791
+ style: {
31792
+ position: "absolute",
31793
+ top: 0,
31794
+ left: 0,
31795
+ width: "100%",
31796
+ transform: `translateY(${vi.start}px)`,
31797
+ whiteSpace: "pre-wrap",
31798
+ wordBreak: "break-all",
31799
+ padding: "0 12px",
31800
+ background: activeStart !== -1 ? "var(--mantine-color-yellow-light)" : void 0
31801
+ },
31802
+ children: q && matchLineSet.has(vi.index) ? highlightSegments(lines[vi.index], q, activeStart) : lines[vi.index].segments.map((seg, i) => (
31803
+ // biome-ignore lint/suspicious/noArrayIndexKey: 파싱된 로그 줄은 불변이라 세그먼트 순서가 바뀌지 않는다
31804
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: segStyle(seg), children: seg.content }, i)
31805
+ ))
31677
31806
  },
31678
- children: lines[vi.index].segments.map((seg, i) => (
31679
- // biome-ignore lint/suspicious/noArrayIndexKey: 파싱된 로그 줄은 불변이라 세그먼트 순서가 바뀌지 않는다
31680
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: segStyle(seg), children: seg.content }, i)
31681
- ))
31682
- },
31683
- vi.key
31684
- )
31685
- )) })
31807
+ vi.key
31808
+ )
31809
+ );
31810
+ }) })
31686
31811
  ]
31687
31812
  }
31688
31813
  );
31814
+ });
31815
+ function LogSearchControls({ query, onQueryChange, match, onPrev, onNext }) {
31816
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
31817
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31818
+ TextInput,
31819
+ {
31820
+ size: "xs",
31821
+ w: 180,
31822
+ placeholder: "로그 찾기",
31823
+ leftSection: /* @__PURE__ */ jsxRuntimeExports.jsx(IconSearch, { size: 14 }),
31824
+ value: query,
31825
+ onChange: (e) => onQueryChange(e.currentTarget.value),
31826
+ onKeyDown: (e) => {
31827
+ if (e.key === "Enter") {
31828
+ e.preventDefault();
31829
+ if (e.shiftKey) onPrev();
31830
+ else onNext();
31831
+ } else if (e.key === "Escape") {
31832
+ onQueryChange("");
31833
+ }
31834
+ },
31835
+ rightSection: query ? /* @__PURE__ */ jsxRuntimeExports.jsx(ActionIcon, { size: "sm", variant: "subtle", color: "gray", onClick: () => onQueryChange(""), "aria-label": "검색어 지우기", children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconX, { size: 14 }) }) : null
31836
+ }
31837
+ ),
31838
+ query ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Group, { gap: 4, wrap: "nowrap", children: [
31839
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Text, { size: "xs", c: "dimmed", style: { fontVariantNumeric: "tabular-nums", minWidth: 36, textAlign: "right" }, children: match.total ? `${match.current}/${match.total}` : "0/0" }),
31840
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ActionIcon, { size: "sm", variant: "default", disabled: !match.total, onClick: onPrev, "aria-label": "이전 매치", children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconChevronUp, { size: 14 }) }),
31841
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ActionIcon, { size: "sm", variant: "default", disabled: !match.total, onClick: onNext, "aria-label": "다음 매치", children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconChevronDown, { size: 14 }) })
31842
+ ] }) : null
31843
+ ] });
31689
31844
  }
31690
31845
  const ROOT_FONT_PX = 16;
31691
31846
  const MIN_HEIGHT_PX = 15 * ROOT_FONT_PX;
@@ -31706,6 +31861,9 @@ function writeStoredHeight(px2) {
31706
31861
  function LogDrawer({ target, onClose }) {
31707
31862
  var _a;
31708
31863
  const [clearSignal, setClearSignal] = reactExports.useState(0);
31864
+ const [query, setQuery] = reactExports.useState("");
31865
+ const [match, setMatch] = reactExports.useState({ current: 0, total: 0 });
31866
+ const streamRef = reactExports.useRef(null);
31709
31867
  const [height, setHeight] = reactExports.useState(() => {
31710
31868
  if (typeof window === "undefined") return 480;
31711
31869
  const stored = readStoredHeight();
@@ -31723,6 +31881,9 @@ function LogDrawer({ target, onClose }) {
31723
31881
  if (resizing) return;
31724
31882
  writeStoredHeight(height);
31725
31883
  }, [resizing, height]);
31884
+ reactExports.useEffect(() => {
31885
+ setQuery("");
31886
+ }, [target == null ? void 0 : target.streamKey]);
31726
31887
  async function handleClear() {
31727
31888
  var _a2;
31728
31889
  setClearSignal((n) => n + 1);
@@ -31778,6 +31939,22 @@ function LogDrawer({ target, onClose }) {
31778
31939
  (_a = target == null ? void 0 : target.actions) == null ? void 0 : _a.map((a) => /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "compact-xs", variant: "light", color: a.color, onClick: a.run, children: a.label }, a.label))
31779
31940
  ] }) }),
31780
31941
  /* @__PURE__ */ jsxRuntimeExports.jsxs(Group, { gap: "xs", children: [
31942
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31943
+ LogSearchControls,
31944
+ {
31945
+ query,
31946
+ onQueryChange: setQuery,
31947
+ match,
31948
+ onPrev: () => {
31949
+ var _a2;
31950
+ return (_a2 = streamRef.current) == null ? void 0 : _a2.prev();
31951
+ },
31952
+ onNext: () => {
31953
+ var _a2;
31954
+ return (_a2 = streamRef.current) == null ? void 0 : _a2.next();
31955
+ }
31956
+ }
31957
+ ),
31781
31958
  /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "compact-xs", variant: "default", onClick: () => void handleClear(), children: "Clear" }),
31782
31959
  /* @__PURE__ */ jsxRuntimeExports.jsx(Drawer.CloseButton, {})
31783
31960
  ] })
@@ -31785,10 +31962,13 @@ function LogDrawer({ target, onClose }) {
31785
31962
  /* @__PURE__ */ jsxRuntimeExports.jsx(Drawer.Body, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: classes$2.streamContainer, style: { height: `${height - 80}px` }, children: target !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
31786
31963
  LogStream,
31787
31964
  {
31965
+ ref: streamRef,
31788
31966
  openStream: target.openStream,
31789
31967
  clearSignal,
31790
31968
  timestamped: target.timestamped,
31791
- loadHistory: target.loadHistory
31969
+ loadHistory: target.loadHistory,
31970
+ query,
31971
+ onMatchState: setMatch
31792
31972
  },
31793
31973
  target.streamKey
31794
31974
  ) }) })
@@ -32086,17 +32266,27 @@ function ProjectDetail({ opened, entry, workspaceRoot, initialSelection, procAct
32086
32266
  var _a, _b;
32087
32267
  const [selection, setSelection] = reactExports.useState(initialSelection ?? "log");
32088
32268
  const [, force] = reactExports.useReducer((x) => x + 1, 0);
32269
+ const [query, setQuery] = reactExports.useState("");
32270
+ const [match, setMatch] = reactExports.useState({ current: 0, total: 0 });
32271
+ const streamRef = reactExports.useRef(null);
32089
32272
  reactExports.useEffect(() => {
32090
- if (opened) setSelection(initialSelection ?? "log");
32273
+ if (opened) {
32274
+ setSelection(initialSelection ?? "log");
32275
+ setQuery("");
32276
+ }
32091
32277
  }, [opened, initialSelection]);
32092
32278
  reactExports.useEffect(() => {
32093
32279
  return subscribe(() => force());
32094
32280
  }, []);
32281
+ reactExports.useEffect(() => {
32282
+ setQuery("");
32283
+ }, [selection]);
32095
32284
  if (!entry) return null;
32096
32285
  const procName = (_a = entry.proc) == null ? void 0 : _a.name;
32097
32286
  const procDisplayName = (_b = entry.proc) == null ? void 0 : _b.displayName;
32098
32287
  const projectKey = procDisplayName ?? entry.name.split("/").pop() ?? entry.name;
32099
32288
  const processes = listProcesses(projectKey);
32289
+ const streamShown = selection === "log" ? Boolean(procName) : Boolean(getProcess(selection));
32100
32290
  function handleSelectScript(scriptName) {
32101
32291
  if (!(entry == null ? void 0 : entry.dir)) return;
32102
32292
  const id = startScript(
@@ -32125,9 +32315,12 @@ function ProjectDetail({ opened, entry, workspaceRoot, initialSelection, procAct
32125
32315
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
32126
32316
  LogStream,
32127
32317
  {
32318
+ ref: streamRef,
32128
32319
  openStream: () => openPm2LogStream(procName),
32129
32320
  clearSignal: 0,
32130
- timestamped: false
32321
+ timestamped: false,
32322
+ query,
32323
+ onMatchState: setMatch
32131
32324
  },
32132
32325
  "pm2-log"
32133
32326
  );
@@ -32139,9 +32332,12 @@ function ProjectDetail({ opened, entry, workspaceRoot, initialSelection, procAct
32139
32332
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
32140
32333
  LogStream,
32141
32334
  {
32335
+ ref: streamRef,
32142
32336
  openStream: () => openScriptStream(proc.id),
32143
32337
  clearSignal: 0,
32144
- timestamped: false
32338
+ timestamped: false,
32339
+ query,
32340
+ onMatchState: setMatch
32145
32341
  },
32146
32342
  `script-${proc.id}`
32147
32343
  );
@@ -32221,7 +32417,35 @@ function ProjectDetail({ opened, entry, workspaceRoot, initialSelection, procAct
32221
32417
  ]
32222
32418
  }
32223
32419
  ),
32224
- /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { style: { flex: "1 1 auto", minWidth: 0, minHeight: 0, display: "flex", flexDirection: "column" }, children: renderContent() })
32420
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { style: { flex: "1 1 auto", minWidth: 0, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
32421
+ streamShown ? /* @__PURE__ */ jsxRuntimeExports.jsx(
32422
+ Group,
32423
+ {
32424
+ justify: "flex-end",
32425
+ gap: "xs",
32426
+ px: "xs",
32427
+ py: 6,
32428
+ style: { flex: "0 0 auto", borderBottom: "1px solid var(--mantine-color-default-border)" },
32429
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32430
+ LogSearchControls,
32431
+ {
32432
+ query,
32433
+ onQueryChange: setQuery,
32434
+ match,
32435
+ onPrev: () => {
32436
+ var _a2;
32437
+ return (_a2 = streamRef.current) == null ? void 0 : _a2.prev();
32438
+ },
32439
+ onNext: () => {
32440
+ var _a2;
32441
+ return (_a2 = streamRef.current) == null ? void 0 : _a2.next();
32442
+ }
32443
+ }
32444
+ )
32445
+ }
32446
+ ) : null,
32447
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { style: { flex: "1 1 auto", minHeight: 0 }, children: renderContent() })
32448
+ ] })
32225
32449
  ] })
32226
32450
  }
32227
32451
  );
@@ -33167,6 +33391,13 @@ function isEditable(el) {
33167
33391
  if (el.tagName === "INPUT" || el.tagName === "TEXTAREA") return true;
33168
33392
  return el.isContentEditable;
33169
33393
  }
33394
+ function setNativeValue(el, value) {
33395
+ var _a;
33396
+ const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
33397
+ const setter = (_a = Object.getOwnPropertyDescriptor(proto, "value")) == null ? void 0 : _a.set;
33398
+ if (setter) setter.call(el, value);
33399
+ else el.value = value;
33400
+ }
33170
33401
  async function doCopy() {
33171
33402
  var _a;
33172
33403
  const text = (_a = window.getSelection()) == null ? void 0 : _a.toString();
@@ -33188,7 +33419,7 @@ async function doCut(el) {
33188
33419
  } catch {
33189
33420
  return false;
33190
33421
  }
33191
- el.value = el.value.slice(0, start) + el.value.slice(end);
33422
+ setNativeValue(el, el.value.slice(0, start) + el.value.slice(end));
33192
33423
  el.selectionStart = el.selectionEnd = start;
33193
33424
  el.dispatchEvent(new Event("input", { bubbles: true }));
33194
33425
  return true;
@@ -33202,7 +33433,7 @@ async function doPaste(el) {
33202
33433
  }
33203
33434
  const start = el.selectionStart ?? el.value.length;
33204
33435
  const end = el.selectionEnd ?? el.value.length;
33205
- el.value = el.value.slice(0, start) + text + el.value.slice(end);
33436
+ setNativeValue(el, el.value.slice(0, start) + text + el.value.slice(end));
33206
33437
  el.selectionStart = el.selectionEnd = start + text.length;
33207
33438
  el.dispatchEvent(new Event("input", { bubbles: true }));
33208
33439
  return true;
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Devis</title>
7
- <script type="module" crossorigin src="./assets/index-B3EEPtRc.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-CfF4ouPT.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="./assets/index-BDxL9RBN.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gbdx/devis",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Local development dashboard for pnpm monorepos — workspace scanning, process management, HTTPS proxy, Docker, and more.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "author": "gibigspub@gmail.com",