@chisquare-tech/origine-ngx-apps-code 0.9.0 → 0.10.0
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.
|
@@ -122,6 +122,13 @@ class CodeApi {
|
|
|
122
122
|
p['q'] = q;
|
|
123
123
|
return this.api.get(`${this.repoPath(project, name)}/refs`, p).pipe(map((r) => data(r) ?? []));
|
|
124
124
|
}
|
|
125
|
+
/** Searches the repository's default branch (text, or a regular expression). */
|
|
126
|
+
searchCode(project, name, q, regex = false) {
|
|
127
|
+
const p = { q };
|
|
128
|
+
if (regex)
|
|
129
|
+
p['regex'] = 'true';
|
|
130
|
+
return this.api.get(`${this.repoPath(project, name)}/search`, p).pipe(map((r) => data(r) ?? { hits: [], repos: 0 }));
|
|
131
|
+
}
|
|
125
132
|
collaborators(project, name) {
|
|
126
133
|
return this.api.get(`${this.repoPath(project, name)}/collaborators`).pipe(map((r) => data(r) ?? []));
|
|
127
134
|
}
|
|
@@ -1291,6 +1298,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
1291
1298
|
// /{org}/{project}/code/{repo}?ref=&path= (prototype "code_repo"): the repository's files at a
|
|
1292
1299
|
// branch, tag or commit, the last commit of each entry, the README, the clone menu and languages.
|
|
1293
1300
|
class RepoHomePage extends RepoPage {
|
|
1301
|
+
searchCode() {
|
|
1302
|
+
const q = this.codeQuery.trim();
|
|
1303
|
+
if (q)
|
|
1304
|
+
void this.router.navigate(this.link('search'), { queryParams: { q } });
|
|
1305
|
+
}
|
|
1294
1306
|
constructor() {
|
|
1295
1307
|
super();
|
|
1296
1308
|
this.router = inject(Router);
|
|
@@ -1302,6 +1314,7 @@ class RepoHomePage extends RepoPage {
|
|
|
1302
1314
|
this.proto = signal('https', ...(ngDevMode ? [{ debugName: "proto" }] : /* istanbul ignore next */ []));
|
|
1303
1315
|
this.cloneOpen = signal(false, ...(ngDevMode ? [{ debugName: "cloneOpen" }] : /* istanbul ignore next */ []));
|
|
1304
1316
|
this.addOpen = signal(false, ...(ngDevMode ? [{ debugName: "addOpen" }] : /* istanbul ignore next */ []));
|
|
1317
|
+
this.codeQuery = '';
|
|
1305
1318
|
this.copied = signal(false, ...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
|
|
1306
1319
|
this.finding = signal(false, ...(ngDevMode ? [{ debugName: "finding" }] : /* istanbul ignore next */ []));
|
|
1307
1320
|
this.fq = signal('', ...(ngDevMode ? [{ debugName: "fq" }] : /* istanbul ignore next */ []));
|
|
@@ -1429,6 +1442,7 @@ class RepoHomePage extends RepoPage {
|
|
|
1429
1442
|
@for (c of crumbs(); track c.path) {<span class="o-faint">/</span><a [routerLink]="link()" [queryParams]="qp(c.path)">{{ c.name }}</a>}
|
|
1430
1443
|
</nav>
|
|
1431
1444
|
<span class="o-r"></span>
|
|
1445
|
+
<form class="o-flex" (ngSubmit)="searchCode()" role="search"><input class="o-in o-sm o-mono" style="width:180px" name="cq" [(ngModel)]="codeQuery" placeholder="Search code" aria-label="Search code" data-testid="repo-code-search" /></form>
|
|
1432
1446
|
<button type="button" class="o-btn o-sm" (click)="openFinder()">Go to file <span class="o-kbd">T</span></button>
|
|
1433
1447
|
@if (canWrite()) {
|
|
1434
1448
|
<span class="anchor add">
|
|
@@ -1518,7 +1532,7 @@ class RepoHomePage extends RepoPage {
|
|
|
1518
1532
|
</div>
|
|
1519
1533
|
</div>
|
|
1520
1534
|
}
|
|
1521
|
-
`, isInline: true, styles: [".anchor{position:relative}.ic{width:18px;flex:none;color:var(--o-dim);text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: RefPicker, selector: "o-ref-picker", inputs: ["repo", "current"], outputs: ["picked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1535
|
+
`, isInline: true, styles: [".anchor{position:relative}.ic{width:18px;flex:none;color:var(--o-dim);text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: RefPicker, selector: "o-ref-picker", inputs: ["repo", "current"], outputs: ["picked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1522
1536
|
}
|
|
1523
1537
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: RepoHomePage, decorators: [{
|
|
1524
1538
|
type: Component,
|
|
@@ -1560,6 +1574,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
1560
1574
|
@for (c of crumbs(); track c.path) {<span class="o-faint">/</span><a [routerLink]="link()" [queryParams]="qp(c.path)">{{ c.name }}</a>}
|
|
1561
1575
|
</nav>
|
|
1562
1576
|
<span class="o-r"></span>
|
|
1577
|
+
<form class="o-flex" (ngSubmit)="searchCode()" role="search"><input class="o-in o-sm o-mono" style="width:180px" name="cq" [(ngModel)]="codeQuery" placeholder="Search code" aria-label="Search code" data-testid="repo-code-search" /></form>
|
|
1563
1578
|
<button type="button" class="o-btn o-sm" (click)="openFinder()">Go to file <span class="o-kbd">T</span></button>
|
|
1564
1579
|
@if (canWrite()) {
|
|
1565
1580
|
<span class="anchor add">
|
|
@@ -4323,6 +4338,115 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
4323
4338
|
}]
|
|
4324
4339
|
}], ctorParameters: () => [] });
|
|
4325
4340
|
|
|
4341
|
+
// /{org}/{project}/code/{repo}/search?q=®ex= (DEV-11): code search over the repository's default
|
|
4342
|
+
// branch, text or a regular expression; each file with its matching lines, the matches marked, a
|
|
4343
|
+
// line opening the file there.
|
|
4344
|
+
class CodeSearchPage extends RepoPage {
|
|
4345
|
+
constructor() {
|
|
4346
|
+
super();
|
|
4347
|
+
this.router = inject(Router);
|
|
4348
|
+
this.hits = signal([], ...(ngDevMode ? [{ debugName: "hits" }] : /* istanbul ignore next */ []));
|
|
4349
|
+
this.searched = signal(false, ...(ngDevMode ? [{ debugName: "searched" }] : /* istanbul ignore next */ []));
|
|
4350
|
+
this.text = '';
|
|
4351
|
+
this.regex = false;
|
|
4352
|
+
this.route.queryParamMap.subscribe((q) => {
|
|
4353
|
+
this.text = q.get('q') ?? '';
|
|
4354
|
+
this.regex = q.get('regex') === 'true';
|
|
4355
|
+
const r = this.repo();
|
|
4356
|
+
if (r && r.name === this.name())
|
|
4357
|
+
this.load(r);
|
|
4358
|
+
});
|
|
4359
|
+
}
|
|
4360
|
+
onRepo(r) {
|
|
4361
|
+
this.load(r);
|
|
4362
|
+
}
|
|
4363
|
+
go() {
|
|
4364
|
+
void this.router.navigate(this.link('search'), { queryParams: { q: this.text.trim(), regex: this.regex ? 'true' : null } });
|
|
4365
|
+
}
|
|
4366
|
+
load(r) {
|
|
4367
|
+
const q = this.text.trim();
|
|
4368
|
+
if (!q)
|
|
4369
|
+
return;
|
|
4370
|
+
this.error.set('');
|
|
4371
|
+
this.api.searchCode(this.projectId(), r.name, q, this.regex).subscribe({
|
|
4372
|
+
next: (res) => { this.hits.set(res.hits); this.searched.set(true); },
|
|
4373
|
+
error: (e) => { this.hits.set([]); this.searched.set(false); this.error.set(apiMessage(e, 'Could not search the code.')); },
|
|
4374
|
+
});
|
|
4375
|
+
}
|
|
4376
|
+
/** A line cut into plain and matched pieces (ranges are byte offsets; the text is UTF-8). */
|
|
4377
|
+
pieces(text, ranges) {
|
|
4378
|
+
if (!ranges?.length)
|
|
4379
|
+
return [{ text, hit: false }];
|
|
4380
|
+
const bytes = new TextEncoder().encode(text);
|
|
4381
|
+
const dec = new TextDecoder();
|
|
4382
|
+
const out = [];
|
|
4383
|
+
let at = 0;
|
|
4384
|
+
for (const [a, b] of [...ranges].sort((x, y) => x[0] - y[0])) {
|
|
4385
|
+
if (a > at)
|
|
4386
|
+
out.push({ text: dec.decode(bytes.slice(at, a)), hit: false });
|
|
4387
|
+
out.push({ text: dec.decode(bytes.slice(Math.max(a, at), b)), hit: true });
|
|
4388
|
+
at = Math.max(at, b);
|
|
4389
|
+
}
|
|
4390
|
+
if (at < bytes.length)
|
|
4391
|
+
out.push({ text: dec.decode(bytes.slice(at)), hit: false });
|
|
4392
|
+
return out;
|
|
4393
|
+
}
|
|
4394
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: CodeSearchPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4395
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: CodeSearchPage, isStandalone: true, selector: "o-code-search", usesInheritance: true, ngImport: i0, template: `
|
|
4396
|
+
<div class="o-page o-wide">
|
|
4397
|
+
@if (repo(); as r) {
|
|
4398
|
+
<form class="o-flex o-wrap" (ngSubmit)="go()" role="search" aria-label="Search code">
|
|
4399
|
+
<input class="o-in o-mono" style="flex:1;min-width:220px" name="q" [(ngModel)]="text" placeholder="Search {{ r.name }} (default branch)" aria-label="Search code" data-testid="code-search-q" />
|
|
4400
|
+
<label class="o-flex o-sm"><input type="checkbox" name="regex" [(ngModel)]="regex" data-testid="code-search-regex" /> Regular expression</label>
|
|
4401
|
+
<button type="submit" class="o-btn o-dark" [disabled]="!text.trim()">Search</button>
|
|
4402
|
+
</form>
|
|
4403
|
+
@if (error()) {<div class="o-note o-red" role="alert">{{ error() }}</div>}
|
|
4404
|
+
@if (searched()) {
|
|
4405
|
+
<span class="o-faint o-sm" aria-live="polite" data-testid="code-search-count">{{ hits().length }} {{ hits().length === 1 ? 'file' : 'files' }}{{ hits().length >= 50 ? ' (the first 50)' : '' }} on {{ r.defaultBranch }}</span>
|
|
4406
|
+
@for (h of hits(); track h.path) {
|
|
4407
|
+
<div class="o-card" [attr.data-testid]="'code-hit-' + h.path">
|
|
4408
|
+
<div class="o-ch" style="background:var(--o-well)"><a class="o-mono o-sm" [routerLink]="link('blob')" [queryParams]="{ path: h.path }">{{ h.path }}</a>@if (h.nameMatch && !h.lines.length) {<span class="o-faint o-sm">matches the file name</span>}</div>
|
|
4409
|
+
@for (l of h.lines; track l.number) {
|
|
4410
|
+
<a class="ln" [routerLink]="link('blob')" [queryParams]="{ path: h.path }" [fragment]="'L' + l.number"><span class="n">{{ l.number }}</span><span>@for (p of pieces(l.text, l.ranges); track $index) {@if (p.hit) {<mark>{{ p.text }}</mark>} @else {{{ p.text }}}}</span></a>
|
|
4411
|
+
}
|
|
4412
|
+
</div>
|
|
4413
|
+
} @empty {
|
|
4414
|
+
<div class="o-card"><div class="o-empty">Nothing matches on {{ r.defaultBranch }}.</div></div>
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
</div>
|
|
4419
|
+
`, isInline: true, styles: [".ln{display:flex;gap:10px;font-family:var(--o-mono);font-size:12px;padding:2px 12px;color:var(--o-tx);text-decoration:none;white-space:pre}.ln:hover{background:var(--o-well)}.ln .n{color:var(--o-faint);min-width:40px;text-align:right}mark{background:#fee484;color:inherit;border-radius:2px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4420
|
+
}
|
|
4421
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: CodeSearchPage, decorators: [{
|
|
4422
|
+
type: Component,
|
|
4423
|
+
args: [{ selector: 'o-code-search', imports: [FormsModule, RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4424
|
+
<div class="o-page o-wide">
|
|
4425
|
+
@if (repo(); as r) {
|
|
4426
|
+
<form class="o-flex o-wrap" (ngSubmit)="go()" role="search" aria-label="Search code">
|
|
4427
|
+
<input class="o-in o-mono" style="flex:1;min-width:220px" name="q" [(ngModel)]="text" placeholder="Search {{ r.name }} (default branch)" aria-label="Search code" data-testid="code-search-q" />
|
|
4428
|
+
<label class="o-flex o-sm"><input type="checkbox" name="regex" [(ngModel)]="regex" data-testid="code-search-regex" /> Regular expression</label>
|
|
4429
|
+
<button type="submit" class="o-btn o-dark" [disabled]="!text.trim()">Search</button>
|
|
4430
|
+
</form>
|
|
4431
|
+
@if (error()) {<div class="o-note o-red" role="alert">{{ error() }}</div>}
|
|
4432
|
+
@if (searched()) {
|
|
4433
|
+
<span class="o-faint o-sm" aria-live="polite" data-testid="code-search-count">{{ hits().length }} {{ hits().length === 1 ? 'file' : 'files' }}{{ hits().length >= 50 ? ' (the first 50)' : '' }} on {{ r.defaultBranch }}</span>
|
|
4434
|
+
@for (h of hits(); track h.path) {
|
|
4435
|
+
<div class="o-card" [attr.data-testid]="'code-hit-' + h.path">
|
|
4436
|
+
<div class="o-ch" style="background:var(--o-well)"><a class="o-mono o-sm" [routerLink]="link('blob')" [queryParams]="{ path: h.path }">{{ h.path }}</a>@if (h.nameMatch && !h.lines.length) {<span class="o-faint o-sm">matches the file name</span>}</div>
|
|
4437
|
+
@for (l of h.lines; track l.number) {
|
|
4438
|
+
<a class="ln" [routerLink]="link('blob')" [queryParams]="{ path: h.path }" [fragment]="'L' + l.number"><span class="n">{{ l.number }}</span><span>@for (p of pieces(l.text, l.ranges); track $index) {@if (p.hit) {<mark>{{ p.text }}</mark>} @else {{{ p.text }}}}</span></a>
|
|
4439
|
+
}
|
|
4440
|
+
</div>
|
|
4441
|
+
} @empty {
|
|
4442
|
+
<div class="o-card"><div class="o-empty">Nothing matches on {{ r.defaultBranch }}.</div></div>
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
</div>
|
|
4447
|
+
`, styles: [".ln{display:flex;gap:10px;font-family:var(--o-mono);font-size:12px;padding:2px 12px;color:var(--o-tx);text-decoration:none;white-space:pre}.ln:hover{background:var(--o-well)}.ln .n{color:var(--o-faint);min-width:40px;text-align:right}mark{background:#fee484;color:inherit;border-radius:2px}\n"] }]
|
|
4448
|
+
}], ctorParameters: () => [] });
|
|
4449
|
+
|
|
4326
4450
|
/*
|
|
4327
4451
|
* @chisquare-tech/origine-ngx-apps-code: the Code module's screens (TRD §6.10). The host app provides
|
|
4328
4452
|
* CodeHost and mounts the pages at /{org}/{project}/code, /code/new, /code/pulls and
|
|
@@ -4333,5 +4457,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
4333
4457
|
* Generated bundle index. Do not edit.
|
|
4334
4458
|
*/
|
|
4335
4459
|
|
|
4336
|
-
export { BranchesPage, CodeApi, CodeHost, CommitBox, CommitPage, CommitsPage, CurrentRepo, CurrentRepoPage, DiffView, FilePage, NewFilePage, NewRepoPage, People, PullPage, PullsPage, RefPicker, ReleasesPage, RepoHomePage, RepoPage, RepoSettingsPage, ReposPage, TOKEN_CSS, ago, apiMessage, checkDot, copy, dayLabel, initials, langColour, matchesPattern, pair, shortDate, size, verifyWhy };
|
|
4460
|
+
export { BranchesPage, CodeApi, CodeHost, CodeSearchPage, CommitBox, CommitPage, CommitsPage, CurrentRepo, CurrentRepoPage, DiffView, FilePage, NewFilePage, NewRepoPage, People, PullPage, PullsPage, RefPicker, ReleasesPage, RepoHomePage, RepoPage, RepoSettingsPage, ReposPage, TOKEN_CSS, ago, apiMessage, checkDot, copy, dayLabel, initials, langColour, matchesPattern, pair, shortDate, size, verifyWhy };
|
|
4337
4461
|
//# sourceMappingURL=chisquare-tech-origine-ngx-apps-code.mjs.map
|