Skip to content

Commit bbb986a

Browse files
authored
feat(cli): use domain and pipeline status text for animation (#157)
* update status text Signed-off-by: Joshua Li <joshuali925@gmail.com> * update readme command Signed-off-by: Joshua Li <joshuali925@gmail.com> --------- Signed-off-by: Joshua Li <joshuali925@gmail.com>
1 parent 2398f80 commit bbb986a

File tree

3 files changed

+51
-46
lines changed

3 files changed

+51
-46
lines changed

aws/cli-installer/README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ Deploy the [Observability Stack](https://github.com/opensearch-project/observabi
55
## Quick Start
66

77
```bash
8-
git clone https://github.com/opensearch-project/observability-stack.git
9-
cd observability-stack/aws/cli-installer && npm install
10-
11-
node bin/cli-installer.mjs --managed \
12-
--pipeline-name obs-stack-<your-alias> \
13-
--region us-east-1
8+
bash -c "$(curl -fsSL https://raw.githubusercontent.com/opensearch-project/observability-stack/main/install.sh)" -- --deployment-target=aws
149
```
1510

1611
Takes ~15 minutes. When complete, the CLI prints a dashboard URL — open it and you're in.

aws/cli-installer/src/aws.mjs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
OpenSearchClient,
44
CreateDomainCommand,
55
DescribeDomainCommand,
6+
DescribeDomainChangeProgressCommand,
67
ListDomainNamesCommand,
78
DescribeDomainsCommand,
89
AddDirectQueryDataSourceCommand,
@@ -30,6 +31,7 @@ import {
3031
ListPipelinesCommand,
3132
CreatePipelineCommand,
3233
GetPipelineCommand,
34+
GetPipelineChangeProgressCommand,
3335
} from '@aws-sdk/client-osis';
3436
import {
3537
ResourceGroupsTaggingAPIClient,
@@ -272,7 +274,17 @@ async function createManagedDomain(cfg) {
272274
while (Date.now() - start < maxWait) {
273275
try {
274276
const desc = await client.send(new DescribeDomainCommand({ DomainName: cfg.osDomainName }));
275-
const endpoint = desc.DomainStatus?.Endpoint;
277+
const ds = desc.DomainStatus || {};
278+
const endpoint = ds.Endpoint;
279+
280+
// Feed real stage progress into the owl animation
281+
try {
282+
const cp = await client.send(new DescribeDomainChangeProgressCommand({ DomainName: cfg.osDomainName }));
283+
const stages = cp.ChangeProgressStatus?.ChangeProgressStages || [];
284+
const current = stages.find((s) => s.Status === 'IN_PROGRESS') || stages.findLast((s) => s.Status === 'COMPLETED');
285+
anim.setDomainStatus(current?.Description || current?.Name || 'Initializing...');
286+
} catch { /* change progress may not be available yet */ }
287+
276288
if (endpoint) {
277289
cfg.opensearchEndpoint = `https://${endpoint}`;
278290
anim.stop();
@@ -570,6 +582,15 @@ export async function createOsiPipeline(cfg, pipelineYaml) {
570582
try {
571583
const resp = await client.send(new GetPipelineCommand({ PipelineName: cfg.pipelineName }));
572584
const status = resp.Pipeline?.Status;
585+
586+
// Feed real stage progress into the fish animation
587+
try {
588+
const cp = await client.send(new GetPipelineChangeProgressCommand({ PipelineName: cfg.pipelineName }));
589+
const stages = cp.ChangeProgressStatuses?.[0]?.ChangeProgressStages || [];
590+
const current = stages.find((s) => s.Status === 'IN_PROGRESS') || stages.findLast((s) => s.Status === 'COMPLETED');
591+
anim.setDomainStatus(current?.Description || current?.Name || 'Initializing...');
592+
} catch { /* change progress may not be available yet */ }
593+
573594
if (status === 'ACTIVE') {
574595
const urls = resp.Pipeline?.IngestEndpointUrls || [];
575596
cfg.ingestEndpoints = urls;

aws/cli-installer/src/ui.mjs

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -495,60 +495,46 @@ function createWordRotator() {
495495
};
496496
}
497497

498-
// Owl searching through data — for OpenSearch domain provisioning
499-
const OPENSEARCH_FRAMES = [
500-
[
501-
'',
502-
" ,___,",
503-
' {o,o} ◇ searching...',
504-
' /)__)',
505-
' -"-"- ◇ ◇ ◇',
506-
null,
507-
'',
508-
],
509-
[
510-
'',
511-
" ,___,",
512-
' {O,o} ◈ indexing...',
513-
' /)__)',
514-
' -"-"- ◈ ◈ ◈',
515-
null,
516-
'',
517-
],
518-
[
519-
'',
520-
" ,___,",
521-
' {o,O} ◆ mapping...',
522-
' /)__)',
523-
' -"-"- ◆ ◆ ◆',
524-
null,
525-
'',
526-
],
527-
[
498+
// Owl eye patterns cycle for animation even when status text is static
499+
const OWL_EYES = ['{o,o}', '{O,o}', '{o,O}', '{O,O}'];
500+
const OWL_GEMS = ['◇', '◈', '◆', '★'];
501+
502+
function buildOwlFrame(frameIdx, statusText) {
503+
const eyes = OWL_EYES[frameIdx % OWL_EYES.length];
504+
const gem = OWL_GEMS[frameIdx % OWL_GEMS.length];
505+
const label = statusText || 'provisioning...';
506+
const drift = (frameIdx % 4) * 2;
507+
const pad = ' '.repeat(drift);
508+
return [
528509
'',
529-
" ,___,",
530-
' {O,O} ★ found it!',
531-
' /)__)',
532-
' -"-"- ★ ★ ★',
510+
` ,___,`,
511+
` ${eyes}${pad} ${gem} ${label}`,
512+
` /)__)`,
513+
` -"-"-${pad} ${gem} ${gem} ${gem}`,
533514
null,
534515
'',
535-
],
536-
];
516+
];
517+
}
537518

538519
// Fish swimming back and forth through the pipeline
539520
const FISH_RIGHT = '><(((º>';
540521
const FISH_LEFT = '<º)))><';
541522
const PIPE_WIDTH = 36;
542523

543-
function buildPipelineFrame(pos, goingRight, caption) {
524+
function buildPipelineFrame(pos, goingRight, caption, statusText) {
544525
const fish = goingRight ? FISH_RIGHT : FISH_LEFT;
545526
const lane = ' '.repeat(PIPE_WIDTH);
546527
const row = lane.slice(0, pos) + fish + lane.slice(pos + fish.length);
547528
const pipe = '═'.repeat(PIPE_WIDTH);
529+
const label = statusText || '';
530+
const padded = label.length < PIPE_WIDTH
531+
? ' ' + label + ' '.repeat(PIPE_WIDTH - label.length - 1)
532+
: ' ' + label.slice(0, PIPE_WIDTH - 1);
548533
return [
549534
'',
550535
` ${pipe}`,
551536
` ${row}`,
537+
` ${padded}`,
552538
` ${pipe}`,
553539
` ${caption}`,
554540
'',
@@ -575,16 +561,17 @@ export function createAsciiAnimation(type) {
575561

576562
// OpenSearch state
577563
let osFrame = 0;
564+
let domainStatus = '';
578565

579566
const getWord = createWordRotator();
580567

581568
function getFrame() {
582569
const word = getWord();
583570
if (isOpenSearch) {
584-
return OPENSEARCH_FRAMES[(osFrame++) % OPENSEARCH_FRAMES.length]
571+
return buildOwlFrame(osFrame++, domainStatus)
585572
.map((l) => l === null ? ` ${word}` : l);
586573
}
587-
const frame = buildPipelineFrame(fishPos, goingRight, word);
574+
const frame = buildPipelineFrame(fishPos, goingRight, word, domainStatus);
588575
if (goingRight) { fishPos++; if (fishPos >= maxPos) goingRight = false; }
589576
else { fishPos--; if (fishPos <= 0) goingRight = true; }
590577
return frame;
@@ -624,6 +611,8 @@ export function createAsciiAnimation(type) {
624611
},
625612
/** Update the status text shown below the art */
626613
setStatus(fn) { statusFn = fn; },
614+
/** Update the domain status label shown next to the owl */
615+
setDomainStatus(text) { domainStatus = text; },
627616
stop() { cleanup(); },
628617
};
629618
}

0 commit comments

Comments
 (0)