Skip to content

Commit 0b9204f

Browse files
committed
WIP
1 parent 6c50dba commit 0b9204f

File tree

7 files changed

+267
-4
lines changed

7 files changed

+267
-4
lines changed

bin/si/deno.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/si/src/cli.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { type ComponentGetOptions } from "./component/get.ts";
4040
import { type ComponentUpdateOptions } from "./component/update.ts";
4141
import { type ComponentDeleteOptions } from "./component/delete.ts";
4242
import { type ComponentSearchOptions } from "./component/search.ts";
43+
import { callTui } from "./command/tui.ts";
4344

4445
/** Current version of the SI CLI */
4546
const VERSION = "0.1.0";
@@ -175,7 +176,9 @@ function buildCommand() {
175176
// deno-lint-ignore no-explicit-any
176177
.command("template", buildTemplateCommand() as any)
177178
// deno-lint-ignore no-explicit-any
178-
.command("whoami", buildWhoamiCommand() as any);
179+
.command("whoami", buildWhoamiCommand() as any)
180+
// deno-lint-ignore no-explicit-any
181+
.command("tui", buildTuiCommand() as any);
179182
}
180183

181184
/**
@@ -267,7 +270,7 @@ function buildRemoteSchemaCommand() {
267270
"--builtins",
268271
"Include builtin schemas (schemas you don't own). By default, builtins are skipped.",
269272
)
270-
.action(async ({ root, apiBaseUrl, apiToken, builtins }, ...schemaNames) => {
273+
.action(async ({ root, apiBaseUrl, apiToken }, ...schemaNames) => {
271274
const project = createProject(root);
272275
const apiCtx = await createApiContext(apiBaseUrl, apiToken);
273276
let finalSchemaNames;
@@ -282,7 +285,6 @@ function buildRemoteSchemaCommand() {
282285
project,
283286
apiCtx,
284287
finalSchemaNames,
285-
builtins ?? false,
286288
);
287289
}),
288290
)
@@ -355,6 +357,22 @@ function buildWhoamiCommand() {
355357
});
356358
}
357359

360+
/**
361+
* Builds the tui command.
362+
*
363+
* @returns A SubCommand to start the TUI
364+
* @internal
365+
*/
366+
function buildTuiCommand() {
367+
return createSubCommand()
368+
.description("Starts the TUI")
369+
.action(async ({ apiBaseUrl, apiToken }) => {
370+
const apiCtx = await createApiContext(apiBaseUrl, apiToken);
371+
372+
await callTui(Context.instance(), apiCtx);
373+
});
374+
}
375+
358376
/**
359377
* Builds the project init subcommands.
360378
*

bin/si/src/command/tui.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Context } from "../context.ts";
2+
import { ApiContext } from "../api.ts";
3+
import * as p from 'npm:@clack/prompts';
4+
import color from 'npm:picocolors';
5+
import { apiConfig } from "../si_client.ts";
6+
import { ChangeSetsApi, ChangeSetViewV1 } from "https://jsr.io/@systeminit/api-client/1.9.0/api.ts";
7+
8+
const EXIT = "-1";
9+
10+
export async function callTui(ctx: Context, _apiCtx: ApiContext) {
11+
const changeSetsApi = new ChangeSetsApi(apiConfig);
12+
const workspaceId = ctx.workspaceId;
13+
if (!workspaceId) throw new Error("No Workspace");
14+
15+
p.updateSettings({
16+
aliases: {
17+
w: 'up',
18+
s: 'down',
19+
a: 'left',
20+
d: 'right',
21+
},
22+
});
23+
24+
p.intro("Welcome! Let's review propsed changes in your workspace")
25+
26+
const cs = p.spinner({
27+
onCancel: () => {
28+
process.exit(0);
29+
}
30+
});
31+
cs.start("Retrieving change sets");
32+
const response = await changeSetsApi.listChangeSets({ workspaceId });
33+
const changeSets = response.data.changeSets as ChangeSetViewV1[];
34+
cs.stop();
35+
36+
const options = changeSets.map((c) => {
37+
return {
38+
value: c.id,
39+
label: c.name,
40+
}
41+
})
42+
const csId = await p.select({
43+
message: "Choose a change set:",
44+
options,
45+
});
46+
47+
if (p.isCancel(csId)) {
48+
p.cancel("Cancelled, exiting...")
49+
process.exit(0);
50+
}
51+
52+
const c = p.spinner();
53+
c.start("Retrieving components");
54+
c.stop();
55+
56+
while (true) {
57+
const componentId = await p.select({
58+
message: "Choose a component to review:",
59+
options: [
60+
{value: EXIT, label: "[quit]"}
61+
],
62+
});
63+
if (p.isCancel(componentId)) {
64+
p.cancel("Cancelled, exiting...")
65+
process.exit(0);
66+
}
67+
if (componentId === EXIT) break;
68+
}
69+
70+
p.outro("Goodbye");
71+
}

lib/luminork-server/src/service/v1.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod components;
1010
mod debug_funcs;
1111
mod funcs;
1212
mod management_funcs;
13+
mod mv;
1314
mod schemas;
1415
mod search;
1516
mod secrets;
@@ -132,6 +133,7 @@ pub use management_funcs::{
132133
ManagementFuncsResult,
133134
get_management_func_run_state::GetManagementFuncJobStateV1Response,
134135
};
136+
pub use mv::get::MvResponse;
135137
pub use schemas::{
136138
DetachFuncBindingV1Response,
137139
GetSchemaV1Response,
@@ -266,6 +268,7 @@ pub use crate::api_types::func_run::v1::{
266268
secrets::update_secret::update_secret,
267269
secrets::get_secrets::get_secrets,
268270
search::search,
271+
mv::get::get,
269272
),
270273
components(
271274
schemas(
@@ -364,6 +367,7 @@ pub use crate::api_types::func_run::v1::{
364367
ExecDebugFuncV1Request,
365368
ExecDebugFuncV1Response,
366369
GetDebugFuncJobStateV1Response,
370+
MvResponse,
367371
)
368372
),
369373
tags(
@@ -375,7 +379,8 @@ pub use crate::api_types::func_run::v1::{
375379
(name = "secrets", description = "Secret management endpoints"),
376380
(name = "funcs", description = "Functions management endpoints"),
377381
(name = "debug_funcs", description = "Debug function endpoints"),
378-
(name = "management_funcs", description = "Management functions endpoints")
382+
(name = "management_funcs", description = "Management functions endpoints"),
383+
(name = "mv", description = "Materialized view endpoints"),
379384
)
380385
)]
381386
pub struct V1ApiDoc;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use axum::{
2+
Json,
3+
extract::Query,
4+
};
5+
use sdf_extract::FriggStore;
6+
use serde::{
7+
Deserialize,
8+
Serialize,
9+
};
10+
use si_frontend_mv_types::object::FrontendObject;
11+
use utoipa::{
12+
IntoParams,
13+
ToSchema,
14+
};
15+
16+
use super::{
17+
MvError,
18+
MvResult,
19+
};
20+
use crate::extract::change_set::ChangeSetDalContext;
21+
22+
#[derive(Deserialize, Serialize, ToSchema, IntoParams, Debug, Clone)]
23+
#[serde(rename_all = "camelCase")]
24+
pub struct GetParams {
25+
#[schema(example = "01H9ZQD35JPMBGHH69BT0Q79VY", nullable = false, value_type = String)]
26+
pub entity_id: String,
27+
#[schema(example = "ComponentList", nullable = false, value_type = String)]
28+
pub kind: String,
29+
}
30+
31+
#[derive(Deserialize, Serialize, Debug, ToSchema, Clone)]
32+
#[serde(rename_all = "camelCase")]
33+
pub struct MvResponse {
34+
#[schema(example = "ComponentList")]
35+
pub kind: String,
36+
#[schema(example = "")]
37+
pub id: String,
38+
#[schema(example = "")]
39+
pub checksum: String,
40+
#[schema(example = "{}")]
41+
pub data: serde_json::Value,
42+
}
43+
44+
#[utoipa::path(
45+
get,
46+
path = "/v1/{workspace_id}/change-sets/{change_set_id}/mv",
47+
params(
48+
("workspace_id" = String, Path, description = "Workspace identifier"),
49+
("change_set_id" = String, Path, description = "Change Set identifier"),
50+
GetParams,
51+
),
52+
tag = "mv",
53+
summary = "Identifiers for a materialized view",
54+
responses(
55+
(status = 200, description = "Mv retrieved successfully", body = MvResponse),
56+
(status = 404, description = "Mv not found"),
57+
(status = 500, description = "Internal server error", body = crate::service::v1::common::ApiError)
58+
)
59+
)]
60+
pub async fn get(
61+
ChangeSetDalContext(ref ctx): ChangeSetDalContext,
62+
Query(params): Query<GetParams>,
63+
FriggStore(frigg): FriggStore,
64+
) -> MvResult<Json<MvResponse>> {
65+
let obj = frigg
66+
.get_current_workspace_object(
67+
ctx.workspace_pk()?,
68+
ctx.change_set_id(),
69+
&params.kind,
70+
&params.entity_id,
71+
)
72+
.await?;
73+
match obj {
74+
Some(FrontendObject {
75+
kind,
76+
id,
77+
checksum,
78+
data,
79+
}) => Ok(Json(MvResponse {
80+
kind,
81+
id,
82+
checksum,
83+
data,
84+
})),
85+
None => Err(MvError::NotFound(params.kind, params.entity_id)),
86+
}
87+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use axum::{
2+
Router,
3+
http::StatusCode,
4+
response::IntoResponse,
5+
routing::get,
6+
};
7+
use dal::TransactionsError;
8+
use frigg::FriggError;
9+
use thiserror::Error;
10+
11+
use crate::AppState;
12+
13+
pub mod get;
14+
15+
#[remain::sorted]
16+
#[derive(Debug, Error)]
17+
pub enum MvError {
18+
#[error("decode error: {0}")]
19+
Decode(#[from] ulid::DecodeError),
20+
#[error("frigg error: {0}")]
21+
Frigg(#[from] FriggError),
22+
#[error("join error: {0}")]
23+
Join(#[from] tokio::task::JoinError),
24+
#[error("MV not found error: {0} {1}")]
25+
NotFound(String, String),
26+
#[error("slow runtime error: {0}")]
27+
SlowRuntime(#[from] dal::slow_rt::SlowRuntimeError),
28+
#[error("transactions error: {0}")]
29+
Transactions(#[from] TransactionsError),
30+
#[error("workspace snapshot error: {0}")]
31+
WorkspaceSnapshot(#[from] dal::WorkspaceSnapshotError),
32+
}
33+
34+
impl IntoResponse for MvError {
35+
fn into_response(self) -> axum::response::Response {
36+
use crate::service::v1::common::ErrorIntoResponse;
37+
self.to_api_response()
38+
}
39+
}
40+
41+
impl crate::service::v1::common::ErrorIntoResponse for MvError {
42+
fn status_and_message(&self) -> (StatusCode, String) {
43+
match self {
44+
MvError::NotFound(_kind, _id) => (StatusCode::NOT_FOUND, self.to_string()),
45+
_ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
46+
}
47+
}
48+
}
49+
50+
pub fn routes() -> Router<AppState> {
51+
Router::new().route("/", get(get::get))
52+
}
53+
54+
pub type MvResult<T> = Result<T, MvError>;

lib/luminork-server/src/service/v1/workspaces.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub fn routes(state: AppState) -> Router<AppState> {
7474
.nest("/actions", super::actions::routes())
7575
.nest("/secrets", super::secrets::routes())
7676
.nest("/management-funcs", super::management_funcs::routes())
77+
.nest("/mv", super::mv::routes())
7778
.nest("/debug-funcs", super::debug_funcs::routes())
7879
.route(
7980
"/request_approval",

0 commit comments

Comments
 (0)