Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6,230 changes: 6,230 additions & 0 deletions apps/console-fb/schema.graphql

Large diffs are not rendered by default.

125 changes: 125 additions & 0 deletions apps/console/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3829,6 +3829,29 @@ type query_root {
"""fetch data from the table: "subject_type" using primary key columns"""
subject_type_by_pk(value: String!): subject_type

"""
fetch data from the table: "test_rule"
"""
test_rule(
"""distinct select on columns"""
distinct_on: [test_rule_select_column!]

"""limit the number of rows returned"""
limit: Int

"""skip the first n rows. Use only with order_by"""
offset: Int

"""sort the rows by one or more columns"""
order_by: [test_rule_order_by!]

"""filter the rows returned"""
where: test_rule_bool_exp
): [test_rule!]!

"""fetch data from the table: "test_rule" using primary key columns"""
test_rule_by_pk(a: uuid!): test_rule

"""fetch data from the table: "auth.users" using primary key columns"""
user(id: uuid!): users

Expand Down Expand Up @@ -5072,6 +5095,43 @@ type subscription_root {
where: subject_type_bool_exp
): [subject_type!]!

"""
fetch data from the table: "test_rule"
"""
test_rule(
"""distinct select on columns"""
distinct_on: [test_rule_select_column!]

"""limit the number of rows returned"""
limit: Int

"""skip the first n rows. Use only with order_by"""
offset: Int

"""sort the rows by one or more columns"""
order_by: [test_rule_order_by!]

"""filter the rows returned"""
where: test_rule_bool_exp
): [test_rule!]!

"""fetch data from the table: "test_rule" using primary key columns"""
test_rule_by_pk(a: uuid!): test_rule

"""
fetch data from the table in a streaming manner: "test_rule"
"""
test_rule_stream(
"""maximum number of rows returned in a single batch"""
batch_size: Int!

"""cursor to stream the results returned by the query"""
cursor: [test_rule_stream_cursor_input]!

"""filter the rows returned"""
where: test_rule_bool_exp
): [test_rule!]!

"""fetch data from the table: "auth.users" using primary key columns"""
user(id: uuid!): users

Expand Down Expand Up @@ -5204,6 +5264,71 @@ type subscription_root {
): [users!]!
}

"""created by nithin, just for testing"""
type test_rule {
a: uuid!
b: timestamptz!
c: Boolean!
d: Int!
}

"""
Boolean expression to filter rows from the table "test_rule". All fields are combined with a logical 'AND'.
"""
input test_rule_bool_exp {
_and: [test_rule_bool_exp!]
_not: test_rule_bool_exp
_or: [test_rule_bool_exp!]
a: uuid_comparison_exp
b: timestamptz_comparison_exp
c: Boolean_comparison_exp
d: Int_comparison_exp
}

"""Ordering options when selecting data from "test_rule"."""
input test_rule_order_by {
a: order_by
b: order_by
c: order_by
d: order_by
}

"""
select columns of table "test_rule"
"""
enum test_rule_select_column {
"""column name"""
a

"""column name"""
b

"""column name"""
c

"""column name"""
d
}

"""
Streaming cursor of the table "test_rule"
"""
input test_rule_stream_cursor_input {
"""Stream column input with initial value"""
initial_value: test_rule_stream_cursor_value_input!

"""cursor ordering"""
ordering: cursor_ordering
}

"""Initial value of the column from where the streaming should start"""
input test_rule_stream_cursor_value_input {
a: uuid
b: timestamptz
c: Boolean
d: Int
}

scalar timestamp

