Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/kamu-data/kamu-web-ui int…
Browse files Browse the repository at this point in the history
…o kamu-ui-406-detect-when-dataset-cache-is-stale
  • Loading branch information
Dmitriy Borzenko committed Sep 25, 2024
2 parents 29dd5e6 + 349ad50 commit 2635853
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Detect dataset cache after the flows are completed
- Added `Share query` button to the Data tab
### Fixed
- Added autofocus to the login field on the login page

## [0.26.4] - 2024-09-13
### Added
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import { AccountComponent } from "./account/account.component";
import { DatasetsTabComponent } from "./account/additional-components/datasets-tab/datasets-tab.component";
import { AccessTokensTabComponent } from "./auth/settings/tabs/access-tokens-tab/access-tokens-tab.component";
import { MatSlideToggleModule } from "@angular/material/slide-toggle";
import { AutofocusDirective } from "./common/directives/autofocus.directive";

const Services = [
{
Expand Down Expand Up @@ -204,6 +205,7 @@ const MatModules = [
AdminDashboardComponent,
AccessTokensTabComponent,
AccountFlowsTabComponent,
AutofocusDirective,
],
imports: [
AppRoutingModule,
Expand Down
7 changes: 3 additions & 4 deletions src/app/auth/login/login.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ <h1 class="text-center text-muted mt-4">Login to Kamu</h1>
class="form-control d-inline"
id="login"
data-test-id="input-login"
required
(keyup)="resetPasswordLoginError()"
(keyup)="onChangeInputField($event)"
appAutofocus
[class.error-border-color]="passwordLoginError$ | async"
/>
<div *ngIf="loginControl?.invalid && (loginControl?.touched || loginControl?.dirty)">
Expand All @@ -65,8 +65,7 @@ <h1 class="text-center text-muted mt-4">Login to Kamu</h1>
class="form-control d-inline"
id="password"
data-test-id="input-password"
required
(keyup)="resetPasswordLoginError()"
(keyup)="onChangeInputField($event)"
[class.error-border-color]="passwordLoginError$ | async"
/>
<div *ngIf="passwordControl?.invalid && (passwordControl?.touched || passwordControl?.dirty)">
Expand Down
6 changes: 6 additions & 0 deletions src/app/auth/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,10 @@ export class LoginComponent extends BaseComponent implements OnInit {
public resetPasswordLoginError(): void {
this.loginService.resetPasswordLoginError();
}

public onChangeInputField(event: KeyboardEvent): void {
if (event.key !== "Enter") {
this.resetPasswordLoginError();
}
}
}
14 changes: 14 additions & 0 deletions src/app/common/directives/autofocus.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { AfterViewInit, Directive, ElementRef, inject } from "@angular/core";

@Directive({
selector: "[appAutofocus]",
})
export class AutofocusDirective implements AfterViewInit {
private elementRef = inject(ElementRef);

ngAfterViewInit(): void {
setTimeout(() => {
(this.elementRef.nativeElement as HTMLElement).focus();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,32 @@ <h2 class="box-title align-items-center pb-3 pt-3 m-0">Saved Queries</h2>
<div class="sql-query-editor-header flex-column justify-content-between">
<h2 class="box-title align-items-center pb-3 m-0">Query:</h2>
<div class="btn-group-parent" *ngIf="dataUpdate$ | async as dataUpdate">
<button
data-test-id="runSqlQueryButton"
name="run sql button"
(click)="runSQLRequest({ query: sqlRequestCode }, true)"
[disabled]="!dataUpdate.schema?.fields?.length"
class="sql-run-button border border-1 rounded-left-2 border-right-0 btn-group-item btn d-flex justify-content-center align-items-center"
>
<span>Run</span><mat-icon>play_arrow</mat-icon>
</button>
<button
class="starred rounded-right-2 border-1 border btn-sm btn btn-group-item d-flex justify-content-center align-items-center"
[matMenuTriggerFor]="menu"
aria-label="Example icon-button with a menu"
data-test-id="searchAdditionalButtons"
>
<mat-icon>arrow_drop_down</mat-icon>
</button>
<div class="d-flex">
<button
data-test-id="shareSqlQueryButton"
(click)="shareQuery()"
class="share-query-button border border-1 rounded d-flex justify-content-center align-items-center me-4"
>
<span class="mr-1 button-text"> Share query</span><mat-icon>share</mat-icon>
</button>
<button
data-test-id="runSqlQueryButton"
name="run sql button"
(click)="runSQLRequest({ query: sqlRequestCode }, true)"
[disabled]="!dataUpdate.schema?.fields?.length"
class="sql-run-button border border-1 rounded-left-2 border-right-0 btn-group-item btn d-flex justify-content-center align-items-center"
>
<span>Run</span><mat-icon>play_arrow</mat-icon>
</button>
<button
class="starred rounded-right-2 border-1 border btn-sm btn btn-group-item d-flex justify-content-center align-items-center"
[matMenuTriggerFor]="menu"
aria-label="Example icon-button with a menu"
data-test-id="searchAdditionalButtons"
>
<mat-icon>arrow_drop_down</mat-icon>
</button>
</div>
<mat-menu #menu="matMenu">
<div class="select-menu-modal notifications-component-menu-modal">
<div class="select-menu-list">
Expand Down Expand Up @@ -136,7 +145,7 @@ <h2 class="box-title align-items-center pb-3 m-0">Query:</h2>
<ng-container *ngIf="!this.editorLoaded || sqlLoading">
<mat-progress-bar data-test-id="editor-progress-bar" class="position-absolute" mode="indeterminate" />
</ng-container>
<div class="border border-1 rounded-2 px-2 py-4 position-relative">
<div class="border border-1 rounded-2 px-2 py-4 position-relative mt-2">
<app-sql-editor
[(template)]="sqlRequestCode"
[error]="sqlErrorMarker$ | async"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,17 @@
color: #1a7f37;
width: min-content;
padding: 5px 10px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}

.share-query-button {
color: #1a7f37;
padding: 5px 10px;
font-weight: 700;
background: #f6f8fa;

.button-text {
font-size: 16px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ import { SqlEditorComponent } from "src/app/shared/editor/components/sql-editor/
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { HttpClientModule } from "@angular/common/http";
import { Apollo } from "apollo-angular";
import { ToastrModule } from "ngx-toastr";
import { ToastrModule, ToastrService } from "ngx-toastr";
import { Clipboard } from "@angular/cdk/clipboard";

describe("DataComponent", () => {
let component: DataComponent;
let fixture: ComponentFixture<DataComponent>;
let datasetSubsService: DatasetSubscriptionsService;
let location: Location;
let ngbModalService: NgbModal;
let clipboard: Clipboard;
let toastrService: ToastrService;

beforeEach(async () => {
await TestBed.configureTestingModule({
Expand All @@ -65,6 +68,8 @@ describe("DataComponent", () => {
datasetSubsService = TestBed.inject(DatasetSubscriptionsService);
location = TestBed.inject(Location);
ngbModalService = TestBed.inject(NgbModal);
clipboard = TestBed.inject(Clipboard);
toastrService = TestBed.inject(ToastrService);
component = fixture.componentInstance;
component.datasetBasics = mockDatasetBasicsDerivedFragment;
spyOn(location, "getState").and.returnValue({ start: 0, end: 100 });
Expand Down Expand Up @@ -184,4 +189,16 @@ describe("DataComponent", () => {
} as OverviewUpdate);
expect(ngbModalServiceSpy).toHaveBeenCalledTimes(1);
});

it("should check click on `Share query` button", fakeAsync(() => {
const toastServiceSpy = spyOn(toastrService, "success");
const clipboardCopySpy = spyOn(clipboard, "copy");
tick();
fixture.detectChanges();

emitClickOnElementByDataTestId(fixture, "shareSqlQueryButton");
expect(toastServiceSpy).toHaveBeenCalledWith("Copied url to clipboard");
expect(clipboardCopySpy).toHaveBeenCalledTimes(1);
flush();
}));
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import { DatasetFlowsService } from "../flows-component/services/dataset-flows.s
import { DatasetViewTypeEnum } from "../../dataset-view.interface";
import { NavigationService } from "src/app/services/navigation.service";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { Clipboard } from "@angular/cdk/clipboard";
import ProjectLinks from "src/app/project-links";
import { ToastrService } from "ngx-toastr";

@Component({
selector: "app-data",
Expand Down Expand Up @@ -57,6 +60,8 @@ export class DataComponent extends BaseComponent implements OnInit {
private datasetFlowsService = inject(DatasetFlowsService);
private navigationService = inject(NavigationService);
private cdr = inject(ChangeDetectorRef);
private clipboard = inject(Clipboard);
private toastService = inject(ToastrService);

public ngOnInit(): void {
this.overviewUpdate$ = this.datasetSubsService.overviewChanges;
Expand Down Expand Up @@ -107,10 +112,15 @@ export class DataComponent extends BaseComponent implements OnInit {
}

private buildSqlRequestCode(): void {
this.sqlRequestCode += `'${this.datasetBasics.alias}'`;
const offset = this.location.getState() as MaybeNull<Partial<OffsetInterval>>;
if (offset && typeof offset.start !== "undefined" && typeof offset.end !== "undefined") {
this.sqlRequestCode += `\nwhere ${this.offsetColumnName}>=${offset.start} and ${this.offsetColumnName}<=${offset.end}\norder by ${this.offsetColumnName} desc`;
const sqlQueryFromUrl = this.activatedRoute.snapshot.queryParamMap.get(ProjectLinks.URL_QUERY_PARAM_SQL_QUERY);
if (sqlQueryFromUrl) {
this.sqlRequestCode = sqlQueryFromUrl;
} else {
this.sqlRequestCode += `'${this.datasetBasics.alias}'`;
const offset = this.location.getState() as MaybeNull<Partial<OffsetInterval>>;
if (offset && typeof offset.start !== "undefined" && typeof offset.end !== "undefined") {
this.sqlRequestCode += `\nwhere ${this.offsetColumnName}>=${offset.start} and ${this.offsetColumnName}<=${offset.end}\norder by ${this.offsetColumnName} desc`;
}
}
}

Expand All @@ -131,6 +141,13 @@ export class DataComponent extends BaseComponent implements OnInit {
}
}

public shareQuery(): void {
const url = new URL(`${window.location.href}`);
url.searchParams.set(ProjectLinks.URL_QUERY_PARAM_SQL_QUERY, this.sqlRequestCode);
this.clipboard.copy(url.href);
this.toastService.success("Copied url to clipboard");
}

private updateNow(): void {
this.datasetFlowsService
.datasetTriggerFlow({
Expand Down
1 change: 1 addition & 0 deletions src/app/project-links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ export default class ProjectLinks {
public static readonly URL_QUERY_PARAM_CALLBACK_URL: string = "callbackUrl";
public static readonly URL_QUERY_PARAM_PUSH_SOURCE_NAME: string = "name";
public static readonly URL_QUERY_PARAM_SECTION: string = "section";
public static readonly URL_QUERY_PARAM_SQL_QUERY: string = "sqlQuery";
}

0 comments on commit 2635853

Please sign in to comment.