"""
Expand Down
1 change: 1 addition & 0 deletions apps/console/src/lib/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { loadOptions } from './svelte_select_fetches';
26 changes: 26 additions & 0 deletions apps/console/src/lib/api/rules/[id]/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
// Replace this with actual database query
const rule = {
id: params.id,
displayName: 'Sample Rule',
description: 'This is a sample rule',
tags: ['sample', 'test'],
annotations: 'key1=>value1',
source: '192.168.1.1',
sourcePort: '80',
destination: '10.0.0.1',
destinationPort: '443',
protocol: 'TCP',
action: 'allow',
direction: 'inbound',
appId: 'app-123',
throttleRate: 50,
weight: 100,
shared: false,
};

return json(rule);
};
80 changes: 37 additions & 43 deletions apps/console/src/lib/api/search-rules.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,49 @@
// $lib/api/search-rules.ts
import { CachePolicy, type SearchRules$result, graphql, order_by } from '$houdini';
import type { PartialGraphQLErrors, Subject } from '$lib/types';
import type { Rule, RuleSearch } from '$lib/schema/rule';
import { Logger } from '@spectacular/utils';
import { type Result, err, ok } from 'neverthrow';
import type { GraphQLError } from 'graphql';

/**
* HINT: Using `neverthrow` lib's `Result` to annotate a functions
* https://x.com/mattpocockuk/status/1825552717571629306
*/
interface GQLResult<T> {
data: T | undefined;
errors: Partial<GraphQLError>[] | null;
}

const log = new Logger('api:rules:search');

const searchRules = graphql(`
query SearchRules(
$where: rules_bool_exp
$limit: Int = 50
$offset: Int = 0
$orderBy: [rules_order_by!] = [{ updatedAt: desc_nulls_last }]
) @cache(policy: NetworkOnly) {
rules(order_by: $orderBy, limit: $limit, offset: $offset, where: $where) {
id
displayName
description
tags
annotations
shared
source
sourcePort
destination
destinationPort
protocol
direction
action
appId
throttleRate
weight
updatedBy
updatedAt
}
}
`);

query SearchRules(
$where: rules_bool_exp
$limit: Int = 50
$offset: Int = 0
$orderBy: [rules_order_by!] = [{ updatedAt: desc_nulls_last }]
) @cache(policy: NetworkOnly) {
rules(order_by: $orderBy, limit: $limit, offset: $offset, where: $where) {
id
displayName
description
source
sourcePort
destination
destinationPort
protocol
action
direction
appId
throttleRate
weight
shared
updatedAt
}
}
`);
const limit = 10;
const orderBy = [{ updatedAt: order_by.desc_nulls_last }];

// TODO: throttle-debounce , prevent double calling, finish
export async function searchRulesFn(
displayNameTerm: string,
): Promise<Result<SearchRules$result['rules'], PartialGraphQLErrors>> {
if (displayNameTerm.length < 4) return ok([]);
export async function searchRulesFn(ruleNameTerm: string): Promise<GQLResult<Rule[]>> {
if ( ruleNameTerm.length < 4) return { data: [], errors: null };

const where = {
displayName: { _ilike: `%${displayNameTerm}%` },
displayName: { _ilike: `%${ruleNameTerm}%` },
};

const variables = { where, limit, orderBy };
Expand All @@ -61,5 +54,6 @@ export async function searchRulesFn(
metadata: { logResult: true },
variables,
});
return data?.rules ? ok(data.rules) : err(errors);

return { data: data?.rules as Rule[], errors };
}
1 change: 1 addition & 0 deletions apps/console/src/lib/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const menuNavLinks: MenuNavLinks = {
list: [
{ href: '/policies', label: 'Policies', keywords: 'svelte, sirens, license, release', preload: 'false' },
{ href: '/rules', label: 'Golden Rules', keywords: 'start, install, cli, tailwind, themes, stylesheets' },
{ href: '/testrule', label: 'testing Rules', keywords: 'start, install, cli, tailwind, themes, stylesheets' },
],
},
{
Expand Down
64 changes: 64 additions & 0 deletions apps/console/src/lib/schema/rule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { action_enum, direction_enum, protocol_enum } from '$houdini';
import { z } from 'zod';

/**
* Rule Schema
*/
export const ruleSchema = z.object({
id: z.string().trim().uuid(),
displayName: z.string().trim().min(4).max(256),
description: z.string().trim().max(256).nullish(),
tags: z.string().trim().min(2).array().max(5).default([]),
annotations: z.string().trim().nullish(), // TODO: validate map string
source: z.string().ip().nullish(),
sourcePort: z.string().trim().nullish(),
destination: z.string().ip().nullish(),
destinationPort: z.string().trim().nullish(),
protocol: z.nativeEnum(protocol_enum).default(protocol_enum.Any),
action: z.nativeEnum(action_enum).default(action_enum.block),
direction: z.nativeEnum(direction_enum).default(direction_enum.egress),
appId: z.string().trim().nullish(),
throttleRate: z.coerce.number().min(0).max(100).optional().default(80),
weight: z.coerce.number().min(0).max(1000).optional().default(1000),
shared: z.boolean().optional().default(false),
active: z.boolean().optional().default(true),
});

export type RuleSchema = typeof ruleSchema;
export type Rule = z.infer<typeof ruleSchema>;

/**
* Search Rule Schema
*/
export const ruleSearchSchema = z.object({
limit: z.number().int().min(5).max(100).default(10),
offset: z.number().int().min(0).default(0),
displayName: z.string().trim().optional(),
tags: z.array(z.string()).optional(),
});
export type RuleSearchSchema = typeof ruleSearchSchema;
export type RuleSearch = z.infer<typeof ruleSearchSchema>;

/**
* Create Rule Schema
*/
export const createRuleSchema = ruleSchema.omit({ id: true });

export type CreateRuleSchema = typeof createRuleSchema;
export type CreateRule = z.infer<typeof createRuleSchema>;
export const createRuleKeys = createRuleSchema.keyof().Enum;

/**
* Update Rule Schema
*/
export const updateRuleSchema = ruleSchema.partial().omit({ id: true }).extend({
originalShared: ruleSchema.shape.shared,
});

export type UpdateRuleSchema = typeof updateRuleSchema;
export type UpdateRule = z.infer<typeof updateRuleSchema>;
export const updateRuleKeys = updateRuleSchema.keyof().Enum;

/**
* Refine functions can be added here if needed
*/
48 changes: 48 additions & 0 deletions apps/console/src/lib/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
export enum LogLevel {
off = 0,
Debug,
Error,
Warning,
Info
}

export class Logger {
static level = LogLevel.Debug;

private source: string;

/**
* Enables production mode.
* Sets logging level to LogLevel.Warning.
*/
static enableProductionMode() {
Logger.level = LogLevel.Warning;
}

constructor(component: string) {
this.source = component;
}

public debug(...data: unknown[]): void {
this.log(console.info, LogLevel.Debug, data);
}

public info(...data: unknown[]): void {
this.log(console.info, LogLevel.Info, data);
}

public warn(...data: unknown[]): void {
this.log(console.warn, LogLevel.Warning, data);
}

public error(...data: unknown[]): void {
this.log(console.error, LogLevel.Error, data);
}

private log = (fun: () => void, level: LogLevel, objects: unknown[]): void => {
if (level >= Logger.level) {
const log = this.source ? [`[${this.source}]`].concat(objects as string[]) : objects;
fun.apply<Console, unknown[], void>(console, log);
}
};
}
Loading
Loading