diff --git a/crates/arroyo-api/src/lib.rs b/crates/arroyo-api/src/lib.rs index d022fd47e..341e56976 100644 --- a/crates/arroyo-api/src/lib.rs +++ b/crates/arroyo-api/src/lib.rs @@ -26,8 +26,9 @@ use crate::jobs::{ use crate::metrics::__path_get_operator_metric_groups; use crate::pipelines::__path_get_pipelines; use crate::pipelines::{ - __path_create_pipeline, __path_delete_pipeline, __path_get_pipeline, __path_get_pipeline_jobs, - __path_patch_pipeline, __path_restart_pipeline, __path_validate_query, + __path_create_pipeline, __path_create_preview_pipeline, __path_delete_pipeline, + __path_get_pipeline, __path_get_pipeline_jobs, __path_patch_pipeline, __path_restart_pipeline, + __path_validate_query, }; use crate::rest::__path_ping; use crate::rest_utils::{service_unavailable, ErrorResp}; @@ -207,6 +208,7 @@ impl IntoResponse for HttpError { validate_query, validate_udf, create_pipeline, + create_preview_pipeline, patch_pipeline, restart_pipeline, get_pipeline, @@ -237,6 +239,7 @@ impl IntoResponse for HttpError { components(schemas( ErrorResp, PipelinePost, + PreviewPost, PipelinePatch, PipelineRestart, Pipeline, diff --git a/crates/arroyo-api/src/pipelines.rs b/crates/arroyo-api/src/pipelines.rs index d60b7911e..a9eb42e89 100644 --- a/crates/arroyo-api/src/pipelines.rs +++ b/crates/arroyo-api/src/pipelines.rs @@ -10,20 +10,20 @@ use petgraph::{Direction, EdgeDirection}; use std::collections::HashMap; use petgraph::visit::NodeRef; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use crate::{compiler_service, connection_profiles, jobs, types}; use arroyo_datastream::default_sink; use arroyo_rpc::api_types::pipelines::{ - Job, Pipeline, PipelinePatch, PipelinePost, PipelineRestart, QueryValidationResult, StopType, - ValidateQueryPost, + Job, Pipeline, PipelinePatch, PipelinePost, PipelineRestart, PreviewPost, + QueryValidationResult, StopType, ValidateQueryPost, }; use arroyo_rpc::api_types::udfs::{GlobalUdf, Udf}; use arroyo_rpc::api_types::{JobCollection, PaginationQueryParams, PipelineCollection}; use arroyo_rpc::grpc::api::{ArrowProgram, ConnectorOp}; use arroyo_connectors::kafka::{KafkaConfig, KafkaTable, SchemaRegistry}; -use arroyo_datastream::logical::{LogicalProgram, OperatorName}; +use arroyo_datastream::logical::{LogicalNode, LogicalProgram, OperatorName}; use arroyo_df::{has_duplicate_udf_names, ArroyoSchemaProvider, CompiledSql, SqlConfig}; use arroyo_formats::ser::ArrowSerializer; use arroyo_rpc::formats::Format; @@ -51,7 +51,9 @@ use crate::udfs::build_udf; use crate::AuthData; use crate::{connection_tables, to_micros}; use arroyo_rpc::config::config; +use arroyo_types::to_millis; use cornucopia_async::{Database, DatabaseSource}; +use petgraph::prelude::EdgeRef; async fn compile_sql<'a>( query: String, @@ -266,14 +268,17 @@ async fn register_schemas(compiled_sql: &mut CompiledSql) -> anyhow::Result<()> } pub(crate) async fn create_pipeline_int<'a>( - req: &PipelinePost, - pub_id: &str, + name: String, + query: String, + udfs: Vec<Udf>, + parallelism: u64, + checkpoint_interval: Duration, + is_preview: bool, + enable_sinks: bool, auth: AuthData, db: &DatabaseSource, -) -> Result<(i64, LogicalProgram), ErrorResp> { - let is_preview = req.preview.unwrap_or(false); - - if req.parallelism > auth.org_metadata.max_parallelism as u64 { +) -> Result<String, ErrorResp> { + if parallelism > auth.org_metadata.max_parallelism as u64 { return Err(bad_request(format!( "Your plan allows you to run pipelines up to parallelism {}; contact support@arroyo.systems for an increase", @@ -281,15 +286,10 @@ pub(crate) async fn create_pipeline_int<'a>( ))); } - let mut compiled = compile_sql( - req.query.clone(), - req.udfs.as_ref().unwrap_or(&vec![]), - req.parallelism as usize, - &auth, - false, - db, - ) - .await?; + let pub_id = generate_id(IdTypes::Pipeline); + + let mut compiled = + compile_sql(query.clone(), &udfs, parallelism as usize, &auth, false, db).await?; if compiled.program.graph.node_count() > auth.org_metadata.max_operators as usize { return Err(bad_request( @@ -297,13 +297,38 @@ pub(crate) async fn create_pipeline_int<'a>( contact support@arroyo.systems for an increase", auth.org_metadata.max_operators))); } - set_parallelism(&mut compiled.program, req.parallelism as usize); - - if is_preview && !config().sinks_in_preview { - for node in compiled.program.graph.node_weights_mut() { - // replace all sink connectors with websink for preview - if node.operator_name == OperatorName::ConnectorSink { - node.operator_config = default_sink().encode_to_vec(); + set_parallelism(&mut compiled.program, parallelism as usize); + + if is_preview { + // in Preview, we either replace sinks with a preview sink, or add a preview sink + // next to them depending on the `enable_sinks` option + let g = &mut compiled.program.graph; + for idx in g.node_indices() { + let should_replace = { + let node = g.node_weight(idx).unwrap(); + node.operator_name == OperatorName::ConnectorSink + && node.operator_config != default_sink().encode_to_vec() + }; + if should_replace { + if enable_sinks { + let new_idx = g.add_node(LogicalNode { + operator_id: format!("{}_1", g.node_weight(idx).unwrap().operator_id), + description: "Preview sink".to_string(), + operator_name: OperatorName::ConnectorSink, + operator_config: default_sink().encode_to_vec(), + parallelism: 1, + }); + let edges: Vec<_> = g + .edges_directed(idx, Direction::Incoming) + .map(|e| (e.source(), e.weight().clone())) + .collect(); + for (source, weight) in edges { + g.add_edge(source, new_idx, weight); + } + } else { + g.node_weight_mut(idx).unwrap().operator_config = + default_sink().encode_to_vec(); + } } } } @@ -323,21 +348,19 @@ pub(crate) async fn create_pipeline_int<'a>( let program_bytes = proto_program.encode_to_vec(); - if req.name.is_empty() { + if name.is_empty() { return Err(required_field("name")); } - let udfs = serde_json::to_value(req.udfs.as_ref().unwrap_or(&vec![])).unwrap(); - api_queries::execute_create_pipeline( &db.client().await?, &pub_id, &auth.organization_id, &auth.user_id, - &req.name, + &name, &PipelineType::sql, - &Some(req.query.clone()), - &udfs, + &Some(query.clone()), + &serde_json::to_value(&udfs).unwrap(), &program_bytes, &2, ) @@ -363,7 +386,30 @@ pub(crate) async fn create_pipeline_int<'a>( } } - Ok((pipeline_id, compiled.program)) + let job_id = jobs::create_job( + &name, + pipeline_id, + checkpoint_interval, + is_preview, + &auth, + &db, + ) + .await?; + + log_event( + "job_created", + json!({ + "service": "api", + "is_preview": is_preview, + "job_id": job_id, + "parallelism": parallelism, + "has_udfs": udfs.first().map(|e| !e.definition.trim().is_empty()).unwrap_or(false), + // TODO: program features + "features": compiled.program.features(), + }), + ); + + Ok(pub_id) } impl TryInto<Pipeline> for DbPipeline { @@ -492,58 +538,67 @@ pub async fn create_pipeline( ) -> Result<Json<Pipeline>, ErrorResp> { let auth_data = authenticate(&state.database, bearer_auth).await?; - let pipeline_pub_id = generate_id(IdTypes::Pipeline); - //let transaction = db.transaction().await?; - - let (pipeline_id, program) = create_pipeline_int( - &pipeline_post, - &pipeline_pub_id, - auth_data.clone(), - &state.database, - ) - .await?; - - let preview = pipeline_post.preview.unwrap_or(false); - let checkpoint_interval = pipeline_post .checkpoint_interval_micros .map(Duration::from_micros) .unwrap_or(*config().default_checkpoint_interval); - let job_id = jobs::create_job( - &pipeline_post.name, - pipeline_id, + let pipeline_id = create_pipeline_int( + pipeline_post.name, + pipeline_post.query, + pipeline_post.udfs.unwrap_or_default(), + pipeline_post.parallelism, checkpoint_interval, - preview, - &auth_data, + false, + true, + auth_data.clone(), &state.database, ) .await?; // transaction.commit().await?; - log_event( - "job_created", - json!({ - "service": "api", - "is_preview": preview, - "job_id": job_id, - "parallelism": pipeline_post.parallelism, - "has_udfs": pipeline_post.udfs.map(|e| !e.is_empty() && !e[0].definition.trim().is_empty()) - .unwrap_or(false), - // TODO: program features - "features": program.features(), - }), - ); + let pipeline = + query_pipeline_by_pub_id(&pipeline_id, &state.database.client().await?, &auth_data).await?; - let pipeline = query_pipeline_by_pub_id( - &pipeline_pub_id, - &state.database.client().await?, - &auth_data, + Ok(Json(pipeline)) +} + +/// Create a new preview pipeline +#[utoipa::path( + post, + path = "/v1/pipelines/preview", + tag = "pipelines", + request_body = PreviewPost, + responses( + (status = 200, description = "Created pipeline and job", body = Pipeline), + (status = 400, description = "Bad request", body = ErrorResp), + ), +)] +pub async fn create_preview_pipeline( + State(state): State<AppState>, + bearer_auth: BearerAuth, + WithRejection(Json(req), _): WithRejection<Json<PreviewPost>, ApiError>, +) -> Result<Json<Pipeline>, ErrorResp> { + let auth_data = authenticate(&state.database, bearer_auth).await?; + + let pipeline_id = create_pipeline_int( + format!("preview_{}", to_millis(SystemTime::now())), + req.query, + req.udfs.unwrap_or_default(), + 1, + Duration::MAX, + true, + req.enable_sinks, + auth_data.clone(), + &state.database, ) .await?; + let pipeline = + query_pipeline_by_pub_id(&pipeline_id, &state.database.client().await?, &auth_data).await?; + Ok(Json(pipeline)) } diff --git a/crates/arroyo-api/src/rest.rs b/crates/arroyo-api/src/rest.rs index bff85211d..6b45b15ee 100644 --- a/crates/arroyo-api/src/rest.rs +++ b/crates/arroyo-api/src/rest.rs @@ -25,8 +25,8 @@ use crate::jobs::{ }; use crate::metrics::get_operator_metric_groups; use crate::pipelines::{ - create_pipeline, delete_pipeline, get_pipeline, get_pipeline_jobs, get_pipelines, - patch_pipeline, restart_pipeline, validate_query, + create_pipeline, create_preview_pipeline, delete_pipeline, get_pipeline, get_pipeline_jobs, + get_pipelines, patch_pipeline, restart_pipeline, validate_query, }; use crate::rest_utils::not_found; use crate::udfs::{create_udf, delete_udf, get_udfs, validate_udf}; @@ -162,6 +162,7 @@ pub fn create_rest_app(database: DatabaseSource, controller_addr: &str) -> Route .route("/udfs/validate", post(validate_udf)) .route("/udfs/:id", delete(delete_udf)) .route("/pipelines", post(create_pipeline)) + .route("/pipelines/preview", post(create_preview_pipeline)) .route("/pipelines", get(get_pipelines)) .route("/jobs", get(get_jobs)) .route("/pipelines/validate_query", post(validate_query)) diff --git a/crates/arroyo-api/src/udfs.rs b/crates/arroyo-api/src/udfs.rs index a9ff96761..496d0764f 100644 --- a/crates/arroyo-api/src/udfs.rs +++ b/crates/arroyo-api/src/udfs.rs @@ -81,8 +81,8 @@ pub async fn create_udf( api_queries::execute_create_udf( &client, &pub_id, - &auth_data.user_id, &auth_data.organization_id, + &auth_data.user_id, &req.prefix, &udf_name, &req.definition, diff --git a/crates/arroyo-connectors/src/preview/operator.rs b/crates/arroyo-connectors/src/preview/operator.rs index 3bee4b9e8..3ba78ceee 100644 --- a/crates/arroyo-connectors/src/preview/operator.rs +++ b/crates/arroyo-connectors/src/preview/operator.rs @@ -1,18 +1,21 @@ use arrow::array::{RecordBatch, TimestampNanosecondArray}; -use arrow::json::writer::record_batch_to_vec; -use std::time::SystemTime; +use arrow::json::writer::JsonArray; +use arrow::json::{Writer, WriterBuilder}; +use std::collections::HashMap; use arroyo_operator::context::ArrowContext; use arroyo_operator::operator::ArrowOperator; use arroyo_rpc::config::config; use arroyo_rpc::grpc::controller_grpc_client::ControllerGrpcClient; -use arroyo_rpc::grpc::SinkDataReq; -use arroyo_types::{from_nanos, to_micros, SignalMessage}; +use arroyo_rpc::grpc::{SinkDataReq, TableConfig}; +use arroyo_state::global_table_config; +use arroyo_types::{from_nanos, to_micros, CheckpointBarrier, SignalMessage}; use tonic::transport::Channel; #[derive(Default)] pub struct PreviewSink { client: Option<ControllerGrpcClient<Channel>>, + row: usize, } #[async_trait::async_trait] @@ -21,7 +24,18 @@ impl ArrowOperator for PreviewSink { "Preview".to_string() } - async fn on_start(&mut self, _: &mut ArrowContext) { + fn tables(&self) -> HashMap<String, TableConfig> { + global_table_config( + "s", + "Number of rows of output produced by this preview sink", + ) + } + + async fn on_start(&mut self, ctx: &mut ArrowContext) { + let table = ctx.table_manager.get_global_keyed_state("s").await.unwrap(); + + self.row = *table.get(&ctx.task_info.task_index).unwrap_or(&0); + self.client = Some( ControllerGrpcClient::connect(config().controller_endpoint()) .await @@ -31,39 +45,56 @@ impl ArrowOperator for PreviewSink { async fn process_batch(&mut self, mut batch: RecordBatch, ctx: &mut ArrowContext) { let ts = ctx.in_schemas[0].timestamp_index; - let timestamp_column = batch + let timestamps: Vec<_> = batch .column(ts) .as_any() .downcast_ref::<TimestampNanosecondArray>() .unwrap() - .clone(); + .iter() + .map(|t| to_micros(from_nanos(t.unwrap_or(0).max(0) as u128))) + .collect(); batch.remove_column(ts); - let rows = record_batch_to_vec(&batch, true, arrow::json::writer::TimestampFormat::RFC3339) + let mut buf = Vec::with_capacity(batch.get_array_memory_size()); + + let mut writer: Writer<_, JsonArray> = WriterBuilder::new() + .with_explicit_nulls(true) + .with_timestamp_format(arrow::json::writer::TimestampFormat::RFC3339) + .build(&mut buf); + + writer.write(&batch).unwrap(); + + writer.finish().unwrap(); + + self.client + .as_mut() + .unwrap() + .send_sink_data(SinkDataReq { + job_id: ctx.task_info.job_id.clone(), + operator_id: ctx.task_info.operator_id.clone(), + subtask_index: ctx.task_info.task_index as u32, + timestamps, + batch: String::from_utf8(buf).unwrap_or_else(|_| String::new()), + start_id: self.row as u64, + done: false, + }) + .await + .unwrap(); + + self.row += batch.num_rows(); + } + + async fn handle_checkpoint(&mut self, _: CheckpointBarrier, ctx: &mut ArrowContext) { + let table = ctx + .table_manager + .get_global_keyed_state::<usize, usize>("s") + .await .unwrap(); - for (value, timestamp) in rows.into_iter().zip(timestamp_column.iter()) { - let s = String::from_utf8(value).unwrap(); - self.client - .as_mut() - .unwrap() - .send_sink_data(SinkDataReq { - job_id: ctx.task_info.job_id.clone(), - operator_id: ctx.task_info.operator_id.clone(), - subtask_index: ctx.task_info.task_index as u32, - timestamp: to_micros( - timestamp - .map(|nanos| from_nanos(nanos as u128)) - .unwrap_or_else(SystemTime::now), - ), - value: s, - done: false, - }) - .await - .unwrap(); - } + table.insert(ctx.task_info.task_index, self.row).await; } + async fn on_close(&mut self, _: &Option<SignalMessage>, ctx: &mut ArrowContext) { self.client .as_mut() @@ -72,8 +103,9 @@ impl ArrowOperator for PreviewSink { job_id: ctx.task_info.job_id.clone(), operator_id: ctx.task_info.operator_id.clone(), subtask_index: ctx.task_info.task_index as u32, - timestamp: to_micros(SystemTime::now()), - value: "".to_string(), + timestamps: vec![], + batch: "[]".to_string(), + start_id: self.row as u64, done: true, }) .await diff --git a/crates/arroyo-controller/src/lib.rs b/crates/arroyo-controller/src/lib.rs index 9a63c2d7a..429f4fade 100644 --- a/crates/arroyo-controller/src/lib.rs +++ b/crates/arroyo-controller/src/lib.rs @@ -372,8 +372,10 @@ impl ControllerGrpc for ControllerServer { if let Some(v) = data_txs.get_mut(&req.job_id) { let output = OutputData { operator_id: req.operator_id, - timestamp: req.timestamp, - value: req.value, + subtask_idx: req.subtask_index, + timestamps: req.timestamps, + batch: req.batch, + start_id: req.start_id, done: req.done, }; diff --git a/crates/arroyo-controller/src/states/running.rs b/crates/arroyo-controller/src/states/running.rs index 9141e5948..8e3b82776 100644 --- a/crates/arroyo-controller/src/states/running.rs +++ b/crates/arroyo-controller/src/states/running.rs @@ -115,7 +115,14 @@ impl State for Running { "service": "controller", "job_id": ctx.config.id, "error": format!("{:?}", err), + "is_preview": ctx.config.ttl.is_some(), })); + + // only allow one restart for preview pipelines + if ctx.config.ttl.is_some() { + return Err(fatal("Job encountered a fatal error; see worker logs for details", err)); + } + if pipeline_config.allowed_restarts != -1 && ctx.status.restarts >= pipeline_config.allowed_restarts { return Err(fatal( "Job has restarted too many times", diff --git a/crates/arroyo-rpc/proto/rpc.proto b/crates/arroyo-rpc/proto/rpc.proto index d63660001..3d279051b 100644 --- a/crates/arroyo-rpc/proto/rpc.proto +++ b/crates/arroyo-rpc/proto/rpc.proto @@ -125,9 +125,10 @@ message SinkDataReq { string job_id = 1; string operator_id = 2; uint32 subtask_index = 3; - uint64 timestamp = 4; - string value = 6; - bool done = 7; + repeated uint64 timestamps = 4; + uint64 start_id = 6; + string batch = 7; + bool done = 8; } message SinkDataResp { @@ -149,9 +150,11 @@ message GrpcOutputSubscription { message OutputData { string operator_id = 1; - uint64 timestamp = 2; - string value = 4; - bool done = 5; + uint32 subtask_idx = 2; + repeated uint64 timestamps = 3; + uint64 start_id = 4; + string batch = 5; + bool done = 6; } message WorkerErrorReq { diff --git a/crates/arroyo-rpc/src/api_types/pipelines.rs b/crates/arroyo-rpc/src/api_types/pipelines.rs index 32e3a5909..c9cfedc0e 100644 --- a/crates/arroyo-rpc/src/api_types/pipelines.rs +++ b/crates/arroyo-rpc/src/api_types/pipelines.rs @@ -23,11 +23,19 @@ pub struct PipelinePost { pub name: String, pub query: String, pub udfs: Option<Vec<Udf>>, - pub preview: Option<bool>, pub parallelism: u64, pub checkpoint_interval_micros: Option<u64>, } +#[derive(Serialize, Deserialize, Clone, Debug, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct PreviewPost { + pub query: String, + pub udfs: Option<Vec<Udf>>, + #[serde(default)] + pub enable_sinks: bool, +} + #[derive(Serialize, Deserialize, Clone, Debug, ToSchema)] #[serde(rename_all = "camelCase")] pub struct PipelinePatch { @@ -133,16 +141,20 @@ pub struct JobLogMessage { #[serde(rename_all = "camelCase")] pub struct OutputData { pub operator_id: String, - pub timestamp: u64, - pub value: String, + pub subtask_idx: u32, + pub timestamps: Vec<u64>, + pub start_id: u64, + pub batch: String, } impl From<grpc_proto::OutputData> for OutputData { fn from(value: grpc_proto::OutputData) -> Self { OutputData { operator_id: value.operator_id, - timestamp: value.timestamp, - value: value.value, + subtask_idx: value.subtask_idx, + timestamps: value.timestamps, + start_id: value.start_id, + batch: value.batch, } } } diff --git a/crates/arroyo-rpc/src/config.rs b/crates/arroyo-rpc/src/config.rs index a2401ba76..987829cb4 100644 --- a/crates/arroyo-rpc/src/config.rs +++ b/crates/arroyo-rpc/src/config.rs @@ -245,10 +245,6 @@ pub struct Config { /// line or from stdin pub query: Option<String>, - /// Controls whether preview pipelines should have sinks enabled - #[serde(default)] - pub sinks_in_preview: bool, - /// Telemetry config #[serde(default)] pub disable_telemetry: bool, diff --git a/crates/arroyo-rpc/src/schema_resolver.rs b/crates/arroyo-rpc/src/schema_resolver.rs index e7a582679..d59fe64d4 100644 --- a/crates/arroyo-rpc/src/schema_resolver.rs +++ b/crates/arroyo-rpc/src/schema_resolver.rs @@ -127,6 +127,10 @@ impl ConfluentSchemaRegistryClient { api_key: Option<VarStr>, api_secret: Option<VarStr>, ) -> anyhow::Result<Self> { + if !(endpoint.starts_with("http://") || endpoint.starts_with("https://")) { + bail!("schema registry endpoint must start with a protocol (like `https://`)") + } + let mut client = Client::builder().timeout(Duration::from_secs(5)); if let Some(api_key) = api_key { @@ -326,11 +330,17 @@ impl ConfluentSchemaRegistry { }) } - fn subject_endpoint(&self) -> Url { + fn subject_endpoint(&self) -> anyhow::Result<Url> { self.client .endpoint .join(&format!("subjects/{}/versions/", self.subject)) - .unwrap() + .map_err(|e| { + anyhow!( + "'{}' is not a valid schema registry endpoint: {}", + self.client.endpoint, + e + ) + }) } pub async fn write_schema( @@ -339,7 +349,7 @@ impl ConfluentSchemaRegistry { schema_type: ConfluentSchemaType, ) -> anyhow::Result<i32> { self.client - .write_schema(self.subject_endpoint(), schema, schema_type) + .write_schema(self.subject_endpoint()?, schema, schema_type) .await .context(format!("subject '{}'", self.subject)) } @@ -368,7 +378,7 @@ impl ConfluentSchemaRegistry { .map(|v| format!("{}", v)) .unwrap_or_else(|| "latest".to_string()); - let url = self.subject_endpoint().join(&version).unwrap(); + let url = self.subject_endpoint()?.join(&version).unwrap(); self.client.get_schema_for_url(url).await.context(format!( "failed to fetch schema for subject '{}' with version {}", diff --git a/webui/index.html b/webui/index.html index b5d4459b5..5af6cdf4e 100644 --- a/webui/index.html +++ b/webui/index.html @@ -26,6 +26,12 @@ ); } </script> + <style > + * { + scrollbar-width: thin; + scrollbar-color: #31333e #0000002e; + } + </style> </head> <body> <div id="root"></div> diff --git a/webui/package.json b/webui/package.json index 093e6e69c..92d4147ff 100644 --- a/webui/package.json +++ b/webui/package.json @@ -21,6 +21,7 @@ "@chakra-ui/styled-system": "^2.9.1", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", + "@fontsource/ibm-plex-mono": "^5.0.13", "@fontsource/inter": "^4.5.15", "@monaco-editor/react": "^4.5.1", "@rjsf/chakra-ui": "^5.8.1", @@ -32,6 +33,8 @@ "@types/json-schema": "^7.0.12", "@types/lodash": "^4.14.200", "@types/react-syntax-highlighter": "^15.5.7", + "ag-grid-community": "^31.3.2", + "ag-grid-react": "^31.3.2", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "d3": "^7.8.5", diff --git a/webui/pnpm-lock.yaml b/webui/pnpm-lock.yaml index 8cc845f6b..b9ee903f8 100644 --- a/webui/pnpm-lock.yaml +++ b/webui/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: '@emotion/styled': specifier: ^11.11.0 version: 11.11.0(@emotion/react@11.11.1(@types/react@18.2.12)(react@18.2.0))(@types/react@18.2.12)(react@18.2.0) + '@fontsource/ibm-plex-mono': + specifier: ^5.0.13 + version: 5.0.13 '@fontsource/inter': specifier: ^4.5.15 version: 4.5.15 @@ -68,6 +71,12 @@ importers: '@types/react-syntax-highlighter': specifier: ^15.5.7 version: 15.5.7 + ag-grid-community: + specifier: ^31.3.2 + version: 31.3.2 + ag-grid-react: + specifier: ^31.3.2 + version: 31.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) ajv: specifier: ^8.12.0 version: 8.12.0 @@ -1257,6 +1266,9 @@ packages: '@floating-ui/utils@0.1.6': resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + '@fontsource/ibm-plex-mono@5.0.13': + resolution: {integrity: sha512-gtlMmvk//2AgDEZDFsoL5z9mgW3ZZg/9SC7pIfDwNKp5DtZpApgqd1Fua3HhPwYRIHrT76IQ1tMTzQKLEGtJGQ==} + '@fontsource/inter@4.5.15': resolution: {integrity: sha512-FzleM9AxZQK2nqsTDtBiY0PMEVWvnKnuu2i09+p6DHvrHsuucoV2j0tmw+kAT3L4hvsLdAIDv6MdGehsPIdT+Q==} @@ -1648,6 +1660,15 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ag-grid-community@31.3.2: + resolution: {integrity: sha512-GxqFRD0OcjaVRE1gwLgoP0oERNPH8Lk8wKJ1txulsxysEQ5dZWHhiIoXXSiHjvOCVMkK/F5qzY6HNrn6VeDMTQ==} + + ag-grid-react@31.3.2: + resolution: {integrity: sha512-SFHN05bsXp901rIT00Fa6iQLCtyavoJiKaXEDUtAU5LMu+GTkjs/FPQBQ8754omgdDFr4NsS3Ri6QbqBne3rug==} + peerDependencies: + react: ^16.3.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.3.0 || ^17.0.0 || ^18.0.0 + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -4714,6 +4735,8 @@ snapshots: '@floating-ui/utils@0.1.6': {} + '@fontsource/ibm-plex-mono@5.0.13': {} + '@fontsource/inter@4.5.15': {} '@humanwhocodes/config-array@0.11.10': @@ -5195,6 +5218,15 @@ snapshots: acorn@8.8.2: {} + ag-grid-community@31.3.2: {} + + ag-grid-react@31.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + dependencies: + ag-grid-community: 31.3.2 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + ajv-formats@2.1.1(ajv@8.12.0): optionalDependencies: ajv: 8.12.0 diff --git a/webui/src/App.tsx b/webui/src/App.tsx index 37f6329d5..517b547ee 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -9,6 +9,7 @@ import { GridItem, HStack, Icon, + IconButton, Stack, Text, } from '@chakra-ui/react'; @@ -19,9 +20,12 @@ import { CloudSidebar, UserProfile } from './lib/CloudComponents'; import { usePing } from './lib/data_fetching'; import ApiUnavailable from './routes/not_found/ApiUnavailable'; import Loading from './components/Loading'; -import React from 'react'; +import React, { ReactNode, createContext, useContext, useState } from 'react'; import { getTourContextValue, TourContext } from './tour'; import { getLocalUdfsContextValue, LocalUdfsContext } from './udf_state'; +import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons'; +import { motion } from 'framer-motion'; +import useLocalStorage from 'use-local-storage'; function logout() { // TODO: also send a request to the server to delete the session @@ -32,15 +36,17 @@ function logout() { interface NavButtonProps extends ButtonProps { icon: As; label: string; - to: string; + to?: string; + collapsed: boolean; + isActive?: boolean; } export const NavButton = (props: NavButtonProps) => { - const { icon, label, ...buttonProps } = props; + const { icon, label, collapsed, ...buttonProps } = props; - let isActive = useMatch(props.to + '/*'); + let isActive = props.isActive || useMatch(props.to + '/*'); - let onClick = useLinkClickHandler(props.to); + let onClick = props.to ? useLinkClickHandler(props.to) : props.onClick; return ( <Button @@ -49,58 +55,136 @@ export const NavButton = (props: NavButtonProps) => { /* @ts-ignore */ onClick={onClick} aria-current={isActive ? 'page' : 'false'} + title={label} {...buttonProps} > <HStack spacing="3"> <Icon as={icon} boxSize="4" color="subtle" /> - <Text fontSize="sm">{label}</Text> + {!collapsed && <Text fontSize="sm">{label}</Text>} </HStack> </Button> ); }; -function Sidebar() { +const Sidebar = ({ + collapsed, + setCollapsed, +}: { + collapsed: boolean; + setCollapsed: (c: boolean) => void; +}) => { + const { menuItems } = useNavbar(); + return ( - <GridItem className="sidebar" area={'nav'}> + <GridItem className="sidebar" area={'nav'} as={motion.div} layout> <Flex as="section" minH="100vh" bg="bg-canvas"> <Flex flex="1" bg="bg-surface" boxShadow="sm-dark" - maxW={{ base: 'full', sm: 'xs' }} - py={{ base: '6', sm: '8' }} - px={{ base: '4', sm: '6' }} + maxW={'xs'} + py={4} + px={4} + justify={'center'} > <Stack justify="space-between" spacing="1" width="full"> <Stack spacing="4" shouldWrapChildren> - <Link to={'/'}> - <img width="160px" src="/logo.svg" /> - </Link> + <Flex justify={'center'}> + <Link to={'/'}> + <motion.img + layout + style={{ height: 35 }} + src={collapsed ? '/icon.svg' : '/logo.svg'} + /> + </Link> + </Flex> <Stack spacing="1"> - <NavButton label="Home" to="/" icon={FiHome} /> - <NavButton label="Connections" to="connections" icon={FiLink} /> - <NavButton label="Pipelines" to="pipelines" icon={FiGitBranch} /> + <NavButton label="Home" to="/" icon={FiHome} collapsed={collapsed} /> + <NavButton + label="Connections" + to="connections" + icon={FiLink} + collapsed={collapsed} + /> + <NavButton + label="Pipelines" + to="pipelines" + icon={FiGitBranch} + collapsed={collapsed} + /> </Stack> <Divider /> <Stack> <CloudSidebar /> </Stack> + <Stack> + {menuItems.map(item => ( + <NavButton + key={item.label} + label={item.label} + onClick={item.onClick} + icon={item.icon} + isActive={item.selected} + collapsed={collapsed} + /> + ))} + </Stack> </Stack> - <Stack> + <Stack display={'none'}> <Divider /> <UserProfile /> </Stack> + <Flex justify={'right'}> + <IconButton + aria-label="collapse sidebar" + onClick={() => setCollapsed(!collapsed)} + icon={ + collapsed ? <ChevronRightIcon boxSize={6} /> : <ChevronLeftIcon boxSize={6} /> + } + /> + </Flex> </Stack> </Flex> </Flex> </GridItem> ); +}; + +export type SubnavType = { + icon: As; + label: string; + onClick: () => void; + selected: boolean; +}; + +interface NavbarContextType { + menuItems: SubnavType[]; + setMenuItems: (items: SubnavType[]) => void; } +const NavbarContext = createContext<NavbarContextType | undefined>(undefined); + +export const NavbarProvider: React.FC<{ children: ReactNode }> = ({ children }) => { + const [menuItems, setMenuItems] = useState<SubnavType[]>([]); + + return ( + <NavbarContext.Provider value={{ menuItems, setMenuItems }}>{children}</NavbarContext.Provider> + ); +}; + +export const useNavbar = () => { + const context = useContext(NavbarContext); + if (context === undefined) { + throw new Error('useNavbar must be used within a NavbarProvider'); + } + return context; +}; + function App() { const { ping, pingLoading, pingError } = usePing(); const tourContextValue = getTourContextValue(); const localUdfsContextValue = getLocalUdfsContextValue(); + const [collapsed, setCollapsed] = useLocalStorage('sidebar-collapse', false); let content = ( <GridItem className="main" area={'main'} overflow={'auto'}> @@ -119,10 +203,16 @@ function App() { return ( <TourContext.Provider value={tourContextValue}> <LocalUdfsContext.Provider value={localUdfsContextValue}> - <Grid templateAreas={'"nav main"'} gridTemplateColumns={'200px minmax(0, 1fr)'} h="100vh"> - <Sidebar /> - {content} - </Grid> + <NavbarProvider> + <Grid + templateAreas={'"nav main"'} + gridTemplateColumns={`${collapsed ? '80px' : '175px'}`} + h="100vh" + > + <Sidebar collapsed={collapsed} setCollapsed={setCollapsed} /> + {content} + </Grid> + </NavbarProvider> </LocalUdfsContext.Provider> </TourContext.Provider> ); diff --git a/webui/src/components/Indicator.tsx b/webui/src/components/Indicator.tsx deleted file mode 100644 index 786a80fab..000000000 --- a/webui/src/components/Indicator.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { Flex, Text } from '@chakra-ui/react'; - -export interface IndicatorProps { - content: string; - label?: string; -} - -const Indicator: React.FC<IndicatorProps> = ({ content, label }) => { - return ( - <Flex direction={'column'} justifyContent={'center'} flex={'0 0 100px'}> - <Text - as="b" - fontSize="lg" - textOverflow={'ellipsis'} - whiteSpace={'normal'} - wordBreak={'break-all'} - noOfLines={1} - > - {content} - </Text> - {label && <Text fontSize="xs">{label}</Text>} - </Flex> - ); -}; - -export default Indicator; diff --git a/webui/src/components/JobCard.tsx b/webui/src/components/JobCard.tsx deleted file mode 100644 index 118433f6b..000000000 --- a/webui/src/components/JobCard.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { Job } from '../lib/data_fetching'; -import { Card, CardBody, Flex } from '@chakra-ui/react'; -import Indicator from './Indicator'; - -export interface JobCardProps { - job: Job; -} - -const jobDuration = (job: Job) => { - if (job.startTime == null) { - return 0; - } else if (job.finishTime == null) { - return Date.now() * 1000 - Number(job.startTime); - } else { - return job.finishTime - job.startTime; - } -}; - -function formatDuration(micros: number): string { - let millis = micros / 1000; - let secs = Math.floor(millis / 1000); - if (secs < 60) { - return `${secs}s`; - } else if (millis / 1000 < 60 * 60) { - let minutes = Math.floor(secs / 60); - let seconds = secs - minutes * 60; - return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; - } else { - let hours = Math.floor(secs / (60 * 60)); - let minutes = Math.floor((secs - hours * 60 * 60) / 60); - let seconds = secs - hours * 60 * 60 - minutes * 60; - return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; - } -} - -const JobCard: React.FC<JobCardProps> = ({ job }) => { - return ( - <Card width={'400px'}> - <CardBody> - <Flex justifyContent={'space-between'}> - <Indicator content={job.state} /> - <Indicator content={formatDuration(jobDuration(job))} label={'Runtime'} /> - <Indicator content={job.tasks ? job.tasks.toString() : 'n/a'} label={'Tasks'} /> - </Flex> - </CardBody> - </Card> - ); -}; - -export default JobCard; diff --git a/webui/src/components/PaginatedContent.tsx b/webui/src/components/PaginatedContent.tsx index a7fc90973..35b7349bf 100644 --- a/webui/src/components/PaginatedContent.tsx +++ b/webui/src/components/PaginatedContent.tsx @@ -29,11 +29,12 @@ const PaginatedContent: React.FC<PaginatedContentProps> = ({ const currentPage = pages?.length ? pages[pageNum - 1] : undefined; useEffect(() => { + const currentPage = pages?.length ? pages[pageNum - 1] : undefined; setMaxPages(Math.max(pageNum, totalPages)); if (currentPage) { setCurrentData(currentPage.data); } - }, [currentPage]); + }, [pages, currentPage]); if (!pages || !pages.length || pages.length != totalPages || loading || !currentPage) { return <Loading />; diff --git a/webui/src/components/PipelineRow.tsx b/webui/src/components/PipelineRow.tsx index b1188e49b..e0c5983c9 100644 --- a/webui/src/components/PipelineRow.tsx +++ b/webui/src/components/PipelineRow.tsx @@ -1,12 +1,78 @@ import React from 'react'; -import { Pipeline, usePipelineJobs } from '../lib/data_fetching'; -import { IconButton, Link, Td, Tr } from '@chakra-ui/react'; -import JobCard from './JobCard'; +import { Job, Pipeline, usePipelineJobs } from '../lib/data_fetching'; +import { Flex, IconButton, Link, Td, Tr, Text } from '@chakra-ui/react'; import { formatDate, relativeTime } from '../lib/util'; -import Indicator from './Indicator'; import { FiCopy, FiXCircle } from 'react-icons/fi'; import { useNavigate } from 'react-router-dom'; +export interface IndicatorProps { + content: string | undefined; + label?: string; + color?: string; +} + +const Indicator: React.FC<IndicatorProps> = ({ content, label, color }) => { + return ( + <Flex direction={'column'} justifyContent={'center'} flex={'0 0 100px'}> + <Text + as="b" + fontSize="lg" + textOverflow={'ellipsis'} + whiteSpace={'normal'} + wordBreak={'break-all'} + noOfLines={1} + color={color} + > + {content} + </Text> + {label && <Text fontSize="xs">{label}</Text>} + </Flex> + ); +}; + +export interface JobCardProps { + job: Job; +} + +const jobDuration = (job: Job) => { + if (job.startTime == null) { + return 0; + } else if (job.finishTime == null) { + return Date.now() * 1000 - Number(job.startTime); + } else { + return job.finishTime - job.startTime; + } +}; + +function stateColor(state: string): string { + switch (state) { + case 'Running': + return 'green.300'; + case 'Failed': + return 'red.300'; + case 'Stopping': + return 'orange.300'; + } + return 'gray.400'; +} + +function formatDuration(micros: number): string { + let millis = micros / 1000; + let secs = Math.floor(millis / 1000); + if (secs < 60) { + return `${secs}s`; + } else if (millis / 1000 < 60 * 60) { + let minutes = Math.floor(secs / 60); + let seconds = secs - minutes * 60; + return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; + } else { + let hours = Math.floor(secs / (60 * 60)); + let minutes = Math.floor((secs - hours * 60 * 60) / 60); + let seconds = secs - hours * 60 * 60 - minutes * 60; + return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; + } +} + export interface PipelineRowProps { pipeline: Pipeline; setPipelineIdToBeDeleted: (pipelineId: string) => void; @@ -25,10 +91,15 @@ const PipelineRow: React.FC<PipelineRowProps> = ({ return <></>; } + let job = jobs[0]; + return ( <Tr key={pipeline.id}> <Td key={'name'} minWidth={230} maxWidth={'400px'}> - <Link href={`/pipelines/${pipeline.id}`}> + <Link + href={`/pipelines/${pipeline.id}`} + onClick={() => navigate(`/pipelines/${pipeline.id}`)} + > <Indicator content={pipeline.name} label={pipeline.id} /> </Link> </Td> @@ -38,10 +109,14 @@ const PipelineRow: React.FC<PipelineRowProps> = ({ label={relativeTime(pipeline.createdAt)} /> </Td> - <Td key={'job'}> - {jobs.map(job => ( - <JobCard key={job.id} job={job} /> - ))} + <Td key={'state'}> + <Indicator content={job?.state} color={stateColor(job?.state)} /> + </Td> + <Td> + <Indicator content={job ? formatDuration(jobDuration(job)) : undefined} /> + </Td> + <Td> + <Indicator content={job?.tasks ? job.tasks.toString() : 'n/a'} /> </Td> <Td key={'actions'} textAlign="right"> <IconButton diff --git a/webui/src/components/PipelinesTable.tsx b/webui/src/components/PipelinesTable.tsx index a7a1ee376..a06916230 100644 --- a/webui/src/components/PipelinesTable.tsx +++ b/webui/src/components/PipelinesTable.tsx @@ -109,7 +109,9 @@ const PipelinesTable: React.FC<JobsTableProps> = ({}) => { <Tr> <Th>Name / ID</Th> <Th>Created at</Th> - <Th>Job</Th> + <Th>State</Th> + <Th>Runtime</Th> + <Th>Tasks</Th> <Th></Th> </Tr> </Thead> diff --git a/webui/src/gen/api-types.ts b/webui/src/gen/api-types.ts index 69bce35fa..f420a66e5 100644 --- a/webui/src/gen/api-types.ts +++ b/webui/src/gen/api-types.ts @@ -67,6 +67,10 @@ export interface paths { */ post: operations["create_pipeline"]; }; + "/v1/pipelines/preview": { + /** Create a new preview pipeline */ + post: operations["create_preview_pipeline"]; + }; "/v1/pipelines/validate_query": { /** Validate a query and return pipeline graph */ post: operations["validate_query"]; @@ -328,11 +332,11 @@ export interface components { value: number; }; MetricGroup: { - name: components["schemas"]["MetricNames"]; + name: components["schemas"]["MetricName"]; subtasks: (components["schemas"]["SubtaskMetrics"])[]; }; /** @enum {string} */ - MetricNames: "bytes_recv" | "bytes_sent" | "messages_recv" | "messages_sent" | "backpressure"; + MetricName: "bytes_recv" | "bytes_sent" | "messages_recv" | "messages_sent" | "backpressure" | "tx_queue_size" | "tx_queue_rem"; NewlineDelimitedFraming: { /** Format: int64 */ maxLineLength?: number | null; @@ -354,10 +358,13 @@ export interface components { data: (components["schemas"]["OperatorMetricGroup"])[]; }; OutputData: { + batch: string; operatorId: string; /** Format: int64 */ - timestamp: number; - value: string; + startId: number; + /** Format: int32 */ + subtaskIdx: number; + timestamps: (number)[]; }; PaginationQueryParams: { /** Format: int32 */ @@ -416,13 +423,17 @@ export interface components { name: string; /** Format: int64 */ parallelism: number; - preview?: boolean | null; query: string; udfs?: (components["schemas"]["Udf"])[] | null; }; PipelineRestart: { force?: boolean | null; }; + PreviewPost: { + enableSinks?: boolean; + query: string; + udfs?: (components["schemas"]["Udf"])[] | null; + }; /** @enum {string} */ PrimitiveType: "Int32" | "Int64" | "UInt32" | "UInt64" | "F32" | "F64" | "Bool" | "String" | "Bytes" | "UnixMillis" | "UnixMicros" | "UnixNanos" | "DateTime" | "Json"; QueryValidationResult: { @@ -719,6 +730,28 @@ export interface operations { }; }; }; + /** Create a new preview pipeline */ + create_preview_pipeline: { + requestBody: { + content: { + "application/json": components["schemas"]["PreviewPost"]; + }; + }; + responses: { + /** @description Created pipeline and job */ + 200: { + content: { + "application/json": components["schemas"]["Pipeline"]; + }; + }; + /** @description Bad request */ + 400: { + content: { + "application/json": components["schemas"]["ErrorResp"]; + }; + }; + }; + }; /** Validate a query and return pipeline graph */ validate_query: { requestBody: { diff --git a/webui/src/lib/data_fetching.ts b/webui/src/lib/data_fetching.ts index ed8c119b0..64a4f68d8 100644 --- a/webui/src/lib/data_fetching.ts +++ b/webui/src/lib/data_fetching.ts @@ -217,12 +217,11 @@ const connectionTablesFetcher = () => { }; }; -export const useConnectionTables = (limit: number) => { +export const useConnectionTables = (limit: number, refresh?: boolean) => { + const options = refresh ? { refreshInterval: 5000 } : {}; const { data, isLoading, mutate, size, setSize } = useSWRInfinite< schemas['ConnectionTableCollection'] - >(connectionTablesKey(limit), connectionTablesFetcher(), { - refreshInterval: 5000, - }); + >(connectionTablesKey(limit), connectionTablesFetcher(), options); return { connectionTablePages: data, @@ -443,6 +442,7 @@ const pipelinesFetcher = () => { const { data, error } = await get('/v1/pipelines', { params: { query: { + limit: 100, starting_after: params.startingAfter, }, }, @@ -457,7 +457,7 @@ export const usePipelines = () => { pipelinesKey, pipelinesFetcher(), { - refreshInterval: 2000, + refreshInterval: 5000, } ); @@ -550,8 +550,12 @@ const pipelineJobsFetcher = () => { }; }; -export const usePipelineJobs = (pipelineId?: string, refresh: boolean = false) => { - const options = refresh ? { refreshInterval: 2000 } : {}; +export const usePipelineJobs = ( + pipelineId?: string, + refresh: boolean = false, + refreshInterval?: number +) => { + const options = refresh ? { refreshInterval: refreshInterval || 2000 } : {}; const { data, error } = useSWR<schemas['JobCollection']>( pipelineJobsKey(pipelineId), pipelineJobsFetcher(), @@ -601,23 +605,6 @@ export const useOperatorErrors = (pipelineId?: string, jobId?: string) => { }; }; -export const useJobOutput = ( - handler: (event: MessageEvent) => void, - pipelineId?: string, - jobId?: string -) => { - if (!pipelineId || !jobId) { - return; - } - const url = `${BASE_URL}/v1/pipelines/${pipelineId}/jobs/${jobId}/output`; - const eventSource = new EventSource(url); - eventSource.onerror = () => { - eventSource.close(); - }; - eventSource.addEventListener('message', handler); - return eventSource; -}; - export const useConnectionTableTest = async ( handler: (event: TestSourceMessage) => void, req: ConnectionTablePost diff --git a/webui/src/main.tsx b/webui/src/main.tsx index ba7a86d77..9811eb3c8 100644 --- a/webui/src/main.tsx +++ b/webui/src/main.tsx @@ -13,7 +13,10 @@ const config: ThemeConfig = { }; const theme = extendTheme(proTheme, { - colors: { ...proTheme.colors, brand: proTheme.colors.blue }, + colors: { + ...proTheme.colors, + brand: proTheme.colors.blue, + }, config: config, components: { Modal: modalTheme, Popover: popoverTheme, Tabs: tabsTheme }, }); diff --git a/webui/src/routes/connections/ChooseConnector.tsx b/webui/src/routes/connections/ChooseConnector.tsx index 5b6e5f492..dfa02407f 100644 --- a/webui/src/routes/connections/ChooseConnector.tsx +++ b/webui/src/routes/connections/ChooseConnector.tsx @@ -18,11 +18,19 @@ import { } from '@chakra-ui/react'; import { useNavigate } from 'react-router-dom'; import { useConnectors } from '../../lib/data_fetching'; +import { useNavbar } from '../../App'; +import { useEffect } from 'react'; export function ChooseConnector() { const navigate = useNavigate(); const { connectors } = useConnectors(); + const { setMenuItems } = useNavbar(); + + useEffect(() => { + setMenuItems([]); + }, []); + const connectorCards = connectors?.map(c => { return ( <Card key={c.name} size={'md'} maxW={400}> diff --git a/webui/src/routes/connections/Connections.tsx b/webui/src/routes/connections/Connections.tsx index 3c85780d5..050b8a6bc 100644 --- a/webui/src/routes/connections/Connections.tsx +++ b/webui/src/routes/connections/Connections.tsx @@ -27,13 +27,14 @@ import { ModalBody, ModalFooter, } from '@chakra-ui/react'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FiInfo, FiXCircle } from 'react-icons/fi'; import { ConnectionTable, del, Format, useConnectionTables } from '../../lib/data_fetching'; import { useNavigate } from 'react-router-dom'; import { formatError } from '../../lib/util'; import { formatDate } from '../../lib/util'; import PaginatedContent from '../../components/PaginatedContent'; +import { useNavbar } from '../../App'; interface ColumnDef { name: string; @@ -92,9 +93,15 @@ export function Connections() { mutateConnectionTables, connectionTablesTotalPages, setConnectionTablesMaxPages, - } = useConnectionTables(10); + } = useConnectionTables(100); const [connectionTables, setConnectionTables] = useState<ConnectionTable[]>([]); + const { setMenuItems } = useNavbar(); + + useEffect(() => { + setMenuItems([]); + }, []); + const deleteTable = async (connection: ConnectionTable) => { const { error } = await del('/v1/connection_tables/{id}', { params: { path: { id: connection.id } }, diff --git a/webui/src/routes/connections/CreateConnection.tsx b/webui/src/routes/connections/CreateConnection.tsx index 8b93a84a4..cf466ff32 100644 --- a/webui/src/routes/connections/CreateConnection.tsx +++ b/webui/src/routes/connections/CreateConnection.tsx @@ -24,6 +24,7 @@ import { ConfigureConnection } from './ConfigureConnection'; import { DefineSchema } from './DefineSchema'; import { ConnectionTester } from './ConnectionTester'; import { ConfigureProfile } from './ConfigureProfile'; +import { useNavbar } from '../../App'; export type CreateConnectionState = { name: string | undefined; @@ -139,6 +140,12 @@ export const CreateConnection = () => { let { connectorId } = useParams(); let { connectors, connectorsLoading } = useConnectors(); + const { setMenuItems } = useNavbar(); + + useEffect(() => { + setMenuItems([]); + }, []); + let navigate = useNavigate(); let connector = connectors?.find(c => c.id === connectorId); diff --git a/webui/src/routes/home/Home.tsx b/webui/src/routes/home/Home.tsx index b68df136c..0a188aa2c 100644 --- a/webui/src/routes/home/Home.tsx +++ b/webui/src/routes/home/Home.tsx @@ -23,6 +23,7 @@ import Loading from '../../components/Loading'; import React, { useContext, useEffect } from 'react'; import WelcomeModal from '../../components/WelcomeModal'; import { TourContext, TourSteps } from '../../tour'; +import { useNavbar } from '../../App'; interface Props { label: string; @@ -57,6 +58,12 @@ export function Home() { const { jobs, jobsLoading } = useJobs(); const navigate = useNavigate(); + const { setMenuItems } = useNavbar(); + + useEffect(() => { + setMenuItems([]); + }, []); + const { tourActive, tourStep, setTourStep, disableTour } = useContext(TourContext); useEffect(() => { diff --git a/webui/src/routes/pipelines/Catalog.tsx b/webui/src/routes/pipelines/Catalog.tsx index dd1f7a528..5637c868c 100644 --- a/webui/src/routes/pipelines/Catalog.tsx +++ b/webui/src/routes/pipelines/Catalog.tsx @@ -6,9 +6,12 @@ import { AccordionPanel, Box, Flex, + HStack, + Icon, Text, } from '@chakra-ui/react'; import { ConnectionTable, SourceField } from '../../lib/data_fetching'; +import { BiTable } from 'react-icons/bi'; function CatalogField({ field, nesting }: { field: SourceField; nesting: number }) { if (field.fieldType!.type.primitive) { @@ -17,7 +20,7 @@ function CatalogField({ field, nesting }: { field: SourceField; nesting: number <Box flex="1" textAlign="left"> {field.fieldName} </Box> - <Box flex="1" textAlign="right"> + <Box flex="1" textAlign="right" color={'pink.300'}> {field.fieldType.sqlName} </Box> </Flex> @@ -49,11 +52,20 @@ export function Catalog({ tables }: { tables: Array<ConnectionTable> }) { <AccordionItem key={table.name} fontSize="xs" pb={4} borderWidth={0}> <Box> <AccordionButton padding={0}> - <Box fontWeight="bold" as="span" flex="1" textAlign="left"> - <Text fontSize="xs" pb={2}> + <HStack + fontWeight="bold" + as="span" + flex="1" + textAlign="left" + fontFamily={'monospace'} + alignItems={'middle'} + color={'gray.300'} + > + <Icon as={BiTable} boxSize={'4'} color={'blue.400'} /> + <Text fontSize="12px" pb={2}> {table.name} </Text> - </Box> + </HStack> <AccordionIcon /> </AccordionButton> </Box> diff --git a/webui/src/routes/pipelines/CatalogTab.tsx b/webui/src/routes/pipelines/CatalogTab.tsx index 9fa4c0529..c30fbc566 100644 --- a/webui/src/routes/pipelines/CatalogTab.tsx +++ b/webui/src/routes/pipelines/CatalogTab.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import { Alert, AlertDescription, AlertIcon, Box, Spacer, Stack, Text } from '@chakra-ui/react'; +import { Alert, AlertDescription, AlertIcon, Box, Stack, Text } from '@chakra-ui/react'; import { Link } from 'react-router-dom'; import { ConnectionTable, useConnectionTables } from '../../lib/data_fetching'; import { Catalog } from './Catalog'; const CatalogTab: React.FC = () => { - const { connectionTablePages, connectionTablesLoading } = useConnectionTables(50); + const { connectionTablePages, connectionTablesLoading } = useConnectionTables(200, false); let connectionTables: ConnectionTable[] = []; let catalogTruncated = false; - if (connectionTablePages?.length) { + if (connectionTablePages?.length && connectionTablePages[0]) { connectionTables = connectionTablePages[0].data; catalogTruncated = connectionTablePages[0].hasMore; } @@ -24,10 +24,7 @@ const CatalogTab: React.FC = () => { catalogTruncatedWarning = ( <Alert flexShrink={0} status="warning"> <AlertIcon /> - <AlertDescription> - The catalogue is too large to be shown in its entirety. Please see the Connections tab for - the complete listing. - </AlertDescription> + <AlertDescription>The catalogue is too large to be shown in its entirety.</AlertDescription> </Alert> ); } @@ -35,7 +32,7 @@ const CatalogTab: React.FC = () => { const catalogType = (name: string, tables: Array<ConnectionTable>) => { return ( <Stack> - <Text fontSize={'md'} pt={2} pb={4} fontWeight={'bold'}> + <Text fontSize={'sm'} pt={2} pb={4} fontWeight={'bold'}> {name.toUpperCase()}S </Text> <Stack spacing={4}> @@ -56,19 +53,10 @@ const CatalogTab: React.FC = () => { }; return ( - <Stack> + <Stack w="100%"> {catalogTruncatedWarning} {catalogType('Source', sources)} {catalogType('Sink', sinks)} - - <Spacer /> - <Box p={4} borderTop={'1px solid'} borderColor={'gray.500'}> - Write SQL to create a streaming pipeline. See the{' '} - <Link to={'http://doc.arroyo.dev/sql'} target="_blank"> - SQL docs - </Link>{' '} - for details on Arroyo SQL. - </Box> </Stack> ); }; diff --git a/webui/src/routes/pipelines/CreatePipeline.tsx b/webui/src/routes/pipelines/CreatePipeline.tsx index e36b061a7..f63897926 100644 --- a/webui/src/routes/pipelines/CreatePipeline.tsx +++ b/webui/src/routes/pipelines/CreatePipeline.tsx @@ -4,18 +4,12 @@ import { AlertIcon, Badge, Box, - Button, + Code, Flex, HStack, Icon, - Popover, - PopoverArrow, - PopoverBody, - PopoverCloseButton, - PopoverContent, - PopoverHeader, - PopoverTrigger, Spinner, + Stack, Tab, TabList, TabPanel, @@ -24,18 +18,14 @@ import { Text, useDisclosure, } from '@chakra-ui/react'; -import React, { useContext, useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { PipelineGraphViewer } from './PipelineGraph'; import { SqlOptions } from '../../lib/types'; import { JobLogMessage, - OutputData, PipelineLocalUdf, post, - useConnectionTables, - useJobMetrics, - useJobOutput, useOperatorErrors, usePipeline, usePipelineJobs, @@ -45,10 +35,13 @@ import Loading from '../../components/Loading'; import OperatorErrors from '../../components/OperatorErrors'; import StartPipelineModal from '../../components/StartPipelineModal'; import { formatError } from '../../lib/util'; -import { WarningIcon } from '@chakra-ui/icons'; import PaginatedContent from '../../components/PaginatedContent'; -import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; -import { MdDragHandle } from 'react-icons/md'; +import { + ImperativePanelHandle, + Panel, + PanelGroup, + PanelResizeHandle, +} from 'react-resizable-panels'; import { PipelineOutputs } from './PipelineOutputs'; import { TourContext, TourSteps } from '../../tour'; import CreatePipelineTourModal from '../../components/CreatePipelineTourModal'; @@ -56,10 +49,15 @@ import TourCompleteModal from '../../components/TourCompleteModal'; import SyntaxHighlighter from 'react-syntax-highlighter'; import { vs2015 } from 'react-syntax-highlighter/dist/esm/styles/hljs'; import PipelineEditorTabs from './PipelineEditorTabs'; -import ResourcePanel from './ResourcePanel'; import { LocalUdf, LocalUdfsContext } from '../../udf_state'; import UdfLabel from '../udfs/UdfLabel'; -import { PiFileSqlDuotone } from 'react-icons/pi'; +import { PiFileSqlDuotone, PiFunction, PiGraph } from 'react-icons/pi'; +import { BiTable } from 'react-icons/bi'; +import { IoWarningOutline } from 'react-icons/io5'; +import { useNavbar } from '../../App'; +import { FiDatabase } from 'react-icons/fi'; +import CatalogTab from './CatalogTab'; +import UdfsResourceTab from '../udfs/UdfsResourceTab'; function useQuery() { const { search } = useLocation(); @@ -67,25 +65,25 @@ function useQuery() { return useMemo(() => new URLSearchParams(search), [search]); } +export interface PreviewOptions { + enableSinks: boolean; +} + export function CreatePipeline() { const [pipelineId, setPipelineId] = useState<string | undefined>(undefined); const { updatePipeline } = usePipeline(pipelineId); - const { jobs } = usePipelineJobs(pipelineId, true); + const { jobs } = usePipelineJobs(pipelineId, true, 500); const job = jobs?.length ? jobs[0] : undefined; const { operatorErrorsPages, operatorErrorsTotalPages, setOperatorErrorsMaxPages } = useOperatorErrors(pipelineId, job?.id); const [operatorErrors, setOperatorErrors] = useState<JobLogMessage[]>([]); const [queryInput, setQueryInput] = useState<string>(''); const [queryInputToCheck, setQueryInputToCheck] = useState<string | undefined>(undefined); - const { operatorMetricGroups } = useJobMetrics(pipelineId, job?.id); const { isOpen, onOpen, onClose } = useDisclosure(); const [options, setOptions] = useState<SqlOptions>({ parallelism: 4, checkpointMS: 5000 }); const navigate = useNavigate(); const [startError, setStartError] = useState<string | null>(null); const [tabIndex, setTabIndex] = useState<number>(0); - const [outputSource, setOutputSource] = useState<EventSource | undefined>(undefined); - const [outputs, setOutputs] = useState<Array<{ id: number; data: OutputData }>>([]); - const { connectionTablesLoading } = useConnectionTables(50); const queryParams = useQuery(); const { pipeline: copyFrom, pipelineLoading: copyFromLoading } = usePipeline( queryParams.get('from') ?? undefined @@ -97,8 +95,8 @@ export function CreatePipeline() { queryInputToCheck, localUdfsToCheck ); + const [previewError, setPreviewError] = useState<string | undefined>(undefined); const hasUdfValidationErrors = localUdfs.some(u => u.errors?.length); - const hasValidationErrors = queryValidation?.errors?.length || hasUdfValidationErrors; const [resourcePanelTab, setResourcePanelTab] = useState(0); const [udfValidationApiError, setUdfValidationApiError] = useState<any | undefined>(undefined); const [validationInProgress, setValidationInProgress] = useState<boolean>(false); @@ -106,6 +104,30 @@ export function CreatePipeline() { const { tourActive, tourStep, setTourStep, disableTour } = useContext(TourContext); + const [sidebarElement, setSidebarElement] = useState<'tables' | 'udfs' | null>('tables'); + const [previewOptions, setPreviewOptions] = useState<PreviewOptions>({ enableSinks: false }); + + const { setMenuItems } = useNavbar(); + + const hasValidationErrors = queryValidation?.errors?.length || hasUdfValidationErrors; + + useEffect(() => { + setMenuItems([ + { + label: 'Tables', + icon: FiDatabase, + onClick: () => setSidebarElement(sidebarElement == 'tables' ? null : 'tables'), + selected: sidebarElement == 'tables', + }, + { + label: 'UDFs', + icon: PiFunction, + onClick: () => setSidebarElement(sidebarElement == 'udfs' ? null : 'udfs'), + selected: sidebarElement == 'udfs', + }, + ]); + }, [sidebarElement]); + useEffect(() => { if (tourActive) { setTourStep(TourSteps.CreatePipelineModal); @@ -137,15 +159,15 @@ export function CreatePipeline() { // merge with local udfs let merged = localUdfs; for (const udf of udfs) { - const { data: udfValiation } = await post('/v1/udfs/validate', { + const { data: udfValidation } = await post('/v1/udfs/validate', { body: { definition: udf.definition, }, }); - if (udfValiation) { - udf.name = udfValiation.udfName ?? udf.name; - udf.errors = udfValiation.errors ?? []; + if (udfValidation) { + udf.name = udfValidation.udfName ?? udf.name; + udf.errors = udfValidation.errors ?? []; } if (!merged.some(u => u.name == udf.name)) { @@ -174,27 +196,20 @@ export function CreatePipeline() { return `udf_${id}`; }; - const sseHandler = (event: MessageEvent) => { - const parsed = JSON.parse(event.data) as OutputData; - const o = { id: Number(event.lastEventId), data: parsed }; - outputs.push(o); - if (outputs.length > 20) { - outputs.shift(); - } - setOutputs(outputs.slice()); - }; + const panelRef = useRef<ImperativePanelHandle | null>(null); useEffect(() => { - if (pipelineId && job) { - if (outputSource) { - outputSource.close(); + if (panelRef?.current != undefined) { + if (sidebarElement == null && panelRef?.current?.getSize() > 0) { + panelRef?.current?.collapse(); + } else if (sidebarElement != null && panelRef?.current?.getSize() == 0) { + panelRef?.current?.expand(); } - setOutputSource(useJobOutput(sseHandler, pipelineId, job.id)); } - }, [job?.id]); + }, [sidebarElement]); // Top-level loading state - if (copyFromLoading || connectionTablesLoading || !localUdfs) { + if (copyFromLoading || !localUdfs) { return <Loading />; } @@ -250,7 +265,6 @@ export function CreatePipeline() { setPipelineId(undefined); setQueryInputToCheck(queryInput); setLocalUdfsToCheck(localUdfs); - setOutputs([]); setUdfValidationApiError(undefined); await stopPreview(); @@ -272,6 +286,7 @@ export function CreatePipeline() { setTourStep(undefined); setQueryInputToCheck(''); setStartingPreview(true); + setPreviewError(undefined); if (!(await pipelineIsValid(1))) { setStartingPreview(false); @@ -282,20 +297,19 @@ export function CreatePipeline() { definition: u.definition, })); - const { data: newPipeline, error } = await post('/v1/pipelines', { + const { data: newPipeline, error } = await post('/v1/pipelines/preview', { body: { - name: `preview-${new Date().getTime()}`, - parallelism: 1, - preview: true, query: queryInput, udfs, + enableSinks: previewOptions.enableSinks, }, }); setStartingPreview(false); if (error) { - console.log('Create pipeline failed'); + console.error('Create pipeline failed', error); + setPreviewError(`Failed to start preview: ${formatError(error)}`); } else { // Setting the pipeline id will trigger fetching the job and subscribing to the output setPipelineId(newPipeline?.id); @@ -304,10 +318,6 @@ export function CreatePipeline() { const stopPreview = async () => { await updatePipeline({ stop: 'immediate' }); - - if (outputSource) { - outputSource.close(); - } }; const run = async () => { @@ -353,80 +363,6 @@ export function CreatePipeline() { /> ); - const previewing = job?.runningDesired && job?.state != 'Failed' && !job?.finishTime; - - let startPreviewButton = <></>; - let stopPreviewButton = <></>; - - if (previewing) { - stopPreviewButton = ( - <Button - onClick={stopPreview} - size="md" - colorScheme="blue" - title="Stop a preview pipeline" - borderRadius={2} - > - Stop Preview - </Button> - ); - } else { - startPreviewButton = ( - <Button - onClick={preview} - size="md" - colorScheme="blue" - title="Run a preview pipeline" - borderRadius={2} - isLoading={startingPreview} - > - Start Preview - </Button> - ); - } - - const checkButton = ( - <Button - size="md" - colorScheme="blue" - onClick={() => pipelineIsValid(0)} - title="Check that the SQL is valid" - borderRadius={2} - > - Check - </Button> - ); - - const startPipelineButton = ( - <Button size="md" colorScheme="green" onClick={run} borderRadius={2}> - Start Pipeline - </Button> - ); - - const buttonGroup = ( - <HStack spacing={4} p={4}> - {checkButton} - <Popover - isOpen={tourStep == TourSteps.Preview} - placement={'top'} - closeOnBlur={false} - variant={'tour'} - > - <PopoverTrigger>{startPreviewButton}</PopoverTrigger> - <PopoverContent> - <PopoverArrow /> - <PopoverCloseButton onClick={disableTour} /> - <PopoverHeader>Nice!</PopoverHeader> - <PopoverBody> - Finally, run a preview pipeline to see the results of your query. - </PopoverBody> - </PopoverContent> - </Popover> - {stopPreviewButton} - {startPipelineButton} - </HStack> - ); - let previewPipelineTab = ( <TabPanel height="100%" position="relative"> <Text>Check your SQL to see the pipeline graph.</Text> @@ -446,19 +382,16 @@ export function CreatePipeline() { }} overflow="auto" > - <PipelineGraphViewer - graph={queryValidation.graph} - operatorMetricGroups={operatorMetricGroups} - setActiveOperator={() => {}} - /> + <PipelineGraphViewer graph={queryValidation.graph} setActiveOperator={() => {}} /> </Box> </TabPanel> ); } let previewResultsTabContent = <Text>Preview your SQL to see outputs.</Text>; + const previewing = job?.runningDesired && job?.state != 'Failed' && !job?.finishTime; - if (outputs.length) { + if (pipelineId != null && jobs != null && jobs[0] != null) { setTourStep(TourSteps.TourCompleted); previewResultsTabContent = ( <Box @@ -471,7 +404,7 @@ export function CreatePipeline() { }} overflow="auto" > - <PipelineOutputs outputs={outputs} /> + <PipelineOutputs pipelineId={pipelineId} job={jobs[0]} onDemand={false} /> </Box> ); } else { @@ -492,8 +425,8 @@ export function CreatePipeline() { ); const validationErrorAlert = ( - <Alert status="error"> - <AlertIcon /> + <Alert status="error" height={8}> + <AlertIcon boxSize={4} /> <AlertDescription> <Text>Validation error</Text> </AlertDescription> @@ -544,8 +477,7 @@ export function CreatePipeline() { } errorsTab = ( - <TabPanel overflowX="auto" height="100%" position="relative"> - {validationErrorAlert} + <TabPanel overflowX="auto" p={0} pl={2} height="100%" position="relative"> {queryErrors} {udfErrors} </TabPanel> @@ -576,7 +508,7 @@ export function CreatePipeline() { } else { errorsTab = ( <TabPanel overflowX="auto" height="100%" position="relative"> - <Text>Job errors will appear here.</Text> + <Text color={'gray.500'}>No job errors</Text> </TabPanel> ); } @@ -601,8 +533,6 @@ export function CreatePipeline() { </TabPanels> ); - const editorTabs = <PipelineEditorTabs queryInput={queryInput} updateQuery={updateQuery} />; - let errorMessage; if (queryValidationError) { errorMessage = formatError(queryValidationError); @@ -610,6 +540,12 @@ export function CreatePipeline() { errorMessage = formatError(udfValidationApiError); } else if (job?.state == 'Failed') { errorMessage = job.failureMessage ?? 'Job failed.'; + } else if (previewError) { + errorMessage = ( + <Code backgroundColor={'transparent'}> + <pre>{previewError}</pre> + </Code> + ); } else { errorMessage = ''; } @@ -617,64 +553,75 @@ export function CreatePipeline() { let errorComponent = <></>; if (errorMessage) { errorComponent = ( - <div> - <Alert status="error"> - <AlertIcon /> - <AlertDescription> - <Text noOfLines={2} textOverflow={'ellipsis'} wordBreak={'break-all'}> - {errorMessage} - </Text> - </AlertDescription> - </Alert> - </div> + <Alert status="error"> + <AlertIcon /> + <AlertDescription> + <Text noOfLines={2} textOverflow={'ellipsis'} wordBreak={'break-all'}> + {errorMessage} + </Text> + </AlertDescription> + </Alert> ); } let previewCompletedComponent = <></>; if (job?.finishTime && !job?.failureMessage) { previewCompletedComponent = ( - <div> - <Alert status="success"> - <AlertIcon /> - <AlertDescription> - <Text>Preview completed</Text> - </AlertDescription> - </Alert> - </div> + <Alert status="success" h={8}> + <AlertIcon boxSize={4} /> + <AlertDescription> + <Text>Preview completed</Text> + </AlertDescription> + </Alert> ); } - let errorsTabIcon = <></>; - if (hasValidationErrors || hasOperatorErrors) { - errorsTabIcon = <Icon as={WarningIcon} color={'red.400'} ml={2} />; - } - const tabs = ( <Tabs display={'flex'} - flexDirection={'column'} + flexDirection={'row'} index={tabIndex} onChange={i => setTabIndex(i)} flex={1} overflow={'auto'} + orientation="vertical" + variant={'unstyled'} + size={'md'} + colorScheme="green" > <TabList> - <Flex width={'100%'} justifyContent={'space-between'}> - <Flex> - <Tab>Pipeline</Tab> - <Tab> - <HStack> - <Text>Results</Text> - {previewing ? <Spinner size="xs" speed="0.9s" /> : null} - </HStack> - </Tab> - <Tab> - <Text>Errors</Text> - {errorsTabIcon} - </Tab> - </Flex> - {buttonGroup} - </Flex> + <Stack w={10} mx={2} spacing={4} h={'100%'} py={4}> + <Tab + title="Pipeline graph" + borderRadius={'md'} + _selected={{ bg: 'gray.600' }} + _hover={{ bg: 'gray.500 ' }} + > + <Icon as={PiGraph} boxSize={5} /> + </Tab> + <Tab + title="Results" + borderRadius={'md'} + _selected={{ bg: 'gray.600' }} + _hover={{ bg: 'gray.500 ' }} + > + <HStack> + {previewing ? <Spinner size="xs" speed="0.9s" /> : <Icon boxSize={5} as={BiTable} />} + </HStack> + </Tab> + <Tab + title="Errors" + borderRadius={'md'} + _selected={{ bg: 'gray.600' }} + _hover={{ bg: 'gray.500 ' }} + > + <Icon + as={IoWarningOutline} + boxSize={5} + color={hasValidationErrors || hasOperatorErrors ? 'red.400' : undefined} + /> + </Tab> + </Stack> </TabList> {previewTabsContent} </Tabs> @@ -682,30 +629,57 @@ export function CreatePipeline() { const panelResizer = ( <PanelResizeHandle> - <Flex justifyContent="center"> - <MdDragHandle color={'grey'} /> - </Flex> + <Box bg={'#111'} h={'2px'} w="100%" /> </PanelResizeHandle> ); return ( <Flex height={'100vh'}> - <Flex> - <ResourcePanel tabIndex={resourcePanelTab} handleTabChange={setResourcePanelTab} /> - </Flex> - <Flex direction={'column'} flex={1} minWidth={0}> - <PanelGroup autoSaveId={'create-pipeline-panels'} direction="vertical"> - <Panel minSize={20}>{editorTabs}</Panel> - {panelResizer} - <Panel minSize={20}> - <Flex direction={'column'} height={'100%'}> - {errorComponent} - {previewCompletedComponent} - {tabs} - </Flex> - </Panel> - </PanelGroup> - </Flex> + <PanelGroup direction="horizontal"> + <Panel minSize={0} defaultSize={15} collapsible={true} ref={panelRef}> + <Flex h={'100vh'} overflowY={'auto'} p={4} bgColor={'#1A1A1A'}> + {sidebarElement == 'tables' ? ( + <CatalogTab /> + ) : sidebarElement == 'udfs' ? ( + <UdfsResourceTab /> + ) : null} + </Flex> + </Panel> + {sidebarElement != null && ( + <PanelResizeHandle> + <Box bg={'#111'} w={'2px'} h="100%" /> + </PanelResizeHandle> + )} + <Panel minSize={60}> + <Flex direction={'column'} bg={'#151515'} h={'100vh'}> + <PanelGroup autoSaveId={'create-pipeline-panels'} direction="vertical"> + <Panel minSize={20}> + <PipelineEditorTabs + queryInput={queryInput} + previewing={previewing} + startingPreview={startingPreview} + preview={preview} + stopPreview={stopPreview} + run={run} + pipelineIsValid={pipelineIsValid} + updateQuery={updateQuery} + previewOptions={previewOptions} + setPreviewOptions={setPreviewOptions} + job={job} + /> + </Panel> + {panelResizer} + <Panel minSize={20}> + <Flex direction={'column'} height={'100%'}> + {errorComponent} + {tabs} + {hasValidationErrors ? validationErrorAlert : previewCompletedComponent} + </Flex> + </Panel> + </PanelGroup> + </Flex> + </Panel> + </PanelGroup> <CreatePipelineTourModal /> <TourCompleteModal /> {startPipelineModal} diff --git a/webui/src/routes/pipelines/PipelineDetails.tsx b/webui/src/routes/pipelines/PipelineDetails.tsx index e097fed55..470293af2 100644 --- a/webui/src/routes/pipelines/PipelineDetails.tsx +++ b/webui/src/routes/pipelines/PipelineDetails.tsx @@ -25,15 +25,13 @@ import { Text, useDisclosure, } from '@chakra-ui/react'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import 'reactflow/dist/style.css'; import 'metrics-graphics/dist/mg.css'; import PipelineConfigModal from './PipelineConfigModal'; import { - OutputData, StopType, useJobCheckpoints, - useJobOutput, useJobMetrics, useOperatorErrors, usePipeline, @@ -52,11 +50,10 @@ import { PipelineOutputs } from './PipelineOutputs'; import PaginatedContent from '../../components/PaginatedContent'; import SyntaxHighlighter from 'react-syntax-highlighter'; import { vs2015 } from 'react-syntax-highlighter/dist/esm/styles/hljs'; +import { useNavbar } from '../../App'; export function PipelineDetails() { const [activeOperator, setActiveOperator] = useState<string | undefined>(undefined); - const [outputs, setOutputs] = useState<Array<{ id: number; data: OutputData }>>([]); - const [subscribed, setSubscribed] = useState<boolean>(false); const { isOpen: configModalOpen, onOpen: onConfigModalOpen, @@ -76,6 +73,12 @@ export function PipelineDetails() { const hasErrors = operatorErrorsPages?.length && operatorErrorsPages[0]?.data.length > 0; + const { setMenuItems } = useNavbar(); + + useEffect(() => { + setMenuItems([]); + }, []); + if (pipelineError || jobsError) { return ( <PipelineNotFound @@ -89,24 +92,6 @@ export function PipelineDetails() { return <Loading />; } - const sseHandler = (event: MessageEvent) => { - const parsed = JSON.parse(event.data) as OutputData; - outputs.push({ id: Number(event.lastEventId), data: parsed }); - if (outputs.length > 20) { - outputs.shift(); - } - setOutputs(outputs.slice()); - }; - - const subscribe = async () => { - if (subscribed) { - return; - } - - setSubscribed(true); - useJobOutput(sseHandler, pipeline.id, job?.id); - }; - async function updateJobState(stop: StopType) { console.log(`Setting pipeline stop_mode=${stop}`); updatePipeline({ stop }); @@ -172,17 +157,11 @@ export function PipelineDetails() { ); const outputsTab = ( - <TabPanel w={'100%'}> - {outputs.length == 0 ? ( - pipeline.graph.nodes.find(n => n.operator.includes('preview')) != null ? ( - <Button isLoading={subscribed} onClick={subscribe} width={150} size="sm"> - Read output - </Button> - ) : ( - <Text>Pipeline does not have a web sink</Text> - ) + <TabPanel w={'100%'} h={'100%'}> + {pipeline.graph.nodes.find(n => n.operator.includes('preview')) == null ? ( + <Text>Pipeline does not have a web sink</Text> ) : ( - <PipelineOutputs outputs={outputs} /> + <PipelineOutputs pipelineId={pipeline.id} job={job} onDemand={true} /> )} </TabPanel> ); diff --git a/webui/src/routes/pipelines/PipelineEditorTabs.tsx b/webui/src/routes/pipelines/PipelineEditorTabs.tsx index 97c81b1f5..cee038292 100644 --- a/webui/src/routes/pipelines/PipelineEditorTabs.tsx +++ b/webui/src/routes/pipelines/PipelineEditorTabs.tsx @@ -1,7 +1,11 @@ -import React, { useContext } from 'react'; +import React, { Dispatch, useContext } from 'react'; import { Box, + Button, + Checkbox, Flex, + FormControl, + FormHelperText, HStack, Icon, IconButton, @@ -12,6 +16,7 @@ import { PopoverContent, PopoverHeader, PopoverTrigger, + Stack, Tab, TabList, TabPanel, @@ -28,13 +33,38 @@ import { PiFileSqlDuotone } from 'react-icons/pi'; import { LocalUdfsContext } from '../../udf_state'; import UdfEditor from '../udfs/UdfEditor'; import UdfEditTab from '../udfs/UdfEditTab'; +import { FiCheckCircle, FiPlay } from 'react-icons/fi'; +import { IoRocketOutline } from 'react-icons/io5'; +import { PreviewOptions } from './CreatePipeline'; +import { Job } from '../../lib/data_fetching'; export interface PipelineEditorTabsProps { queryInput: string; + previewing: boolean | undefined; + startingPreview: boolean; + preview: () => void; + stopPreview: () => void; + run: () => void; + pipelineIsValid: (tab: number) => void; updateQuery: (s: string) => void; + previewOptions: PreviewOptions; + setPreviewOptions: Dispatch<PreviewOptions>; + job?: Job; } -const PipelineEditorTabs: React.FC<PipelineEditorTabsProps> = ({ queryInput, updateQuery }) => { +const PipelineEditorTabs: React.FC<PipelineEditorTabsProps> = ({ + queryInput, + previewing, + startingPreview, + preview, + stopPreview, + run, + pipelineIsValid, + updateQuery, + previewOptions, + setPreviewOptions, + job, +}) => { const { openedUdfs, isGlobal, editorTab, handleEditorTabChange } = useContext(LocalUdfsContext); const { isOpen: exampleQueriesIsOpen, @@ -65,6 +95,12 @@ const PipelineEditorTabs: React.FC<PipelineEditorTabsProps> = ({ queryInput, upd <IconButton icon={<HiOutlineBookOpen />} aria-label="Example queries" + title="Example queries" + size={'xs'} + mr={4} + borderColor={'gray.500'} + borderWidth={'1px'} + px={2} onClick={() => { openExampleQueries(); setTourStep(TourSteps.ExampleQuery); @@ -81,9 +117,9 @@ const PipelineEditorTabs: React.FC<PipelineEditorTabsProps> = ({ queryInput, upd ); const tabs = ( - <Flex flexWrap={'wrap'}> - <Tab gap={1}> - <Icon as={PiFileSqlDuotone} boxSize={5} /> + <Flex flexWrap={'nowrap'} overflowX={'auto'} style={{ scrollbarWidth: 'none' }}> + <Tab gap={1} height={10}> + <Icon as={PiFileSqlDuotone} boxSize={4} /> Query </Tab> {openedUdfs.map(udf => { @@ -126,19 +162,158 @@ const PipelineEditorTabs: React.FC<PipelineEditorTabsProps> = ({ queryInput, upd </TabPanels> ); + let startPreviewButton = <></>; + let stopPreviewButton = <></>; + + if (previewing) { + stopPreviewButton = ( + <Button + onClick={stopPreview} + size="xs" + colorScheme="blue" + title="Stop a preview pipeline" + borderRadius={2} + disabled={job?.state != 'Running'} + > + Stop + </Button> + ); + } else { + startPreviewButton = ( + <Button + onClick={preview} + size="xs" + title="Run a preview pipeline" + borderRadius={2} + isLoading={startingPreview} + backgroundColor={'gray.700'} + borderColor={'gray.500'} + borderWidth={'1px'} + > + <HStack spacing={2}> + <Icon as={FiPlay}></Icon> + <Text>Preview</Text> + </HStack> + </Button> + ); + } + + if (tourStep == TourSteps.Preview) { + startPreviewButton = ( + <Popover isOpen={true} placement={'top'} closeOnBlur={false} variant={'tour'}> + <PopoverTrigger>{startPreviewButton}</PopoverTrigger> + <PopoverContent> + <PopoverArrow /> + <PopoverCloseButton onClick={disableTour} /> + <PopoverHeader>Nice!</PopoverHeader> + <PopoverBody> + Finally, run a preview pipeline to see the results of your query. + </PopoverBody> + </PopoverContent> + </Popover> + ); + } else if (!previewing) { + startPreviewButton = ( + <Popover trigger="hover"> + <PopoverTrigger>{startPreviewButton}</PopoverTrigger> + <PopoverContent mt={2}> + <PopoverArrow /> + <PopoverHeader> + <Text fontWeight={'bold'} p={2} my={0} fontSize={'sm'}> + Preview options + </Text> + </PopoverHeader> + <PopoverBody p={4}> + <Stack> + <FormControl> + <Checkbox + checked={previewOptions.enableSinks} + onChange={e => + setPreviewOptions({ ...previewOptions, enableSinks: e.target.checked }) + } + > + Enable sinks + </Checkbox> + <FormHelperText fontSize={'xs'}> + By default, sinks are disabled in preview mode + </FormHelperText> + </FormControl> + </Stack> + </PopoverBody> + </PopoverContent> + </Popover> + ); + } + + const checkButton = ( + <Button + size="xs" + color={'white'} + backgroundColor={'gray.700'} + onClick={() => pipelineIsValid(0)} + title="Check that the SQL is valid" + borderRadius={2} + borderColor={'gray.500'} + borderWidth={'1px'} + > + <HStack spacing={2}> + <Icon as={FiCheckCircle}></Icon> + <Text>Check</Text> + </HStack> + </Button> + ); + + const startPipelineButton = ( + <Button + size="xs" + backgroundColor={'gray.700'} + onClick={run} + borderRadius={2} + color="green.200" + borderColor={'gray.500'} + borderWidth={'1px'} + > + <HStack> + <Icon as={IoRocketOutline} /> + <Text>Launch</Text> + </HStack> + </Button> + ); + return ( <Flex direction={'column'} backgroundColor="#1e1e1e" height="100%"> <Tabs + size={'sm'} display={'flex'} flexDirection={'column'} flex={1} index={editorTab} onChange={handleEditorTabChange} > - <TabList display={'grid'} gridTemplateColumns={'minmax(0, 1fr) min-content'} width={'100%'}> - {tabs} - <HStack p={4}>{exampleQueriesButton}</HStack> - </TabList> + <HStack spacing={0}> + <TabList + display={'grid'} + gridTemplateColumns={'minmax(0, 1fr) min-content'} + width={'100%'} + h={10} + > + {tabs} + </TabList> + <HStack + backgroundColor={'gray.700'} + border={'1px solid #111'} + boxShadow={'-5px 5px 15px #00000044'} + h="100%" + pl={4} + spacing={2} + > + {checkButton} + {startPreviewButton} + {stopPreviewButton} + {startPipelineButton} + {exampleQueriesButton} + </HStack> + </HStack> {tabPanels} </Tabs> {exampleQueries} diff --git a/webui/src/routes/pipelines/PipelineGraph.tsx b/webui/src/routes/pipelines/PipelineGraph.tsx index b10214b57..aa12cd408 100644 --- a/webui/src/routes/pipelines/PipelineGraph.tsx +++ b/webui/src/routes/pipelines/PipelineGraph.tsx @@ -80,7 +80,7 @@ export function PipelineGraphViewer({ x: 0, y: 0, width: 200, - height: 100, + height: 50, }; }); @@ -109,7 +109,7 @@ export function PipelineGraphViewer({ }); return ( - <Box className="pipelineGraph"> + <Box className="pipelineGraph" h="100%"> <ReactFlow proOptions={{ hideAttribution: true }} nodes={nodes} diff --git a/webui/src/routes/pipelines/PipelineOutputs.tsx b/webui/src/routes/pipelines/PipelineOutputs.tsx index 03323ccac..68a718034 100644 --- a/webui/src/routes/pipelines/PipelineOutputs.tsx +++ b/webui/src/routes/pipelines/PipelineOutputs.tsx @@ -1,50 +1,185 @@ -import { Th, Td, Tr, Table, Thead, Tbody } from '@chakra-ui/react'; -import { ReactElement } from 'react'; -import { OutputData } from '../../lib/data_fetching'; - -export function PipelineOutputs({ outputs }: { outputs: Array<{ id: number; data: OutputData }> }) { - let headers: Array<ReactElement> = []; - const data = outputs - .map(row => { - const output = row.data; - let parsed = JSON.parse(output.value); - - let cols: Array<ReactElement> = []; - - if (headers.length == 0) { - Object.keys(parsed).forEach(k => { - headers.push(<Th key={k}>{k}</Th>); - }); - } - - Object.values(parsed).forEach((v, i) => { - cols.push(<Td key={i}>{JSON.stringify(v, null, 2)}</Td>); +import { Text, Button, Stack, Box, HStack, Spacer, Spinner } from '@chakra-ui/react'; +import { useEffect, useRef, useState, useCallback } from 'react'; +import { Job, OutputData } from '../../lib/data_fetching'; +import { AgGridReact } from 'ag-grid-react'; +import 'ag-grid-community/styles/ag-grid.css'; +import '@fontsource/ibm-plex-mono'; +import '../../styles/data-grid-style.css'; + +export function PipelineOutputs({ + pipelineId, + job, + onDemand = false, +}: { + pipelineId: string; + job: Job; + onDemand: boolean; +}) { + const gridRef = useRef<AgGridReact>(null); + const outputSource = useRef<EventSource | undefined>(undefined); + const currentJobId = useRef<string | undefined>(undefined); + const [cols, setCols] = useState<any | undefined>(undefined); + const [rows, setRows] = useState<any[]>([]); + const [subscribed, setSubscribed] = useState<boolean>(false); + const rowsRead = useRef(0); + const rowsInTable = useRef(0); + const rowRef = useRef<HTMLSpanElement | null>(null); + + const MAX_ROWS = 10_000; + + const sseHandler = (event: MessageEvent) => { + const record = JSON.parse(event.data) as OutputData; + const id = record.startId; + const batch: any[] = JSON.parse(record.batch); + + if (cols == undefined && batch.length > 0) { + setCols([ + { + headerName: '', + field: 'id', + width: 70, + resizable: false, + pinned: 'left', + cellStyle: { color: 'var(--chakra-colors-purple-500)' }, + }, + { field: 'timestamp', width: 210, cellStyle: { color: 'var(--chakra-colors-green-500)' } }, + ...Object.keys(batch[0]).map(k => { + return { + headerName: k, + field: k, + }; + }), + ]); + } + + rowsRead.current = rowsRead.current + batch.length; + rowsInTable.current = rowsInTable.current + batch.length; + + if (rowRef.current) { + rowRef.current.innerText = String(rowsRead.current); + } + + batch.forEach((r, i) => { + Object.keys(r).forEach(k => { + if (typeof r[k] === 'object') { + r[k] = JSON.stringify(r[k]); + } + }); + + r.id = id + i; + r.timestamp = new Date(record.timestamps[i] / 1000).toISOString(); + }); + + batch.reverse(); + + let op: any = { + add: batch, + addIndex: 0, + }; + + if (rowsInTable.current > MAX_ROWS) { + let remove: any[] = []; + gridRef.current!.api.forEachNode((node, idx) => { + if (idx > rowsInTable.current - MAX_ROWS) { + remove.push(node.data); + } }); + op.remove = remove; + rowsInTable.current = rowsInTable.current - remove.length; + } + + gridRef.current!.api.applyTransaction(op)!; + }; + + const close = () => { + if (outputSource.current) { + outputSource.current.removeEventListener('message', sseHandler); + outputSource.current.close(); + } + }; + + const clearData = useCallback(() => { + const rowData: any[] = []; + gridRef.current!.api.forEachNode(function (node) { + rowData.push(node.data); + }); + const res = gridRef.current!.api.applyTransaction({ + remove: rowData, + })!; + }, []); + + useEffect(() => { + if (onDemand && !subscribed) { + close(); + return; + } + + if (outputSource.current?.readyState != EventSource.CLOSED && currentJobId.current == job.id) { + return; + } + + close(); - return ( - <Tr key={row.id}> - <Th key={'row'}>{row.id + 1}</Th> - <Th key={'date'}> - {new Intl.DateTimeFormat('en-US', { dateStyle: 'short', timeStyle: 'long' }).format( - new Date(Number(output.timestamp) / 1000) - )} - </Th> - {cols} - </Tr> - ); - }) - .reverse(); + if (pipelineId && job.id) { + const url = `/api/v1/pipelines/${pipelineId}/jobs/${job.id}/output`; + const eventSource = new EventSource(url); + eventSource.onerror = () => { + setSubscribed(false); + eventSource.close(); + }; + outputSource.current = eventSource; + eventSource.addEventListener('message', sseHandler); + currentJobId.current = job.id; + } + }, [job, subscribed]); return ( - <Table maxWidth="500px"> - <Thead> - <Tr> - <Th>Row</Th> - <Th>Time</Th> - {headers} - </Tr> - </Thead> - <Tbody>{data}</Tbody> - </Table> + <Stack h="100%"> + <Box h="100%" display={onDemand && !subscribed && !cols ? 'none' : 'block'}> + <AgGridReact + autoSizeStrategy={{ type: 'fitCellContents' }} + skipHeaderOnAutoSize={true} + ref={gridRef} + suppressFieldDotNotation={true} + animateRows={false} + className="ag-theme-custom" + rowData={rows} + columnDefs={cols} + suppressDragLeaveHidesColumns={true} + /> + </Box> + {onDemand && ( + <HStack spacing={4}> + <Button + onClick={() => setSubscribed(!subscribed)} + size="xs" + opacity={'0.9'} + colorScheme={!subscribed ? 'green' : 'gray'} + variant={'solid'} + rounded={'sm'} + isLoading={job.state != 'Running'} + title={ + subscribed + ? 'Stop tailing output' + : job.state == 'Running' + ? 'Start tailing output from pipeline' + : 'Job must be running to tail output' + } + > + <HStack spacing={2}> + {subscribed && <Spinner size="xs" speed={'0.9s'} />} + <Text>{!subscribed ? 'Start tailing' : 'Stop tailing'}</Text> + </HStack> + </Button> + <Button rounded={'sm'} size="xs" onClick={clearData} variant={'outline'}> + Clear + </Button> + <Spacer /> + <Text fontFamily={'monospace'}> + read <span ref={rowRef}>{rowsRead.current}</span> rows + </Text> + </HStack> + )} + </Stack> ); } diff --git a/webui/src/routes/pipelines/PipelinesIndex.tsx b/webui/src/routes/pipelines/PipelinesIndex.tsx index 0ada90ddd..2211704c0 100644 --- a/webui/src/routes/pipelines/PipelinesIndex.tsx +++ b/webui/src/routes/pipelines/PipelinesIndex.tsx @@ -2,10 +2,17 @@ import './pipelines.css'; import { Button, Container, Heading, HStack, Stack } from '@chakra-ui/react'; import { useLinkClickHandler } from 'react-router-dom'; -import React from 'react'; +import React, { useEffect } from 'react'; import PipelinesTable from '../../components/PipelinesTable'; +import { useNavbar } from '../../App'; export function PipelinesIndex() { + const { setMenuItems } = useNavbar(); + + useEffect(() => { + setMenuItems([]); + }, []); + return ( <Container py="8" flex="1"> <Stack spacing={{ base: '8', lg: '6' }}> diff --git a/webui/src/routes/pipelines/ResourcePanel.tsx b/webui/src/routes/pipelines/ResourcePanel.tsx index 3781764b8..105ab301d 100644 --- a/webui/src/routes/pipelines/ResourcePanel.tsx +++ b/webui/src/routes/pipelines/ResourcePanel.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { Flex, HStack, Stack, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react'; -import CatalogTab from './CatalogTab'; import UdfsResourceTab from '../udfs/UdfsResourceTab'; export interface ResourcePanelProps { @@ -35,9 +34,7 @@ const ResourcePanel: React.FC<ResourcePanelProps> = ({ tabIndex, handleTabChange </Flex> </TabList> <TabPanels flex={1}> - <TabPanel height={'100%'} display={'flex'} px={5}> - <CatalogTab /> - </TabPanel> + <TabPanel height={'100%'} display={'flex'} px={5}></TabPanel> <TabPanel height={'100%'} px={5}> <UdfsResourceTab /> </TabPanel> diff --git a/webui/src/routes/udfs/UdfEditTab.tsx b/webui/src/routes/udfs/UdfEditTab.tsx index 37ff31977..a220699be 100644 --- a/webui/src/routes/udfs/UdfEditTab.tsx +++ b/webui/src/routes/udfs/UdfEditTab.tsx @@ -40,7 +40,7 @@ const UdfEditTab: React.FC<UdfEditTabProps> = ({ udf }) => { const cancelDeleteRef = useRef<HTMLButtonElement>(null); const tab = ( - <Tab px={2} key={udf.id}> + <Tab height={10} px={2} key={udf.id}> <UdfLabel udf={udf} /> <CloseButton as={'div'} w={5} fontSize={8} onClick={() => closeUdf(udf)} /> </Tab> @@ -119,9 +119,9 @@ const UdfEditTab: React.FC<UdfEditTabProps> = ({ udf }) => { return ( <> - <Popover trigger={'hover'} variant={'default'} closeDelay={0} gutter={-8}> + <Popover trigger={'hover'} variant={'default'} closeDelay={100} gutter={-8}> <PopoverTrigger>{tab}</PopoverTrigger> - <PopoverContent width={'min-content'}> + <PopoverContent width={'min-content'} mt={2}> <PopoverArrow /> <PopoverHeader> <Text align={'center'} fontStyle={'italic'} fontSize={'sm'}> diff --git a/webui/src/routes/udfs/UdfLabel.tsx b/webui/src/routes/udfs/UdfLabel.tsx index 38cf0e9f5..48a9df9eb 100644 --- a/webui/src/routes/udfs/UdfLabel.tsx +++ b/webui/src/routes/udfs/UdfLabel.tsx @@ -1,8 +1,9 @@ import React, { useContext } from 'react'; -import { Code, Flex, Icon } from '@chakra-ui/react'; +import { Text, Flex, Icon } from '@chakra-ui/react'; import { DiRust } from 'react-icons/di'; import { LocalUdf, LocalUdfsContext, nameRoot } from '../../udf_state'; import { GlobalUdf } from '../../lib/data_fetching'; +import '@fontsource/ibm-plex-mono'; export interface UdfLabelProps { udf: LocalUdf | GlobalUdf; @@ -15,17 +16,19 @@ const UdfLabel: React.FC<UdfLabelProps> = ({ udf }) => { return ( <Flex alignItems={'center'} onClick={() => openTab(udf)} cursor={'pointer'} w={'min-content'}> <Icon as={DiRust} boxSize={5} /> - <Code + <Text borderRadius={3} - fontSize={'md'} + fontSize={'sm'} + p={1} borderBottom={hasErrors ? '2px dotted red' : 'none'} textOverflow={'ellipsis'} whiteSpace={'normal'} noOfLines={1} textDecoration={isOverridden(udf) ? 'line-through' : 'none'} + fontFamily={'IBM Plex Mono, monospace'} > {nameRoot(udf.name)} - </Code> + </Text> </Flex> ); }; diff --git a/webui/src/styles/data-grid-style.css b/webui/src/styles/data-grid-style.css new file mode 100644 index 000000000..097f6c08d --- /dev/null +++ b/webui/src/styles/data-grid-style.css @@ -0,0 +1,4967 @@ +/* + * This file is a theme downloaded from the AG Grid Theme Builder for AG Grid 31.3.2. + * + * See installation docs at https://www.ag-grid.com/javascript-data-grid/applying-theme-builder-styling-grid/ + */ + +@import url('https://fonts.googleapis.com/css2?family=IBM%20Plex%20Mono:wght@400;700&display=swap'); + +.ag-theme-custom { + --ag-background-color: #26262617; + --ag-foreground-color: #dff0e3; + --ag-text-color: var(--ag-foreground-color); + --ag-accent-color: #00a2ff; + --ag-invalid-color: #e02525; + --ag-border-color: #45ff0c0f; + --ag-wrapper-border: solid 1px var(--ag-border-color); + --ag-row-border: solid 1px var(--ag-border-color); + --ag-header-border: var(--ag-row-border); + --ag-footer-border: var(--ag-row-border); + --ag-column-border: solid 1px var(--ag-border-color); + --ag-column-header-border: var(--ag-column-border); + --ag-column-header-border-height: 100%; + --ag-pinned-column-border: solid 1px var(--ag-border-color); + --ag-pinned-row-border: solid 1px var(--ag-border-color); + --ag-side-panel-border: solid 1px var(--ag-border-color); + --ag-side-button-selected-border: solid 1px var(--ag-border-color); + --ag-side-button-selected-background-color: var(--ag-background-color); + --ag-side-bar-background-color: var(--ag-chrome-background-color); + --ag-font-family: 'IBM Plex Mono'; + --ag-chrome-background-color: color-mix(in srgb, transparent, var(--ag-foreground-color) 2%); + --ag-header-background-color: #21222c; + --ag-header-font-family: var(--ag-font-family); + --ag-header-font-weight: 700; + --ag-header-font-size: 14px; + --ag-header-text-color: #eefff2; + --ag-header-cell-hover-background-color: transparent; + --ag-header-cell-hover-background-transition-duration: 0.2s; + --ag-data-color: #d9d9d9; + --ag-subtle-text-color: color-mix(in srgb, transparent, var(--ag-text-color) 50%); + --ag-range-selection-border-style: solid; + --ag-range-selection-border-color: var(--ag-accent-color); + --ag-range-selection-background-color: color-mix( + in srgb, + transparent, + var(--ag-accent-color) 20% + ); + --ag-range-selection-chart-background-color: #0058ff1a; + --ag-range-selection-chart-category-background-color: #00ff841a; + --ag-range-selection-highlight-color: color-mix(in srgb, transparent, var(--ag-accent-color) 50%); + --ag-row-hover-color: color-mix(in srgb, transparent, var(--ag-accent-color) 12%); + --ag-column-hover-color: color-mix(in srgb, transparent, var(--ag-accent-color) 5%); + --ag-selected-row-background-color: color-mix(in srgb, transparent, var(--ag-accent-color) 8%); + --ag-modal-overlay-background-color: color-mix( + in srgb, + transparent, + var(--ag-background-color) 66% + ); + --ag-odd-row-background-color: #0000002b; + --ag-border-radius: 0px; + --ag-wrapper-border-radius: 0px; + --ag-cell-horizontal-padding: calc( + var(--ag-grid-size) * 2 * var(--ag-cell-horizontal-padding-scale) + ); + --ag-cell-widget-spacing: calc(var(--ag-grid-size) * 1.5); + --ag-cell-horizontal-padding-scale: 1; + --ag-label-widget-spacing: var(--ag-grid-size); + --ag-row-group-indent-size: calc(var(--ag-cell-widget-spacing) + var(--ag-icon-size)); + --ag-value-change-delta-up-color: #43a047; + --ag-value-change-delta-down-color: #e53935; + --ag-value-change-value-highlight-background-color: #16a08580; + --ag-grid-size: 3px; + --ag-font-size: 13px; + --ag-row-height: calc( + max(var(--ag-icon-size), var(--ag-font-size)) + var(--ag-grid-size) * 3.5 * + var(--ag-row-vertical-padding-scale) + ); + --ag-row-vertical-padding-scale: 1.5; + --ag-header-height: calc( + max(var(--ag-icon-size), var(--ag-font-size)) + var(--ag-grid-size) * 4.25 * + var(--ag-header-vertical-padding-scale) + ); + --ag-header-vertical-padding-scale: 1.5; + --ag-popup-shadow: 0 0 16px 0 #00000026; + --ag-dropdown-shadow: 0 1px 4px 1px #babfc766; + --ag-drag-ghost-background-color: var(--ag-background-color); + --ag-drag-ghost-border: solid 1px var(--ag-border-color); + --ag-drag-ghost-shadow: var(--ag-popup-shadow); + --ag-focus-shadow: 0 0 0 3px color-mix(in srgb, transparent, var(--ag-accent-color) 50%); + --ag-side-bar-panel-width: 250px; + --ag-header-column-resize-handle-display: block; + --ag-header-column-resize-handle-height: 30%; + --ag-header-column-resize-handle-width: 2px; + --ag-header-column-resize-handle-color: var(--ag-border-color); + --ag-widget-container-horizontal-padding: calc(var(--ag-grid-size) * 1.5); + --ag-widget-container-vertical-padding: calc(var(--ag-grid-size) * 1.5); + --ag-widget-horizontal-spacing: calc(var(--ag-grid-size) * 1.5); + --ag-widget-vertical-spacing: var(--ag-grid-size); + --ag-list-item-height: calc(var(--ag-icon-size) + var(--ag-widget-vertical-spacing)); + --ag-icon-size: 16px; + --ag-toggle-button-width: 28px; + --ag-toggle-button-height: 18px; + --ag-toggle-button-border-width: 2px; + --ag-toggle-button-on-border-color: var(--ag-accent-color); + --ag-toggle-button-on-background-color: var(--ag-accent-color); + --ag-toggle-button-off-border-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 30% + ); + --ag-toggle-button-off-background-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 30% + ); + --ag-toggle-button-switch-border-color: var(--ag-toggle-button-off-border-color); + --ag-toggle-button-switch-background-color: var(--ag-background-color); + --ag-checkbox-border-width: 1px; + --ag-checkbox-border-radius: var(--ag-border-radius); + --ag-checkbox-unchecked-background-color: var(--ag-background-color); + --ag-checkbox-unchecked-border-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 30% + ); + --ag-checkbox-checked-background-color: var(--ag-accent-color); + --ag-checkbox-checked-border-color: var(--ag-accent-color); + --ag-checkbox-checked-shape-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%227%22%20fill%3D%22none%22%3E%3Cpath%20stroke%3D%22%23000%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%221.75%22%20d%3D%22M1%203.5%203.5%206l5-5%22%2F%3E%3C%2Fsvg%3E'); + --ag-checkbox-checked-shape-color: var(--ag-background-color); + --ag-checkbox-indeterminate-background-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 30% + ); + --ag-checkbox-indeterminate-border-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 30% + ); + --ag-checkbox-indeterminate-shape-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%222%22%20fill%3D%22none%22%3E%3Crect%20width%3D%2210%22%20height%3D%222%22%20fill%3D%22%23000%22%20rx%3D%221%22%2F%3E%3C%2Fsvg%3E'); + --ag-checkbox-indeterminate-shape-color: var(--ag-background-color); + --ag-radio-checked-shape-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%226%22%20height%3D%226%22%20fill%3D%22none%22%3E%3Ccircle%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E'); + --ag-menu-border: solid 1px color-mix(in srgb, transparent, var(--ag-foreground-color) 20%); + --ag-menu-background-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 3% + ); + --ag-menu-text-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 95% + ); + --ag-menu-shadow: var(--ag-popup-shadow); + --ag-menu-separator-color: var(--ag-border-color); + --ag-set-filter-indent-size: var(--ag-icon-size); + --ag-chart-menu-button-border: solid 1px var(--ag-border-color); + --ag-icon-button-hover-color: color-mix(in srgb, transparent, var(--ag-foreground-color) 10%); + --ag-dialog-shadow: var(--ag-popup-shadow); + --ag-dialog-border: solid 1px color-mix(in srgb, transparent, var(--ag-foreground-color) 20%); + --ag-panel-background-color: var(--ag-background-color); + --ag-panel-title-bar-background-color: var(--ag-header-background-color); + --ag-panel-title-bar-border: solid 1px var(--ag-border-color); + --ag-column-select-indent-size: var(--ag-icon-size); + --ag-tool-panel-separator-border: solid 1px var(--ag-border-color); + --ag-tooltip-background-color: var(--ag-chrome-background-color); + --ag-tooltip-text-color: var(--ag-text-color); + --ag-tooltip-border: solid 1px var(--ag-border-color); + --ag-column-drop-cell-background-color: color-mix( + in srgb, + transparent, + var(--ag-foreground-color) 7% + ); + --ag-column-drop-cell-border: solid 1px + color-mix(in srgb, transparent, var(--ag-foreground-color) 13%); + --ag-advanced-filter-builder-button-bar-border: solid 1px var(--ag-border-color); + --ag-advanced-filter-builder-indent-size: calc(var(--ag-grid-size) * 2 + var(--ag-icon-size)); + --ag-advanced-filter-builder-join-pill-color: #f08e8d; + --ag-advanced-filter-builder-column-pill-color: #a6e194; + --ag-advanced-filter-builder-option-pill-color: #f3c08b; + --ag-advanced-filter-builder-value-pill-color: #85c0e4; + --ag-filter-tool-panel-group-indent: calc(var(--ag-grid-size)); + --ag-icon-button-hover-background-color: color-mix( + in srgb, + transparent, + var(--ag-foreground-color) 10% + ); + --ag-row-loading-skeleton-effect-color: rgba(66, 66, 66, 0.2); + --ag-tab-bar-background-color: color-mix(in srgb, transparent, var(--ag-foreground-color) 5%); + --ag-tab-bar-horizontal-padding: 0; + --ag-tab-bar-top-padding: 0; + --ag-tab-background-color: transparent; + --ag-tab-text-color: color-mix(in srgb, transparent, var(--ag-text-color) 70%); + --ag-tab-horizontal-padding: calc(var(--ag-grid-size)); + --ag-tab-top-padding: calc(var(--ag-grid-size)); + --ag-tab-bottom-padding: calc(var(--ag-grid-size)); + --ag-tab-spacing: 0; + --ag-tab-hover-background-color: var(--ag-tab-background-color); + --ag-tab-hover-text-color: var(--ag-text-color); + --ag-tab-selected-background-color: var(--ag-background-color); + --ag-tab-selected-text-color: var(--ag-text-color); + --ag-tab-selected-border-width: 1px; + --ag-tab-selected-border-color: var(--ag-border-color); + --ag-tab-selected-underline-color: transparent; + --ag-tab-selected-underline-width: 0; + --ag-tab-selected-underline-transition-duration: 0; + --ag-tab-bar-border: solid 1px var(--ag-border-color); + --ag-input-background-color: var(--ag-background-color); + --ag-input-border: solid 1px var(--ag-border-color); + --ag-input-border-radius: var(--ag-border-radius); + --ag-input-text-color: var(--ag-text-color); + --ag-input-padding-start: var(--ag-grid-size); + --ag-input-height: calc(max(var(--ag-icon-size), var(--ag-font-size)) + var(--ag-grid-size) * 2); + --ag-input-focus-background-color: var(--ag-input-background-color); + --ag-input-focus-border: solid 1px var(--ag-accent-color); + --ag-input-focus-shadow: var(--ag-focus-shadow); + --ag-input-focus-text-color: var(--ag-input-text-color); + --ag-input-disabled-background-color: color-mix( + in srgb, + var(--ag-background-color), + var(--ag-foreground-color) 6% + ); + --ag-input-disabled-border: var(--ag-input-border); + --ag-input-disabled-text-color: color-mix(in srgb, transparent, var(--ag-text-color) 50%); + --ag-input-invalid-background-color: var(--ag-input-background-color); + --ag-input-invalid-border: solid 1px var(--ag-invalid-color); + --ag-input-invalid-text-color: var(--ag-input-text-color); +} + +/* Part core/part */ +:where([class^='ag-']), +:where([class^='ag-']):after, +:where([class^='ag-']):before, +:where([class^='ag-']):focus, +:where([class^='ag-']):focus-within { + box-sizing: border-box; + outline: none; +} +:where([class^='ag-']):where(button), +:where([class^='ag-']):where(input), +:where([class^='ag-']):where(textarea) { + background: none; + border: none; + color: inherit; + cursor: pointer; + font-family: inherit; + font-size: inherit; + line-height: inherit; + margin: 0; + padding: 0; +} +:where([class^='ag-']):where(button) { + font-weight: inherit; +} +:where([class^='ag-'])::-ms-clear { + display: none; +} +ag-grid, +ag-grid-angular, +ag-grid-aurelia, +ag-grid-ng2, +ag-grid-polymer { + display: block; +} +.ag-aria-description-container { + border: 0; + z-index: 9999; + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + padding: 0; + position: absolute; + white-space: nowrap; + width: 1px; +} +.ag-hidden { + display: none !important; +} +.ag-invisible { + visibility: hidden !important; +} +.ag-no-transition { + transition: none !important; +} +.ag-unselectable { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-selectable { + -webkit-user-select: text; + -moz-user-select: text; + user-select: text; +} +.ag-tabs-header { + display: flex; +} +.ag-tab { + cursor: pointer; + position: relative; +} +.ag-tab-guard { + display: block; + height: 0; + width: 0; +} +.ag-select-agg-func-popup, +.ag-tab-guard { + position: absolute; +} +.ag-shake-left-to-right { + animation-direction: alternate; + animation-duration: 0.2s; + animation-iteration-count: infinite; + animation-name: ag-shake-left-to-right; +} +@keyframes ag-shake-left-to-right { + 0% { + padding-left: 6px; + padding-right: 2px; + } + to { + padding-left: 2px; + padding-right: 6px; + } +} +.ag-watermark { + bottom: 20px; + color: #9b9b9b; + opacity: 0.7; + position: absolute; + right: 25px; + transition: opacity 1s ease-out 3s; +} +.ag-watermark:before { + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDkiIGhlaWdodD0iMzYiIGZpbGw9Im5vbmUiPjxwYXRoIGZpbGw9IiM5QjlCOUIiIGQ9Ik0xOTIuOTkzIDIzLjY1OHYtNy45NDZoLTEzLjU0MWwtNy45NDcgNy45NDZ6TTIwOC4yNSAzLjk1aC0xNi45NzRsLTguMDEgNy45NDdoMjQuOTg0ek0xNjMuNjIyIDMxLjYwNWw0LjA2OS00LjA2OWgxMy43MzJ2Ny45NDdoLTE3LjgwMXoiLz48cGF0aCBmaWxsPSIjOUI5QjlCIiBkPSJNMTY2LjYxIDE5Ljc4aDguNzczbDguMDEtNy45NDZIMTY2LjYxek0xNTcuMDExIDMxLjYwNWg2LjYxMWw3Ljg4My03Ljk0N2gtMTQuNDk0ek0xOTEuMjc2IDMuOTVsLTQuMDY4IDQuMDdIMTYxLjI3Vi4wNzJoMzAuMDA2ek0yMC44NCAzMC4yMDZIOC4zNzhsLTIuMTYyIDUuMzRILjc1TDEyLjI1NyA4LjU5Mmg0Ljc2OEwyOC41MyAzNS41NDZoLTUuNTN6bS0xLjcxNy00LjI2TDE0LjYwOSAxNC45NWwtNC41MTQgMTAuOTk4ek0xMDQuNDM3IDE4LjUwOWMxLjU4OS0yLjM1MiA1LjU5NC0yLjYwNyA3LjI0Ny0yLjYwN3Y0LjU3OGMtMi4wMzQgMC00LjA2OS4wNjMtNS4yNzcuOTUzLTEuMjA3Ljg5LTEuODQzIDIuMDk4LTEuODQzIDMuNTZ2MTAuNTUzaC00Ljk1OVYxNS45MDJoNC43Njh6TTExOS4zNzYgMTUuOTAyaC00Ljk1OHYxOS42NDRoNC45NTh6TTExOS4zNzYgNy4xM2gtNC45NTh2NS44NDhoNC45NTh6TTE0My45NzkgNy4xM3YyOC40MTZoLTQuNzY4bC0uMTI3LTIuOTg4YTguMyA4LjMgMCAwIDEtMi42NyAyLjQ4Yy0xLjA4MS41NzItMi40MTYuODktMy45NDIuODktMS4zMzUgMC0yLjYwNi0uMjU1LTMuNjg3LS43LTEuMTQ0LS41MDgtMi4xNjItMS4xNDQtMi45ODgtMi4wMzRhOS42IDkuNiAwIDAgMS0xLjk3MS0zLjE3OWMtLjUwOC0xLjIwNy0uNjk5LTIuNjA2LS42OTktNC4xMzJzLjI1NC0yLjkyNC42OTktNC4xOTZjLjUwOS0xLjI3MSAxLjE0NS0yLjM1MiAxLjk3MS0zLjI0MnMxLjg0NC0xLjU4OSAyLjk4OC0yLjA5OCAyLjM1Mi0uNzYzIDMuNjg3LS43NjNjMS41MjYgMCAyLjc5Ny4yNTUgMy44NzguODI3czEuOTcxIDEuMzM1IDIuNjcgMi40MTZWNy4xOTNoNC45NTl6bS0xMC40MjYgMjQuNTM4YzEuNjUzIDAgMi45MjQtLjU3MiAzLjk0MS0xLjY1M3MxLjUyNi0yLjU0MyAxLjUyNi00LjMyMy0uNTA5LTMuMTc4LTEuNTI2LTQuMzIyYy0xLjAxNy0xLjA4MS0yLjI4OC0xLjY1My0zLjk0MS0xLjY1My0xLjU5IDAtMi45MjUuNTcyLTMuODc4IDEuNjUzLTEuMDE3IDEuMDgtMS41MjYgMi41NDMtMS41MjYgNC4zMjIgMCAxLjc4LjUwOSAzLjE4IDEuNTI2IDQuMjYgMS4wMTcgMS4xNDQgMi4yODggMS43MTYgMy44NzggMS43MTZNNTcuMjAyIDIwLjM1M0g0NC45MzN2NC4yNTloNi45OTNjLS4xOSAyLjE2MS0xLjAxNyAzLjgxNC0yLjQxNiA1LjE1LTEuMzk4IDEuMjctMy4xNzggMS45MDYtNS40NjcgMS45MDYtMS4yNzEgMC0yLjQ4LS4yNTQtMy40OTYtLjY5OWE3IDcgMCAwIDEtMi43MzQtMS45N2MtLjc2My0uODI3LTEuMzM1LTEuODQ0LTEuNzgtMy4wNTJzLS42MzYtMi40OC0uNjM2LTMuOTQyLjE5LTIuNzMzLjYzNi0zLjk0MWMuMzgxLTEuMjA4IDEuMDE3LTIuMTYyIDEuNzgtMy4wNTIuNzYzLS44MjYgMS42NTMtMS40NjIgMi43MzMtMS45N2E5LjEgOS4xIDAgMCAxIDMuNTYtLjdxNC4wMDUgMCA2LjEwMyAxLjkwN2wzLjMwNi0zLjMwNWMtMi40OC0xLjkwNy01LjY1OC0yLjkyNS05LjQwOS0yLjkyNS0yLjA5NyAwLTQuMDA0LjMxOC01LjcyMSAxLjAxOC0xLjcxNi42OTktMy4xNzkgMS41ODktNC4zODYgMi43OTdBMTIuMSAxMi4xIDAgMCAwIDMxLjIgMTYuMjJjLS42MzUgMS43MTctLjk1MyAzLjYyNC0uOTUzIDUuNjU4cy4zMTggMy45NDIgMS4wMTcgNS42NThjLjcgMS43MTcgMS41OSAzLjE3OSAyLjc5NyA0LjM4N2ExMi4xIDEyLjEgMCAwIDAgNC4zODcgMi43OTdjMS43MTYuNyAzLjYyMyAxLjAxNyA1LjY1NyAxLjAxNyAyLjAzNSAwIDMuODc4LS4zMTggNS41MzEtMS4wMTcgMS42NTMtLjcgMy4wNTItMS41OSA0LjE5Ni0yLjc5N3ExLjcxNi0xLjgxMiAyLjY3LTQuMzg3Yy42MzYtMS43MTYuOTU0LTMuNjIzLjk1NC01LjY1OHYtLjgyNmMtLjE5MS0uMTI3LS4yNTUtLjQ0NS0uMjU1LS43TTk1Ljk4MiAyMC4zNTNoLTEyLjI3djQuMjU5aDYuOTkzYy0uMTkgMi4xNjEtMS4wMTcgMy44MTQtMi40MTYgNS4xNS0xLjM5OCAxLjI3LTMuMTc4IDEuOTA2LTUuNDY3IDEuOTA2LTEuMjcxIDAtMi40OC0uMjU0LTMuNDk2LS42OTlhNyA3IDAgMCAxLTIuNzM0LTEuOTdjLS43NjMtLjgyNy0xLjMzNS0xLjg0NC0xLjc4LTMuMDUycy0uNjM2LTIuNDgtLjYzNi0zLjk0Mi4xOS0yLjczMy42MzYtMy45NDFjLjM4MS0xLjIwOCAxLjAxNy0yLjE2MiAxLjc4LTMuMDUyLjc2My0uODI2IDEuNjUzLTEuNDYyIDIuNzM0LTEuOTdhOS4xIDkuMSAwIDAgMSAzLjU2LS43cTQuMDA1IDAgNi4xMDMgMS45MDdsMy4zMDUtMy4zMDVjLTIuNDc5LTEuOTA3LTUuNjU4LTIuOTI1LTkuNDA4LTIuOTI1LTIuMDk4IDAtNC4wMDUuMzE4LTUuNzIyIDEuMDE4LTEuNzE2LjY5OS0zLjE3OCAxLjU4OS00LjM4NiAyLjc5N2ExMi4xIDEyLjEgMCAwIDAtMi43OTcgNC4zODZjLS42MzYgMS43MTctLjk1NCAzLjYyNC0uOTU0IDUuNjU4cy4zMTggMy45NDIgMS4wMTcgNS42NThjLjcgMS43MTcgMS41OSAzLjE3OSAyLjc5NyA0LjM4N2ExMi4xIDEyLjEgMCAwIDAgNC4zODcgMi43OTdjMS43MTYuNyAzLjYyMyAxLjAxNyA1LjY1OCAxLjAxNyAyLjAzNCAwIDMuODc4LS4zMTggNS41My0xLjAxNyAxLjY1My0uNyAzLjA1Mi0xLjU5IDQuMTk2LTIuNzk3cTEuNzE4LTEuODEyIDIuNjctNC4zODdjLjYzNi0xLjcxNi45NTQtMy42MjMuOTU0LTUuNjU4di0uODI2Yy0uMTktLjEyNy0uMjU1LS40NDUtLjI1NS0uNyIvPjwvc3ZnPg==); + background-repeat: no-repeat; + background-size: 170px 40px; + content: ''; + display: block; + height: 40px; + width: 170px; +} +.ag-watermark-text { + font-family: Impact, sans-serif; + font-size: 19px; + font-weight: 700; + opacity: 0.5; +} +.ag-ltr .ag-watermark-text { + padding-left: 0.7rem; +} +.ag-rtl .ag-watermark-text { + padding-right: 0.7rem; +} +.ag-root-wrapper-body { + display: flex; + flex-direction: row; +} +.ag-root-wrapper-body.ag-layout-normal { + flex: 1 1 auto; + height: 0; + min-height: 0; +} +.ag-root { + display: flex; + flex-direction: column; + position: relative; +} +.ag-root.ag-layout-auto-height, +.ag-root.ag-layout-normal { + flex: 1 1 auto; + overflow: hidden; + width: 0; +} +.ag-root.ag-layout-normal { + height: 100%; +} +.ag-body-horizontal-scroll-viewport, +.ag-body-vertical-scroll-viewport, +.ag-body-viewport, +.ag-center-cols-viewport, +.ag-floating-bottom-viewport, +.ag-floating-top-viewport, +.ag-header-viewport, +.ag-sticky-bottom-viewport, +.ag-sticky-top-viewport, +.ag-virtual-list-viewport { + flex: 1 1 auto; + height: 100%; + min-width: 0; + overflow: hidden; + position: relative; +} +.ag-body-viewport, +.ag-center-cols-viewport { + -ms-overflow-style: none !important; + scrollbar-width: none !important; +} +.ag-body-viewport::-webkit-scrollbar, +.ag-center-cols-viewport::-webkit-scrollbar { + display: none !important; +} +.ag-body-viewport { + display: flex; + -webkit-overflow-scrolling: touch; +} +.ag-body-viewport.ag-layout-normal { + overflow-y: auto; +} +.ag-center-cols-viewport { + min-height: 100%; + overflow-x: auto; + width: 100%; +} +.ag-body-horizontal-scroll-viewport { + overflow-x: scroll; +} +.ag-body-vertical-scroll-viewport { + overflow-y: scroll; +} +.ag-virtual-list-viewport { + overflow: auto; + width: 100%; +} +.ag-body-container, +.ag-body-horizontal-scroll-container, +.ag-body-vertical-scroll-container, +.ag-center-cols-container, +.ag-floating-bottom-container, +.ag-floating-bottom-full-width-container, +.ag-floating-top-container, +.ag-full-width-container, +.ag-header-container, +.ag-pinned-left-cols-container, +.ag-pinned-right-cols-container, +.ag-sticky-bottom-container, +.ag-sticky-top-container, +.ag-virtual-list-container { + position: relative; +} +.ag-floating-bottom-container, +.ag-floating-top-container, +.ag-header-container, +.ag-sticky-bottom-container, +.ag-sticky-top-container { + height: 100%; + white-space: nowrap; +} +.ag-center-cols-container, +.ag-pinned-right-cols-container { + display: block; +} +.ag-body-horizontal-scroll-container { + height: 100%; +} +.ag-body-vertical-scroll-container { + width: 100%; +} +.ag-floating-bottom-full-width-container, +.ag-floating-top-full-width-container, +.ag-full-width-container, +.ag-sticky-bottom-full-width-container, +.ag-sticky-top-full-width-container { + pointer-events: none; + position: absolute; + top: 0; +} +.ag-ltr .ag-floating-bottom-full-width-container, +.ag-ltr .ag-floating-top-full-width-container, +.ag-ltr .ag-full-width-container, +.ag-ltr .ag-sticky-bottom-full-width-container, +.ag-ltr .ag-sticky-top-full-width-container { + left: 0; +} +.ag-rtl .ag-floating-bottom-full-width-container, +.ag-rtl .ag-floating-top-full-width-container, +.ag-rtl .ag-full-width-container, +.ag-rtl .ag-sticky-bottom-full-width-container, +.ag-rtl .ag-sticky-top-full-width-container { + right: 0; +} +.ag-full-width-container { + width: 100%; +} +.ag-floating-bottom-full-width-container, +.ag-floating-top-full-width-container { + display: inline-block; + height: 100%; + overflow: hidden; + width: 100%; +} +.ag-virtual-list-container { + overflow: hidden; +} +.ag-body { + display: flex; + flex: 1 1 auto; + flex-direction: row !important; + min-height: 0; + position: relative; +} +.ag-body-horizontal-scroll, +.ag-body-vertical-scroll { + display: flex; + min-height: 0; + min-width: 0; + position: relative; +} +.ag-body-horizontal-scroll.ag-scrollbar-invisible, +.ag-body-vertical-scroll.ag-scrollbar-invisible { + bottom: 0; + position: absolute; +} +.ag-body-horizontal-scroll.ag-scrollbar-invisible.ag-apple-scrollbar, +.ag-body-vertical-scroll.ag-scrollbar-invisible.ag-apple-scrollbar { + opacity: 0; + transition: opacity 0.4s; + visibility: hidden; +} +.ag-body-horizontal-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-active, +.ag-body-horizontal-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-scrolling, +.ag-body-vertical-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-active, +.ag-body-vertical-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-scrolling { + opacity: 1; + visibility: visible; +} +.ag-body-horizontal-scroll { + width: 100%; +} +.ag-body-horizontal-scroll.ag-scrollbar-invisible { + left: 0; + right: 0; +} +.ag-body-vertical-scroll { + height: 100%; +} +.ag-body-vertical-scroll.ag-scrollbar-invisible { + top: 0; + z-index: 10; +} +.ag-ltr .ag-body-vertical-scroll.ag-scrollbar-invisible { + right: 0; +} +.ag-rtl .ag-body-vertical-scroll.ag-scrollbar-invisible { + left: 0; +} +.ag-force-vertical-scroll { + overflow-y: scroll !important; +} +.ag-horizontal-left-spacer, +.ag-horizontal-right-spacer { + height: 100%; + min-width: 0; + overflow-x: scroll; +} +.ag-horizontal-left-spacer.ag-scroller-corner, +.ag-horizontal-right-spacer.ag-scroller-corner { + overflow-x: hidden; +} +.ag-ltr .ag-column-moving .ag-cell { + transition: left 0.2s; +} +.ag-rtl .ag-column-moving .ag-cell { + transition: right 0.2s; +} +.ag-ltr .ag-column-moving .ag-header-cell { + transition: left 0.2s; +} +.ag-rtl .ag-column-moving .ag-header-cell { + transition: right 0.2s; +} +.ag-ltr .ag-column-moving .ag-header-group-cell { + transition: left 0.2s, width 0.2s; +} +.ag-rtl .ag-column-moving .ag-header-group-cell { + transition: right 0.2s, width 0.2s; +} +.ag-row-animation .ag-row { + transition: transform 0.4s, top 0.4s; +} +.ag-row-animation .ag-row.ag-after-created { + transition: transform 0.4s, top 0.4s, height 0.4s; +} +.ag-row-no-animation .ag-row { + transition: none; +} +.ag-row-loading { + align-items: center; + display: flex; +} +.ag-row-position-absolute { + position: absolute; +} +.ag-row-position-relative { + position: relative; +} +.ag-full-width-row { + overflow: hidden; + pointer-events: all; +} +.ag-row-inline-editing { + z-index: 1; +} +.ag-row-dragging { + z-index: 2; +} +.ag-stub-cell { + align-items: center; + display: flex; +} +.ag-cell { + display: inline-block; + height: 100%; + position: absolute; + white-space: nowrap; +} +.ag-cell-value { + flex: 1 1 auto; +} +.ag-cell-value, +.ag-group-value { + overflow: hidden; + text-overflow: ellipsis; +} +.ag-cell-wrap-text { + white-space: normal; +} +.ag-sparkline-wrapper { + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.ag-full-width-row .ag-cell-wrapper.ag-row-group { + align-items: center; + height: 100%; +} +.ag-cell .ag-icon { + display: inline-block; + vertical-align: middle; +} +.ag-popup-child { + top: 0; + z-index: 5; +} +.ag-popup-editor { + position: absolute; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-large-text-input { + display: block; +} +.ag-floating-top { + border-bottom: var(--ag-pinned-row-border); + display: flex; + overflow: hidden; + position: relative; + white-space: nowrap; + width: 100%; +} +.ag-pinned-left-floating-top, +.ag-pinned-right-floating-top { + display: inline-block; + min-width: 0; + overflow: hidden; + position: relative; +} +.ag-floating-bottom { + border-top: var(--ag-pinned-row-border); + display: flex; + overflow: hidden; + position: relative; + white-space: nowrap; + width: 100%; +} +.ag-pinned-left-floating-bottom, +.ag-pinned-right-floating-bottom { + display: inline-block; + min-width: 0; + overflow: hidden; + position: relative; +} +.ag-sticky-bottom, +.ag-sticky-top { + background-color: var(--ag-background-color); + display: flex; + position: absolute; + width: 100%; +} +.ag-pinned-left-sticky-top, +.ag-pinned-right-sticky-top { + height: 100%; + overflow: hidden; + position: relative; +} +.ag-sticky-bottom-full-width-container, +.ag-sticky-top-full-width-container { + height: 100%; + overflow: hidden; + width: 100%; +} +.ag-value-slide-out { + opacity: 1; +} +.ag-ltr .ag-value-slide-out { + margin-right: 5px; + transition: opacity 3s, margin-right 3s; +} +.ag-rtl .ag-value-slide-out { + margin-left: 5px; + transition: opacity 3s, margin-left 3s; +} +:is(.ag-ltr, .ag-rtl) .ag-value-slide-out { + transition-timing-function: linear; +} +.ag-value-slide-out-end { + opacity: 0; +} +.ag-ltr .ag-value-slide-out-end { + margin-right: 10px; +} +.ag-rtl .ag-value-slide-out-end { + margin-left: 10px; +} +.ag-opacity-zero { + opacity: 0 !important; +} +.ag-tool-panel-wrapper { + cursor: default; + display: flex; + overflow-x: hidden; + overflow-y: auto; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-select-agg-func-item { + align-items: center; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + height: 100%; + position: relative; +} +.ag-select-agg-func-item > * { + flex: none; +} +.ag-select-agg-func-item { + flex: 1 1 auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-tool-panel-horizontal-resize { + cursor: ew-resize; + height: 100%; + position: absolute; + top: 0; + width: 5px; + z-index: 1; +} +.ag-details-row { + width: 100%; +} +.ag-details-row-fixed-height { + height: 100%; +} +.ag-details-grid { + width: 100%; +} +.ag-details-grid-fixed-height { + height: 100%; +} +.ag-cell-label-container { + align-items: center; + display: flex; + flex-direction: row-reverse; + height: 100%; + justify-content: space-between; + width: 100%; +} +.ag-right-aligned-header .ag-cell-label-container { + flex-direction: row; +} +.ag-right-aligned-header .ag-header-cell-text { + text-align: end; +} +.ag-column-group-icons { + display: block; +} +.ag-column-group-icons > * { + cursor: pointer; +} +.ag-pill-select { + display: flex; + flex-direction: column; +} +.ag-pill-select .ag-column-drop { + border-bottom: 0; + flex: unset; + min-height: unset; +} +.ag-pill-select .ag-column-drop-list { + padding: 0; +} +.ag-pill-select .ag-select { + padding-top: var(--ag-grid-size); +} +.ag-pill-select .ag-picker-field-wrapper { + background-color: transparent; + border: 0; +} +.ag-pill-select .ag-picker-field-display { + cursor: pointer; +} +.ag-ltr { + direction: ltr; +} +.ag-ltr .ag-body, +.ag-ltr .ag-body-horizontal-scroll, +.ag-ltr .ag-body-viewport, +.ag-ltr .ag-floating-bottom, +.ag-ltr .ag-floating-top, +.ag-ltr .ag-header, +.ag-ltr .ag-sticky-bottom, +.ag-ltr .ag-sticky-top { + flex-direction: row; +} +.ag-rtl { + direction: rtl; +} +.ag-rtl .ag-body, +.ag-rtl .ag-body-horizontal-scroll, +.ag-rtl .ag-body-viewport, +.ag-rtl .ag-floating-bottom, +.ag-rtl .ag-floating-top, +.ag-rtl .ag-header, +.ag-rtl .ag-sticky-bottom, +.ag-rtl .ag-sticky-top { + flex-direction: row-reverse; +} +.ag-rtl .ag-icon-contracted, +.ag-rtl .ag-icon-expanded, +.ag-rtl .ag-icon-tree-closed { + display: block; + transform: rotate(180deg); +} +.ag-group { + position: relative; + width: 100%; +} +.ag-group-title-bar { + align-items: center; + display: flex; + padding: var(--ag-grid-size); +} +.ag-group-title { + display: inline; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-group-title-bar .ag-group-title { + cursor: default; +} +.ag-group-toolbar { + align-items: center; + display: flex; + padding: var(--ag-grid-size); +} +.ag-group-container { + display: flex; +} +.ag-disabled .ag-group-container { + pointer-events: none; +} +.ag-disabled-group-container, +.ag-disabled-group-title-bar { + opacity: 0.5; +} +.ag-group-container-horizontal { + flex-direction: row; + flex-wrap: wrap; +} +.ag-group-container-vertical { + flex-direction: column; +} +.ag-group-title-bar-icon { + cursor: pointer; + flex: none; +} +.ag-ltr .ag-group-title-bar-icon { + margin-right: var(--ag-grid-size); +} +.ag-rtl .ag-group-title-bar-icon { + margin-left: var(--ag-grid-size); +} +.ag-group-item-alignment-stretch .ag-group-item { + align-items: stretch; +} +.ag-group-item-alignment-start .ag-group-item { + align-items: flex-start; +} +.ag-group-item-alignment-end .ag-group-item { + align-items: flex-end; +} +.ag-popup-child:not(.ag-tooltip-custom) { + box-shadow: var(--ag-popup-shadow); +} +.ag-rtl { + text-align: right; +} +.ag-row > .ag-cell-wrapper.ag-row-group { + border: 1px solid blue; +} +.ag-ltr .ag-row > .ag-cell-wrapper.ag-row-group { + padding-left: calc( + var(--ag-cell-horizontal-padding) + var(--ag-row-group-indent-size) * + var(--ag-indentation-level) + ); +} +.ag-rtl .ag-row > .ag-cell-wrapper.ag-row-group { + padding-right: calc( + var(--ag-cell-horizontal-padding) + var(--ag-row-group-indent-size) * + var(--ag-indentation-level) + ); +} +.ag-ltr .ag-cell-wrapper.ag-row-group { + padding-left: calc(var(--ag-indentation-level) * var(--ag-row-group-indent-size)); +} +.ag-rtl .ag-cell-wrapper.ag-row-group { + padding-right: calc(var(--ag-indentation-level) * var(--ag-row-group-indent-size)); +} +.ag-ltr .ag-pivot-leaf-group { + margin-left: var(--ag-row-group-indent-size); +} +.ag-rtl .ag-pivot-leaf-group { + margin-right: var(--ag-row-group-indent-size); +} +.ag-ltr .ag-row-group-leaf-indent { + margin-left: var(--ag-row-group-indent-size); +} +.ag-rtl .ag-row-group-leaf-indent { + margin-right: var(--ag-row-group-indent-size); +} +.ag-value-change-delta { + padding: 0 2px; +} +.ag-value-change-delta-up { + color: var(--ag-value-change-delta-up-color); +} +.ag-value-change-delta-down { + color: var(--ag-value-change-delta-down-color); +} +.ag-value-change-value { + background-color: transparent; + border-radius: 1px; + padding-left: 1px; + padding-right: 1px; + transition: background-color 1s; +} +.ag-value-change-value-highlight { + background-color: var(--ag-value-change-value-highlight-background-color); + transition: background-color 0.1s; +} +.ag-cell-data-changed { + background-color: var(--ag-value-change-value-highlight-background-color) !important; +} +.ag-cell-data-changed-animation { + background-color: transparent; +} +.ag-cell-highlight { + background-color: var(--ag-range-selection-highlight-color) !important; +} +.ag-row { + background-color: var(--ag-background-color); + border-bottom: var(--ag-row-border); + color: var(--ag-data-color); + height: var(--ag-row-height); + white-space: nowrap; + width: 100%; + --ag-internal-content-line-height: min( + calc(var(--ag-row-height) - 1px), + var(--ag-line-height, 1000px) + ); +} +.ag-sticky-bottom .ag-row { + border-bottom: none; + border-top: var(--ag-row-border); +} +.ag-group-contracted, +.ag-group-expanded { + cursor: pointer; +} +.ag-cell, +.ag-full-width-row .ag-cell-wrapper.ag-row-group { + border: 1px solid transparent; + line-height: var(--ag-internal-content-line-height); +} +.ag-ltr .ag-cell { + border-right: var(--ag-column-border); +} +.ag-rtl .ag-cell { + border-left: var(--ag-column-border); +} +.ag-cell-wrapper { + align-items: center; + display: flex; +} +.ag-cell-wrapper.ag-row-group { + align-items: flex-start; +} +.ag-cell-wrapper > :not(.ag-cell-value):not(.ag-group-value) { + align-items: center; + display: flex; + height: var(--ag-internal-content-line-height); +} +.ag-ltr .ag-group-contracted, +.ag-ltr .ag-group-expanded, +.ag-ltr .ag-row-drag, +.ag-ltr .ag-selection-checkbox { + margin-right: var(--ag-cell-widget-spacing); +} +.ag-rtl .ag-group-contracted, +.ag-rtl .ag-group-expanded, +.ag-rtl .ag-row-drag, +.ag-rtl .ag-selection-checkbox { + margin-left: var(--ag-cell-widget-spacing); +} +.ag-ltr .ag-group-child-count { + margin-left: 3px; +} +.ag-rtl .ag-group-child-count { + margin-right: 3px; +} +.ag-row-highlight-above:after, +.ag-row-highlight-below:after { + background-color: var(--ag-range-selection-border-color); + content: ''; + height: 1px; + position: absolute; + width: calc(100% - 1px); +} +.ag-ltr .ag-row-highlight-above:after, +.ag-ltr .ag-row-highlight-below:after { + left: 1px; +} +.ag-rtl .ag-row-highlight-above:after, +.ag-rtl .ag-row-highlight-below:after { + right: 1px; +} +.ag-row-highlight-above:after { + top: -1px; +} +.ag-row-highlight-above.ag-row-first:after { + top: 0; +} +.ag-row-highlight-below:after { + bottom: 0; +} +.ag-row-odd { + background-color: var(--ag-odd-row-background-color); +} +.ag-row-selected:before { + background-color: var(--ag-selected-row-background-color); + content: ''; + display: block; + inset: 0; + pointer-events: none; + position: absolute; +} +.ag-row-hover.ag-full-width-row.ag-row-group:before, +.ag-row-hover:not(.ag-full-width-row):before { + background-color: var(--ag-row-hover-color); + content: ''; + display: block; + inset: 0; + pointer-events: none; + position: absolute; +} +.ag-row-hover.ag-row-selected:before { + background-color: var(--ag-row-hover-color); + background-image: linear-gradient( + var(--ag-selected-row-background-color), + var(--ag-selected-row-background-color) + ); +} +.ag-row-hover.ag-full-width-row.ag-row-group > * { + position: relative; +} +.ag-column-hover { + background-color: var(--ag-column-hover-color); +} +.ag-ltr .ag-right-aligned-cell { + text-align: right; +} +.ag-rtl .ag-right-aligned-cell { + text-align: left; +} +.ag-right-aligned-cell .ag-cell-value, +.ag-right-aligned-cell .ag-group-value { + margin-left: auto; +} +.ag-cell, +.ag-full-width-row .ag-cell-wrapper.ag-row-group { + -webkit-font-smoothing: subpixel-antialiased; +} +.ag-cell, +.ag-full-width-row .ag-cell-wrapper.ag-row-group, +.ag-row > .ag-cell-wrapper { + padding-left: calc(var(--ag-cell-horizontal-padding) - 1px); + padding-right: calc(var(--ag-cell-horizontal-padding) - 1px); +} +.ag-row-dragging { + cursor: move; + opacity: 0.5; +} +.ag-details-row { + background-color: var(--ag-background-color); + padding: calc(var(--ag-grid-size) * 3.5); +} +.ag-layout-auto-height .ag-center-cols-container, +.ag-layout-auto-height .ag-center-cols-viewport, +.ag-layout-print .ag-center-cols-container, +.ag-layout-print .ag-center-cols-viewport { + min-height: 150px; +} +.ag-overlay-loading-wrapper { + background-color: var(--ag-modal-overlay-background-color); +} +.ag-overlay-no-rows-wrapper.ag-layout-auto-height { + padding-top: 60px; +} +.ag-skeleton-container { + align-content: center; + height: 100%; + width: 100%; +} +.ag-skeleton-effect { + animation: ag-skeleton-loading 1.5s ease-in-out 0.5s infinite; + background-color: var(--ag-row-loading-skeleton-effect-color); + border-radius: 0.25rem; + height: 1em; + width: 100%; +} +@keyframes ag-skeleton-loading { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + to { + opacity: 1; + } +} +.ag-loading { + align-items: center; + display: flex; + height: 100%; +} +.ag-ltr .ag-loading { + padding-left: var(--ag-cell-horizontal-padding); +} +.ag-rtl .ag-loading { + padding-right: var(--ag-cell-horizontal-padding); +} +.ag-ltr .ag-loading-icon { + padding-right: var(--ag-cell-widget-spacing); +} +.ag-rtl .ag-loading-icon { + padding-left: var(--ag-cell-widget-spacing); +} +.ag-icon-loading { + animation-duration: 1s; + animation-iteration-count: infinite; + animation-name: spin; + animation-timing-function: linear; +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + to { + transform: rotate(1turn); + } +} +.ag-details-row { + padding: calc(var(--ag-grid-size) * 3.75); +} +.ag-body-viewport:not(.ag-has-focus) .ag-cell-range-single-cell:not(.ag-cell-inline-editing), +.ag-cell-range-selected:not(.ag-cell-focus) { + background-color: var(--ag-range-selection-background-color); +} +.ag-cell-range-chart:is( + .ag-cell-range-selected:not(.ag-cell-focus), + .ag-body-viewport:not(.ag-has-focus) .ag-cell-range-single-cell:not(.ag-cell-inline-editing) + ) { + background-color: var(--ag-range-selection-chart-background-color) !important; +} +.ag-cell-range-chart.ag-cell-range-chart-category:is( + .ag-cell-range-selected:not(.ag-cell-focus), + .ag-body-viewport:not(.ag-has-focus) .ag-cell-range-single-cell:not(.ag-cell-inline-editing) + ) { + background-color: var(--ag-range-selection-chart-category-background-color) !important; +} +.ag-cell-range-selected-1:not(.ag-cell-focus), +.ag-root:not(.ag-context-menu-open) + .ag-body-viewport:not(.ag-has-focus) + .ag-cell-range-selected-1:not(.ag-cell-inline-editing) { + background-color: var(--ag-range-selection-background-color); +} +.ag-cell-range-selected-2:not(.ag-cell-focus) { + background-image: linear-gradient( + var(--ag-range-selection-background-color), + var(--ag-range-selection-background-color) + ); +} +.ag-cell-range-selected-3:not(.ag-cell-focus) { + background-image: linear-gradient( + var(--ag-range-selection-background-color), + var(--ag-range-selection-background-color) + ), + linear-gradient( + var(--ag-range-selection-background-color), + var(--ag-range-selection-background-color) + ); +} +.ag-cell-range-selected-4:not(.ag-cell-focus) { + background-image: linear-gradient( + var(--ag-range-selection-background-color), + var(--ag-range-selection-background-color) + ), + linear-gradient( + var(--ag-range-selection-background-color), + var(--ag-range-selection-background-color) + ), + linear-gradient( + var(--ag-range-selection-background-color), + var(--ag-range-selection-background-color) + ); +} +.ag-cell.ag-cell-range-selected.ag-cell-range-top:not(.ag-cell-range-single-cell) { + border-top-color: var(--ag-range-selection-border-color); + border-top-style: var(--ag-range-selection-border-style); +} +.ag-cell.ag-cell-range-selected.ag-cell-range-right:not(.ag-cell-range-single-cell) { + border-right-color: var(--ag-range-selection-border-color); + border-right-style: var(--ag-range-selection-border-style); +} +.ag-cell.ag-cell-range-selected.ag-cell-range-bottom:not(.ag-cell-range-single-cell) { + border-bottom-color: var(--ag-range-selection-border-color); + border-bottom-style: var(--ag-range-selection-border-style); +} +.ag-cell.ag-cell-range-selected.ag-cell-range-left:not(.ag-cell-range-single-cell) { + border-left-color: var(--ag-range-selection-border-color); + border-left-style: var(--ag-range-selection-border-style); +} +.ag-ltr .ag-cell-focus:not(.ag-cell-range-selected):focus-within, +.ag-ltr .ag-cell-range-single-cell, +.ag-ltr .ag-cell-range-single-cell.ag-cell-range-handle, +.ag-ltr .ag-context-menu-open .ag-cell-focus:not(.ag-cell-range-selected), +.ag-ltr .ag-full-width-row.ag-row-focus:focus .ag-cell-wrapper.ag-row-group, +.ag-rtl .ag-cell-focus:not(.ag-cell-range-selected):focus-within, +.ag-rtl .ag-cell-range-single-cell, +.ag-rtl .ag-cell-range-single-cell.ag-cell-range-handle, +.ag-rtl .ag-context-menu-open .ag-cell-focus:not(.ag-cell-range-selected), +.ag-rtl .ag-full-width-row.ag-row-focus:focus .ag-cell-wrapper.ag-row-group { + border: 1px solid; + border-color: var(--ag-range-selection-border-color); + border-style: var(--ag-range-selection-border-style); + outline: initial; +} +.ag-cell.ag-selection-fill-top, +.ag-cell.ag-selection-fill-top.ag-cell-range-selected { + border-top: 1px dashed; + border-top-color: var(--ag-range-selection-border-color); +} +.ag-ltr .ag-cell.ag-selection-fill-right, +.ag-ltr .ag-cell.ag-selection-fill-right.ag-cell-range-selected { + border-right: 1px dashed var(--ag-range-selection-border-color) !important; +} +.ag-rtl .ag-cell.ag-selection-fill-right, +.ag-rtl .ag-cell.ag-selection-fill-right.ag-cell-range-selected { + border-left: 1px dashed var(--ag-range-selection-border-color) !important; +} +.ag-cell.ag-selection-fill-bottom, +.ag-cell.ag-selection-fill-bottom.ag-cell-range-selected { + border-bottom: 1px dashed; + border-bottom-color: var(--ag-range-selection-border-color); +} +.ag-ltr .ag-cell.ag-selection-fill-left, +.ag-ltr .ag-cell.ag-selection-fill-left.ag-cell-range-selected { + border-left: 1px dashed var(--ag-range-selection-border-color) !important; +} +.ag-rtl .ag-cell.ag-selection-fill-left, +.ag-rtl .ag-cell.ag-selection-fill-left.ag-cell-range-selected { + border-right: 1px dashed var(--ag-range-selection-border-color) !important; +} +.ag-fill-handle, +.ag-range-handle { + background-color: var(--ag-range-selection-border-color); + bottom: -1px; + height: 6px; + position: absolute; + width: 6px; +} +.ag-ltr .ag-fill-handle, +.ag-ltr .ag-range-handle { + right: -1px; +} +.ag-rtl .ag-fill-handle, +.ag-rtl .ag-range-handle { + left: -1px; +} +.ag-fill-handle { + cursor: cell; +} +.ag-ltr .ag-range-handle { + cursor: nwse-resize; +} +.ag-rtl .ag-range-handle { + cursor: nesw-resize; +} +.ag-input-wrapper, +.ag-picker-field-wrapper { + align-items: center; + display: flex; + flex: 1 1 auto; + line-height: normal; + position: relative; +} +.ag-label-align-right .ag-label { + order: 1; +} +.ag-label-align-right > * { + flex: none; +} +.ag-label-align-top { + align-items: flex-start; + flex-direction: column; +} +.ag-label-align-top > * { + align-self: stretch; +} +.ag-label-ellipsis { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-input-field { + align-items: center; + display: flex; + flex-direction: row; +} +.ag-input-field-input { + flex: 1 1 auto; +} +.ag-floating-filter-input .ag-input-field-input[type='date'] { + width: 1px; +} +.ag-input-field-input { + min-width: 0; + width: 100%; +} +.ag-label { + white-space: nowrap; +} +.ag-ltr .ag-label { + margin-right: var(--ag-grid-size); +} +.ag-rtl .ag-label { + margin-left: var(--ag-grid-size); +} +.ag-label-align-top .ag-label { + margin-bottom: calc(var(--ag-grid-size) * 0.5); +} +.ag-ltr .ag-label-align-right .ag-label { + margin-left: var(--ag-grid-size); +} +.ag-rtl .ag-label-align-right .ag-label { + margin-right: var(--ag-grid-size); +} +.ag-column-select-header-filter-wrapper .ag-input-wrapper:before, +.ag-filter-filter .ag-input-wrapper:before, +.ag-filter-toolpanel-search .ag-input-wrapper:before, +.ag-mini-filter .ag-input-wrapper:before { + background-color: currentColor; + content: ''; + display: block; + height: 12px; + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMS41Ij48cGF0aCBkPSJNNS4zIDlhMy43IDMuNyAwIDEgMCAwLTcuNSAzLjcgMy43IDAgMCAwIDAgNy41Wk0xMC41IDEwLjUgOC4zIDguMiIvPjwvc3ZnPg=='); + mask-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMS41Ij48cGF0aCBkPSJNNS4zIDlhMy43IDMuNyAwIDEgMCAwLTcuNSAzLjcgMy43IDAgMCAwIDAgNy41Wk0xMC41IDEwLjUgOC4zIDguMiIvPjwvc3ZnPg=='); + -webkit-mask-position: center; + mask-position: center; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + opacity: 50%; + position: absolute; + width: 12px; +} +.ag-ltr .ag-column-select-header-filter-wrapper .ag-input-wrapper:before, +.ag-ltr .ag-filter-filter .ag-input-wrapper:before, +.ag-ltr .ag-filter-toolpanel-search .ag-input-wrapper:before, +.ag-ltr .ag-mini-filter .ag-input-wrapper:before { + margin-left: var(--ag-grid-size); +} +.ag-rtl .ag-column-select-header-filter-wrapper .ag-input-wrapper:before, +.ag-rtl .ag-filter-filter .ag-input-wrapper:before, +.ag-rtl .ag-filter-toolpanel-search .ag-input-wrapper:before, +.ag-rtl .ag-mini-filter .ag-input-wrapper:before { + margin-right: var(--ag-grid-size); +} +.ag-ltr .ag-column-select-header-filter-wrapper input.ag-number-field-input, +.ag-ltr .ag-column-select-header-filter-wrapper input.ag-text-field-input, +.ag-ltr .ag-filter-filter input.ag-number-field-input, +.ag-ltr .ag-filter-filter input.ag-text-field-input, +.ag-ltr .ag-filter-toolpanel-search input.ag-number-field-input, +.ag-ltr .ag-filter-toolpanel-search input.ag-text-field-input, +.ag-ltr .ag-mini-filter input.ag-number-field-input, +.ag-ltr .ag-mini-filter input.ag-text-field-input { + padding-left: 26px; +} +.ag-rtl .ag-column-select-header-filter-wrapper input.ag-number-field-input, +.ag-rtl .ag-column-select-header-filter-wrapper input.ag-text-field-input, +.ag-rtl .ag-filter-filter input.ag-number-field-input, +.ag-rtl .ag-filter-filter input.ag-text-field-input, +.ag-rtl .ag-filter-toolpanel-search input.ag-number-field-input, +.ag-rtl .ag-filter-toolpanel-search input.ag-text-field-input, +.ag-rtl .ag-mini-filter input.ag-number-field-input, +.ag-rtl .ag-mini-filter input.ag-text-field-input { + padding-right: 26px; +} +.ag-advanced-filter-header { + align-items: center; + background-color: var(--ag-header-background-color); + border-bottom: var(--ag-header-border); + display: flex; + padding-left: var(--ag-cell-horizontal-padding); + padding-right: var(--ag-cell-horizontal-padding); + position: relative; +} +.ag-advanced-filter { + align-items: center; + display: flex; + width: 100%; +} +.ag-advanced-filter-apply-button, +.ag-advanced-filter-builder-button { + line-height: normal; + white-space: nowrap; +} +.ag-ltr .ag-advanced-filter-apply-button, +.ag-ltr .ag-advanced-filter-builder-button { + margin-left: calc(var(--ag-grid-size) * 2); +} +.ag-rtl .ag-advanced-filter-apply-button, +.ag-rtl .ag-advanced-filter-builder-button { + margin-right: calc(var(--ag-grid-size) * 2); +} +.ag-advanced-filter-builder-button { + align-items: center; + background-color: unset; + border: 0; + display: flex; + font-size: var(--ag-font-size); + font-weight: 600; + padding: var(--ag-grid-size); +} +.ag-advanced-filter-builder-button:hover:not(:disabled) { + background-color: var(--ag-row-hover-color); +} +.ag-advanced-filter-builder-button:not(:disabled) { + cursor: pointer; +} +.ag-ltr .ag-advanced-filter-builder-button-label { + margin-left: var(--ag-grid-size); +} +.ag-rtl .ag-advanced-filter-builder-button-label { + margin-right: var(--ag-grid-size); +} +.ag-advanced-filter-builder { + background-color: var(--ag-chrome-background-color); + display: flex; + flex-direction: column; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + width: 100%; +} +.ag-advanced-filter-builder-list { + flex: 1; + overflow: auto; +} +.ag-advanced-filter-builder-button-panel { + border-top: var(--ag-advanced-filter-builder-button-bar-border); + display: flex; + justify-content: flex-end; + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-ltr + .ag-advanced-filter-builder + .ag-advanced-filter-builder-button-panel + .ag-advanced-filter-builder-apply-button, +.ag-ltr + .ag-advanced-filter-builder + .ag-advanced-filter-builder-button-panel + .ag-advanced-filter-builder-cancel-button { + margin-left: calc(var(--ag-grid-size) * 2); +} +.ag-rtl + .ag-advanced-filter-builder + .ag-advanced-filter-builder-button-panel + .ag-advanced-filter-builder-apply-button, +.ag-rtl + .ag-advanced-filter-builder + .ag-advanced-filter-builder-button-panel + .ag-advanced-filter-builder-cancel-button { + margin-right: calc(var(--ag-grid-size) * 2); +} +.ag-advanced-filter-builder-item-wrapper { + align-items: center; + display: flex; + flex: 1 1 auto; + justify-content: space-between; + overflow: hidden; +} +.ag-ltr .ag-advanced-filter-builder-item-wrapper { + padding-left: calc(var(--ag-icon-size) / 2); + padding-right: var(--ag-icon-size); +} +.ag-rtl .ag-advanced-filter-builder-item-wrapper { + padding-left: var(--ag-icon-size); + padding-right: calc(var(--ag-icon-size) / 2); +} +.ag-advanced-filter-builder-item-tree-lines > * { + width: var(--ag-advanced-filter-builder-indent-size); +} +.ag-advanced-filter-builder-item-tree-lines .ag-advanced-filter-builder-item-tree-line-root { + width: var(--ag-icon-size); +} +.ag-advanced-filter-builder-item-tree-lines .ag-advanced-filter-builder-item-tree-line-root:before { + height: 50%; + top: 50%; +} +.ag-advanced-filter-builder-item-tree-line-horizontal, +.ag-advanced-filter-builder-item-tree-line-vertical, +.ag-advanced-filter-builder-item-tree-line-vertical-bottom, +.ag-advanced-filter-builder-item-tree-line-vertical-top { + align-items: center; + display: flex; + height: 100%; + position: relative; +} +.ag-advanced-filter-builder-item-tree-line-horizontal:after, +.ag-advanced-filter-builder-item-tree-line-horizontal:before, +.ag-advanced-filter-builder-item-tree-line-vertical-bottom:after, +.ag-advanced-filter-builder-item-tree-line-vertical-bottom:before, +.ag-advanced-filter-builder-item-tree-line-vertical-top:after, +.ag-advanced-filter-builder-item-tree-line-vertical-top:before, +.ag-advanced-filter-builder-item-tree-line-vertical:after, +.ag-advanced-filter-builder-item-tree-line-vertical:before { + content: ''; + height: 100%; + position: absolute; +} +.ag-advanced-filter-builder-item-tree-line-horizontal:after { + border-bottom: 1px solid var(--ag-border-color); + height: 50%; + top: 0; + width: calc(var(--ag-advanced-filter-builder-indent-size) - var(--ag-icon-size)); +} +.ag-ltr .ag-advanced-filter-builder-item-tree-line-horizontal:after { + left: calc(var(--ag-icon-size) / 2); +} +.ag-rtl .ag-advanced-filter-builder-item-tree-line-horizontal:after { + right: calc(var(--ag-icon-size) / 2); +} +.ag-advanced-filter-builder-item-tree-line-vertical:before { + top: 0; + width: calc(var(--ag-advanced-filter-builder-indent-size) - var(--ag-icon-size) / 2); +} +.ag-ltr .ag-advanced-filter-builder-item-tree-line-vertical:before { + border-left: 1px solid var(--ag-border-color); + left: calc(var(--ag-icon-size) / 2); +} +.ag-rtl .ag-advanced-filter-builder-item-tree-line-vertical:before { + border-right: 1px solid var(--ag-border-color); + right: calc(var(--ag-icon-size) / 2); +} +.ag-advanced-filter-builder-item-tree-line-vertical-top:before { + height: 50%; + top: 0; + width: calc(var(--ag-advanced-filter-builder-indent-size) - var(--ag-icon-size) / 2); +} +.ag-ltr .ag-advanced-filter-builder-item-tree-line-vertical-top:before { + border-left: 1px solid var(--ag-border-color); + left: calc(var(--ag-icon-size) / 2); +} +.ag-rtl .ag-advanced-filter-builder-item-tree-line-vertical-top:before { + border-right: 1px solid var(--ag-border-color); + right: calc(var(--ag-icon-size) / 2); +} +.ag-advanced-filter-builder-item-tree-line-vertical-bottom:before { + height: calc(50% - var(--ag-icon-size) * 1.5 / 2); + top: calc(50% + var(--ag-icon-size) * 1.5 / 2); + width: calc(var(--ag-icon-size) / 2); +} +.ag-ltr .ag-advanced-filter-builder-item-tree-line-vertical-bottom:before { + border-left: 1px solid var(--ag-border-color); + left: calc(var(--ag-icon-size) / 2); +} +.ag-rtl .ag-advanced-filter-builder-item-tree-line-vertical-bottom:before { + border-right: 1px solid var(--ag-border-color); + right: calc(var(--ag-icon-size) / 2); +} +.ag-advanced-filter-builder-item-condition { + padding-bottom: var(--ag-grid-size); + padding-top: var(--ag-grid-size); +} +.ag-advanced-filter-builder-item, +.ag-advanced-filter-builder-item-buttons, +.ag-advanced-filter-builder-item-condition, +.ag-advanced-filter-builder-item-tree-lines, +.ag-advanced-filter-builder-pill, +.ag-advanced-filter-builder-pill-wrapper { + align-items: center; + display: flex; + height: 100%; +} +.ag-advanced-filter-builder-pill-wrapper { + margin: 0 var(--ag-grid-size); +} +.ag-advanced-filter-builder-pill { + border-radius: var(--ag-border-radius); + min-height: calc(100% - var(--ag-grid-size) * 3); + min-width: calc(var(--ag-grid-size) * 2); + padding: var(--ag-grid-size) calc(var(--ag-grid-size) * 2); + position: relative; +} +.ag-ltr .ag-advanced-filter-builder-pill .ag-picker-field-display { + margin-right: var(--ag-grid-size); +} +.ag-rtl .ag-advanced-filter-builder-pill .ag-picker-field-display { + margin-left: var(--ag-grid-size); +} +.ag-advanced-filter-builder-pill .ag-advanced-filter-builder-value-number { + font-family: monospace; + font-weight: 700; +} +.ag-advanced-filter-builder-pill .ag-advanced-filter-builder-value-empty { + color: var(--ag-subtle-text-color); +} +.ag-advanced-filter-builder-item-button:focus-visible, +.ag-advanced-filter-builder-pill:focus-visible { + shadow: var(--ag-focus-shadow); +} +.ag-advanced-filter-builder-pill-display { + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-advanced-filter-builder-join-pill { + background-color: var(--ag-advanced-filter-builder-join-pill-color); + cursor: pointer; +} +.ag-advanced-filter-builder-column-pill { + background-color: var(--ag-advanced-filter-builder-column-pill-color); + cursor: pointer; +} +.ag-advanced-filter-builder-option-pill { + background-color: var(--ag-advanced-filter-builder-option-pill-color); + cursor: pointer; +} +.ag-advanced-filter-builder-value-pill { + background-color: var(--ag-advanced-filter-builder-value-pill-color); + cursor: text; + max-width: 140px; +} +.ag-advanced-filter-builder-value-pill .ag-advanced-filter-builder-pill-display { + display: block; +} +.ag-advanced-filter-builder-item-buttons > * { + margin: 0 calc(var(--ag-grid-size) * 0.5); +} +.ag-advanced-filter-builder-item-button { + color: var(--ag-subtle-text-color); + cursor: pointer; + position: relative; +} +.ag-advanced-filter-builder-item-button-disabled { + cursor: default; + opacity: 0.5; +} +.ag-advanced-filter-builder-virtual-list-container { + top: var(--ag-grid-size); +} +.ag-advanced-filter-builder-virtual-list-item { + cursor: default; + display: flex; + height: var(--ag-list-item-height); +} +.ag-advanced-filter-builder-virtual-list-item:hover { + background-color: var(--ag-row-hover-color); +} +.ag-advanced-filter-builder-virtual-list-item:hover .ag-advanced-filter-builder-item-button { + opacity: 100%; +} +.ag-advanced-filter-builder-validation .ag-advanced-filter-builder-invalid, +.ag-advanced-filter-builder-virtual-list-item-highlight + .ag-advanced-filter-builder-item-button:focus-visible { + opacity: 100%; +} +.ag-advanced-filter-builder-invalid { + color: var(--ag-invalid-color); + cursor: default; + margin: 0 var(--ag-grid-size); +} +.ag-cell-inline-editing { + border-radius: var(--ag-border-radius); + padding: 0; + z-index: 1; +} +.ag-cell-inline-editing .ag-cell-edit-wrapper, +.ag-cell-inline-editing .ag-cell-editor, +.ag-cell-inline-editing .ag-cell-editor .ag-wrapper, +.ag-cell-inline-editing .ag-cell-editor input, +.ag-cell-inline-editing .ag-cell-wrapper { + height: 100%; + line-height: normal; + width: 100%; +} +.ag-autocomplete-list-popup, +.ag-popup-editor .ag-large-text { + background-color: var(--ag-background-color); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-dropdown-shadow); + padding: 0; +} +.ag-large-text-input { + height: auto; + padding: var(--ag-cell-horizontal-padding); +} +.ag-rtl .ag-large-text-input textarea { + resize: none; +} +.ag-checkbox-edit { + padding-left: var(--ag-cell-horizontal-padding); + padding-right: var(--ag-cell-horizontal-padding); +} +.ag-chart { + height: 100%; + width: 100%; +} +.ag-chart, +.ag-chart-components-wrapper { + display: flex; + overflow: hidden; + position: relative; +} +.ag-chart-components-wrapper { + flex: 1 1 auto; +} +.ag-chart-title-edit { + display: none; + left: 0; + position: absolute; + text-align: center; + top: 0; +} +.ag-chart-title-edit.currently-editing { + display: inline-block; +} +.ag-chart-canvas-wrapper { + flex: 1 1 auto; + overflow: hidden; + position: relative; +} +.ag-charts-canvas { + display: block; +} +.ag-chart-menu { + display: flex; + flex-direction: column; + position: absolute; + top: 16px; +} +.ag-ltr .ag-chart-menu { + right: 20px; +} +.ag-rtl .ag-chart-menu { + left: 20px; +} +.ag-chart-docked-container { + min-width: 0; + position: relative; + transition: min-width 0.4s; + width: 0; +} +.ag-chart-menu-hidden ~ .ag-chart-docked-container { + max-width: 0; + overflow: hidden; +} +.ag-chart-tabbed-menu { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + width: 100%; +} +.ag-chart-tabbed-menu-header { + cursor: default; + flex: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-chart-tabbed-menu-body { + align-items: stretch; + display: flex; + flex: 1 1 auto; + overflow: hidden; +} +.ag-chart-tab { + overflow: hidden; + overflow-y: auto; + width: 100%; +} +.ag-chart-settings { + overflow-x: hidden; +} +.ag-chart-settings-wrapper { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + position: relative; + width: 100%; +} +.ag-chart-settings-nav-bar { + align-items: center; + border-top: 1px solid var(--ag-border-color); + display: flex; + height: 30px; + padding: 0 10px; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + width: 100%; +} +.ag-chart-settings-card-selector { + align-items: center; + display: flex; + flex: 1 1 auto; + height: 100%; + justify-content: space-around; + padding: 0 10px; +} +.ag-chart-settings-card-item { + background-color: var(--ag-foreground-color); + border-radius: 4px; + cursor: pointer; + height: 10px; + height: 8px; + position: relative; + width: 10px; + width: 8px; +} +.ag-chart-settings-card-item.ag-not-selected { + opacity: 0.2; +} +.ag-chart-settings-card-item:before { + background-color: transparent; + content: ' '; + display: block; + height: 20px; + left: 50%; + margin-left: -10px; + margin-top: -10px; + position: absolute; + top: 50%; + width: 20px; +} +.ag-chart-settings-card-item.ag-selected { + background-color: var(--ag-accent-color); +} +.ag-chart-settings-next, +.ag-chart-settings-prev { + flex: none; + position: relative; +} +.ag-chart-settings-next-button, +.ag-chart-settings-prev-button { + cursor: pointer; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; +} +.ag-chart-settings-mini-charts-container { + flex: 1 1 auto; + overflow-x: hidden; + overflow-y: auto; + position: relative; +} +.ag-chart-settings-mini-wrapper { + display: flex; + flex-direction: column; + left: 0; + min-height: 100%; + overflow: hidden; + position: absolute; + top: 0; + width: 100%; +} +.ag-chart-settings-mini-wrapper.ag-animating { + transition: left 0.3s; + transition-timing-function: ease-in-out; +} +.ag-chart-mini-thumbnail { + cursor: pointer; +} +.ag-chart-mini-thumbnail-canvas { + display: block; +} +.ag-chart-advanced-settings-wrapper, +.ag-chart-data-wrapper, +.ag-chart-format-wrapper { + display: flex; + flex-direction: column; + padding-bottom: 16px; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-chart-advanced-settings-wrapper, +.ag-chart-data-wrapper { + height: 100%; + overflow-y: auto; +} +.ag-chart-advanced-settings { + background-color: var(--ag-chrome-background-color); +} +.ag-chart-advanced-settings, +.ag-chart-advanced-settings-wrapper { + width: 100%; +} +.ag-chart-advanced-settings-wrapper { + padding-bottom: 0; +} +.ag-chart-advanced-settings-section, +.ag-chart-data-section, +.ag-chart-format-section { + display: flex; + margin: 0; +} +.ag-chart-advanced-settings-section { + border-bottom: 1px solid var(--ag-border-color); + padding-bottom: calc(var(--ag-grid-size) * 2); + padding-top: calc(var(--ag-grid-size) * 2); +} +.ag-chart-empty-text { + align-items: center; + background-color: var(--ag-background-color); + display: flex; + height: 100%; + justify-content: center; + top: 0; + width: 100%; +} +.ag-chart .ag-chart-menu { + display: none; +} +.ag-chart-menu-hidden:hover .ag-chart-menu { + display: block; +} +.ag-chart .ag-chart-menu-wrapper .ag-chart-menu, +.ag-chart .ag-chart-tool-panel-button-enable .ag-chart-menu { + display: flex; + flex-direction: row; + gap: 20px; + top: 8px; + width: auto; +} +.ag-ltr .ag-chart .ag-chart-menu-wrapper .ag-chart-menu, +.ag-ltr .ag-chart .ag-chart-tool-panel-button-enable .ag-chart-menu { + justify-content: right; + right: calc(var(--ag-cell-horizontal-padding) + var(--ag-grid-size) - 4px); +} +.ag-rtl .ag-chart .ag-chart-menu-wrapper .ag-chart-menu, +.ag-rtl .ag-chart .ag-chart-tool-panel-button-enable .ag-chart-menu { + justify-content: left; + left: calc(var(--ag-cell-horizontal-padding) + var(--ag-grid-size) - 4px); +} +.ag-chart-menu-close { + display: none; +} +.ag-chart-tool-panel-button-enable .ag-chart-menu-close { + background-color: var(--ag-background-color); + border-bottom: var(--ag-chart-menu-button-border); + border-top: var(--ag-chart-menu-button-border); + cursor: pointer; + display: block; + position: absolute; + top: 50%; + transition: transform 0.33s ease-in-out; +} +.ag-ltr .ag-chart-tool-panel-button-enable .ag-chart-menu-close { + border-left: var(--ag-chart-menu-button-border); + padding: 14px 5px 14px 2px; + right: 0; +} +.ag-rtl .ag-chart-tool-panel-button-enable .ag-chart-menu-close { + border-right: var(--ag-chart-menu-button-border); + left: 0; + padding: 14px 2px 14px 5px; +} +.ag-chart-tool-panel-button-enable .ag-chart-menu-close:before { + bottom: -40px; + content: ''; + position: absolute; + top: -40px; +} +.ag-ltr .ag-chart-tool-panel-button-enable .ag-chart-menu-close:before { + left: -10px; + right: 0; +} +.ag-rtl .ag-chart-tool-panel-button-enable .ag-chart-menu-close:before { + left: 0; + right: -10px; +} +.ag-chart-tool-panel-button-enable .ag-chart-menu-close:hover { + background-image: linear-gradient( + var(--ag-icon-button-hover-color), + var(--ag-icon-button-hover-color) + ); +} +.ag-chart-tool-panel-button-enable .ag-icon-menu { + display: none; +} +.ag-ltr .ag-chart-tool-panel-button-enable .ag-chart-menu-close { + transform: translate(3px, -50%); +} +.ag-rtl .ag-chart-tool-panel-button-enable .ag-chart-menu-close { + transform: translate(-3px, -50%); +} +.ag-chart-tool-panel-button-enable .ag-chart-menu-close:hover { + transform: translateY(-50%); +} +.ag-ltr .ag-chart-menu-visible .ag-chart-tool-panel-button-enable .ag-chart-menu-close:hover { + transform: translate(5px, -50%); +} +.ag-rtl .ag-chart-menu-visible .ag-chart-tool-panel-button-enable .ag-chart-menu-close:hover { + transform: translate(-5px, -50%); +} +.ag-charts-font-size-color { + align-self: stretch; + display: flex; + justify-content: space-between; +} +.ag-charts-data-group-item { + position: relative; +} +.ag-charts-data-group-item:not(:last-child) { + margin-bottom: var(--ag-grid-size); +} +.ag-chart-menu { + background: var(--ag-background-color); +} +.ag-chart-menu, +.ag-chart-menu-icon { + border-radius: var(--ag-border-radius); +} +.ag-chart-menu-icon { + cursor: pointer; + margin: 2px 0; + opacity: 0.5; + opacity: 0.8; +} +.ag-chart-menu-icon:hover { + opacity: 1; +} +.ag-chart-menu-toolbar-button { + background-color: unset; + border: 0; + border-radius: 1px; + padding: 0 2px; +} +.ag-chart-mini-thumbnail { + border: 1px solid var(--ag-border-color); + border-radius: 5px; +} +.ag-chart-mini-thumbnail.ag-selected { + border-color: var(--ag-accent-color); +} +.ag-chart-data-column-drag-handle { + margin-left: var(--ag-grid-size); +} +.ag-charts-data-group-title-bar, +.ag-charts-format-top-level-group-title-bar, +.ag-charts-settings-group-title-bar { + position: relative; +} +.ag-charts-advanced-settings-top-level-group-title-bar { + background-color: unset; + position: relative; +} +.ag-charts-advanced-settings-top-level-group-title-bar:focus-visible, +.ag-charts-data-group-title-bar:focus-visible, +.ag-charts-format-top-level-group-title-bar:focus-visible, +.ag-charts-settings-group-title-bar:focus-visible { + box-shadow: inset var(--ag-focus-shadow); +} +.ag-charts-data-group-container { + padding: calc(var(--ag-widget-container-vertical-padding) * 0.5) + var(--ag-widget-container-horizontal-padding); +} +.ag-charts-data-group-container + .ag-charts-data-group-item:not(.ag-charts-format-sub-level-group):not(.ag-pill-select):not( + .ag-select + ) { + height: var(--ag-list-item-height); +} +.ag-charts-data-group-container .ag-charts-data-group-item.ag-picker-field { + margin-top: var(--ag-grid-size); +} +.ag-charts-advanced-settings-top-level-group-container, +.ag-charts-format-top-level-group-container { + margin-left: calc(var(--ag-grid-size) * 2); + padding: var(--ag-grid-size); +} +.ag-charts-advanced-settings-top-level-group-item, +.ag-charts-format-top-level-group-item { + margin: var(--ag-grid-size) 0; +} +.ag-charts-format-sub-level-group-container { + display: flex; + flex-direction: column; + gap: var(--ag-widget-vertical-spacing); + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-charts-settings-group-container { + display: grid; + grid-template-columns: 60px 1fr 60px 1fr 60px; + padding: var(--ag-grid-size); + row-gap: 8px; +} +.ag-charts-settings-group-container .ag-chart-mini-thumbnail:nth-child(3n + 1) { + grid-column: 1; +} +.ag-charts-settings-group-container .ag-chart-mini-thumbnail:nth-child(3n + 2) { + grid-column: 3; +} +.ag-charts-settings-group-container .ag-chart-mini-thumbnail:nth-child(3n + 3) { + grid-column: 5; +} +.ag-chart-data-section, +.ag-chart-format-section { + display: flex; + margin: 0; +} +.ag-chart-menu-panel { + background-color: var(--ag-chrome-background-color); +} +.ag-ltr .ag-chart-menu-panel { + border-left: 1px solid var(--ag-border-color); +} +.ag-rtl .ag-chart-menu-panel { + border-right: 1px solid var(--ag-border-color); +} +.ag-chart-tabbed-menu-body { + position: relative; +} +.ag-chart-tabbed-menu-body:after { + background: linear-gradient(var(--ag-chrome-background-color), transparent); + content: ''; + display: block; + height: 16px; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.ag-charts-data-group-title-bar, +.ag-charts-format-top-level-group-title-bar, +.ag-charts-settings-group-container, +.ag-charts-settings-group-title-bar { + border-top: none; + font-weight: 500; + padding: 0 calc(var(--ag-grid-size) * 1.5); +} +.ag-charts-format-top-level-group-item { + padding-bottom: 12px; +} +.ag-charts-advanced-settings-top-level-group-item, +.ag-charts-format-top-level-group-item { + margin-bottom: 0; + margin-top: calc(var(--ag-grid-size) * 2); +} +.ag-charts-settings-group-container { + margin-top: calc(var(--ag-grid-size)); +} +.ag-ltr .ag-charts-settings-group-container { + padding-right: var(--ag-widget-container-horizontal-padding); +} +.ag-rtl .ag-charts-settings-group-container { + padding-left: var(--ag-widget-container-horizontal-padding); +} +.ag-ltr .ag-charts-format-sub-level-group-container { + padding-right: 0; +} +.ag-rtl .ag-charts-format-sub-level-group-container { + padding-left: 0; +} +.ag-charts-advanced-settings-top-level-group-toolbar, +.ag-charts-format-top-level-group-toolbar { + margin-top: var(--ag-grid-size); +} +.ag-ltr .ag-charts-advanced-settings-top-level-group-toolbar, +.ag-ltr .ag-charts-format-top-level-group-toolbar { + padding-left: calc(var(--ag-grid-size) * 2); +} +.ag-rtl .ag-charts-advanced-settings-top-level-group-toolbar, +.ag-rtl .ag-charts-format-top-level-group-toolbar { + padding-right: calc(var(--ag-grid-size) * 2); +} +.ag-charts-data-group-title-bar, +.ag-charts-format-top-level-group-title-bar, +.ag-charts-settings-group-title-bar { + margin-top: calc(var(--ag-grid-size) * 2); +} +.ag-charts-advanced-settings-top-level-group-container, +.ag-charts-format-top-level-group-container { + padding: 0; +} +.ag-ltr .ag-charts-advanced-settings-top-level-group-container, +.ag-ltr .ag-charts-format-top-level-group-container { + padding-left: 0; + padding-right: var(--ag-widget-container-horizontal-padding); +} +.ag-rtl .ag-charts-advanced-settings-top-level-group-container, +.ag-rtl .ag-charts-format-top-level-group-container { + padding-left: var(--ag-widget-container-horizontal-padding); + padding-right: 0; +} +.ag-chart-mini-thumbnail { + background-color: var(--ag-background-color); + margin-bottom: 0; + margin-top: 0; +} +.ag-charts-format-sub-level-group { + margin-bottom: calc(var(--ag-grid-size) * 2); +} +.ag-ltr .ag-charts-format-sub-level-group { + border-left: 1px dashed; + border-left-color: var(--ag-border-color); + padding-left: var(--ag-grid-size); +} +.ag-rtl .ag-charts-format-sub-level-group { + border-right: 1px dashed; + border-right-color: var(--ag-border-color); + padding-right: var(--ag-grid-size); +} +.ag-charts-advanced-settings-top-level-group-title-bar, +.ag-charts-format-sub-level-group-title-bar { + background: none; + font-weight: 500; + padding-bottom: 0; + padding-top: 0; +} +.ag-charts-format-sub-level-group-container { + padding-bottom: 0; +} +.ag-charts-format-sub-level-group-item:last-child { + margin-bottom: 0; +} +.ag-chart-menu { + --ag-icon-size: 20px; + background-color: color-mix(in srgb, transparent, var(--ag-background-color) 30%); + padding: 4px 2px; +} +.ag-chart-docked-container { + min-width: 260px; +} +.ag-chart-settings-card-item.ag-not-selected:hover { + opacity: 0.35; +} +.ag-column-drop { + align-items: center; + display: inline-flex; + overflow: auto; + position: relative; + width: 100%; +} +.ag-column-drop-cell, +.ag-column-drop-list { + align-items: center; + display: flex; +} +.ag-column-drop-cell { + gap: var(--ag-label-widget-spacing); + position: relative; +} +.ag-column-drop-cell-text { + flex: 1 1 auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-column-drop-vertical { + align-items: stretch; + display: flex; + flex: 1 1 0px; + flex-direction: column; + overflow: hidden; +} +.ag-column-drop-vertical-title-bar { + align-items: center; + display: flex; + flex: none; +} +.ag-column-drop-vertical-list { + align-items: stretch; + flex-direction: column; + flex-grow: 1; + overflow-x: auto; + position: relative; +} +.ag-column-drop-vertical-list > * { + flex: none; +} +.ag-column-drop-empty .ag-column-drop-vertical-list { + overflow: hidden; +} +.ag-column-drop-vertical-empty-message { + display: block; +} +.ag-column-drop.ag-column-drop-horizontal { + overflow: hidden; + white-space: nowrap; +} +.ag-column-drop-cell-button { + cursor: pointer; +} +.ag-column-drop-wrapper { + display: flex; +} +.ag-column-drop-horizontal-half-width { + display: inline-block; + width: 50% !important; +} +.ag-column-drop-cell { + background: var(--ag-column-drop-cell-background-color); + border: var(--ag-column-drop-cell-border); + border-radius: 500px; + padding: calc(var(--ag-grid-size) * 0.5); +} +.ag-ltr .ag-column-drop-cell { + padding-left: calc(var(--ag-grid-size) * 0.75); +} +.ag-rtl .ag-column-drop-cell { + padding-right: calc(var(--ag-grid-size) * 0.75); +} +.ag-column-drop-cell:focus-visible { + box-shadow: var(--ag-focus-shadow); +} +.ag-column-drop-cell-button { + min-width: calc(var(--ag-grid-size) * 4); +} +.ag-column-drop-cell-ghost { + opacity: 0.5; +} +.ag-column-drop-horizontal { + gap: var(--ag-cell-widget-spacing); + height: var(--ag-header-height); +} +.ag-ltr .ag-column-drop-horizontal { + padding-left: var(--ag-cell-horizontal-padding); +} +.ag-rtl .ag-column-drop-horizontal { + padding-right: var(--ag-cell-horizontal-padding); +} +.ag-column-drop-horizontal-list { + gap: var(--ag-cell-widget-spacing); +} +.ag-column-drop-vertical-list { + padding-bottom: var(--ag-grid-size); + padding-left: var(--ag-grid-size); + padding-right: var(--ag-grid-size); +} +.ag-column-drop-vertical-cell { + margin-top: var(--ag-grid-size); +} +.ag-column-drop-vertical { + min-height: 50px; +} +.ag-column-drop-vertical:not(.ag-last-column-drop) { + border-bottom: var(--ag-tool-panel-separator-border); +} +.ag-ltr .ag-column-drop-vertical-icon { + margin-right: var(--ag-widget-horizontal-spacing); +} +.ag-rtl .ag-column-drop-vertical-icon { + margin-left: var(--ag-widget-horizontal-spacing); +} +.ag-column-drop-vertical-empty-message { + bottom: 0; + left: 0; + margin-top: var(--ag-grid-size); + overflow: hidden; + position: absolute; + right: 0; + top: 0; +} +.ag-select-agg-func-popup { + @include ag.card(); + background: var(--ag-background-color); + height: calc(var(--ag-grid-size) * 5 * 3.5); + padding: 0; +} +.ag-select-agg-func-virtual-list-item { + cursor: default; + @include ag.unthemed-rtl( + ( + padding-left: calc(var(--ag-grid-size) * 2), + ) + ); +} +.ag-select-agg-func-virtual-list-item:hover { + background-color: var(--ag-selected-row-background-color); +} +@include ag.keyboard-focus((ag-select-agg-func-virtual-list-item), 1px); +.ag-sort-indicator-container { + display: contents; +} +.ag-sort-indicator-icon { + @include ag.unthemed-rtl( + ( + padding-left: var(--ag-grid-size), + ) + ); +} +.ag-column-drop-horizontal { + background-color: var(--ag-header-background-color); + border-bottom: var(--ag-header-border); +} +.ag-ltr .ag-column-drop-horizontal-half-width:not(:last-child) { + border-right: var(--ag-column-border); +} +.ag-rtl .ag-column-drop-horizontal-half-width:not(:last-child) { + border-left: var(--ag-column-border); +} +.ag-column-drop-cell-button { + min-width: 0; + opacity: 0.75; +} +.ag-column-drop-cell-button:hover { + opacity: 1; +} +.ag-column-drop-vertical { + min-height: 75px; +} +.ag-column-drop-vertical-title-bar { + padding: var(--ag-widget-container-vertical-padding) calc(var(--ag-grid-size) * 2) 0; +} +.ag-column-drop-vertical-empty-message { + align-items: center; + border: 1px dashed; + border-color: var(--ag-border-color); + display: flex; + justify-content: center; + margin: calc(var(--ag-grid-size) * 1.5) calc(var(--ag-grid-size) * 2); + padding: calc(var(--ag-grid-size) * 2); +} +.ag-column-select { + display: flex; + flex: 3 1 0px; + flex-direction: column; + overflow: hidden; + position: relative; +} +.ag-column-select-header { + flex: none; + height: var(--ag-header-height); + padding-left: var(--ag-widget-container-horizontal-padding); + padding-right: var(--ag-widget-container-horizontal-padding); +} +.ag-column-select-column, +.ag-column-select-column-group, +.ag-column-select-header { + align-items: center; + display: flex; + gap: var(--ag-widget-horizontal-spacing); + position: relative; +} +.ag-column-select-column, +.ag-column-select-column-group { + height: 100%; +} +.ag-column-select-virtual-list-item:focus-visible { + box-shadow: inset var(--ag-focus-shadow); +} +.ag-column-select-header-icon { + border-radius: var(--ag-border-radius); + cursor: pointer; + height: var(--ag-icon-size); + position: relative; + width: var(--ag-icon-size); +} +.ag-column-select-header-icon:focus-visible { + box-shadow: var(--ag-focus-shadow); +} +.ag-column-select-header-filter-wrapper { + flex: 1 1 auto; +} +.ag-column-select-header-filter { + width: 100%; +} +.ag-column-select-list { + flex: 1 1 0px; + overflow: hidden; +} +.ag-ltr .ag-column-select-column { + padding-left: calc(var(--ag-indentation-level) * var(--ag-column-select-indent-size)); +} +.ag-rtl .ag-column-select-column { + padding-right: calc(var(--ag-indentation-level) * var(--ag-column-select-indent-size)); +} +.ag-ltr .ag-column-select-add-group-indent { + margin-left: calc(var(--ag-icon-size) + var(--ag-grid-size) * 1.5); +} +.ag-rtl .ag-column-select-add-group-indent { + margin-right: calc(var(--ag-icon-size) + var(--ag-grid-size) * 1.5); +} +.ag-column-select-column-group:not(:last-child), +.ag-column-select-column:not(:last-child) { + margin-bottom: var(--ag-widget-vertical-spacing); +} +.ag-column-select-column-group-readonly, +.ag-column-select-column-readonly { + opacity: 0.5; + pointer-events: none; +} +.ag-column-select-virtual-list-viewport { + padding: calc(var(--ag-widget-container-vertical-padding) * 0.5) 0; +} +.ag-column-select-virtual-list-item { + padding: 0 var(--ag-widget-container-horizontal-padding); +} +.ag-column-select-column-label { + flex: 1 1 auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-column-select-checkbox { + display: flex; +} +.ag-set-filter-item { + align-items: center; + display: flex; + height: 100%; +} +.ag-set-filter-item-checkbox { + display: flex; + height: 100%; + width: 100%; +} +.ag-set-filter-group-icons { + display: block; +} +.ag-set-filter-group-icons > * { + cursor: pointer; +} +.ag-filter-body-wrapper { + display: flex; + flex-direction: column; +} +.ag-filter-filter { + flex: 1 1 0px; +} +.ag-filter-condition { + display: flex; + justify-content: center; +} +.ag-floating-filter-body { + display: flex; + flex: 1 1 auto; + height: 100%; + position: relative; +} +.ag-floating-filter-full-body { + align-items: center; + display: flex; + flex: 1 1 auto; + height: 100%; + overflow: hidden; + width: 100%; +} +.ag-floating-filter-full-body > div { + flex: 1 1 auto; +} +.ag-floating-filter-input { + align-items: center; + display: flex; + width: 100%; +} +.ag-floating-filter-input > * { + flex: 1 1 auto; +} +.ag-floating-filter-button { + display: flex; + flex: none; +} +.ag-set-floating-filter-input input[disabled] { + pointer-events: none; +} +.ag-floating-filter-button-button { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: transparent; + border: none; + height: var(--ag-icon-size); + width: var(--ag-icon-size); +} +.ag-filter-loading { + height: 100%; + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); + position: absolute; + width: 100%; + z-index: 1; +} +.ag-column-panel { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} +.ag-pivot-mode-panel { + display: flex; + height: var(--ag-header-height); +} +.ag-pivot-mode-select { + align-items: center; + display: flex; +} +.ag-ltr .ag-pivot-mode-select { + margin-left: var(--ag-widget-container-horizontal-padding); +} +.ag-rtl .ag-pivot-mode-select { + margin-right: var(--ag-widget-container-horizontal-padding); +} +.ag-column-panel-column-select { + border-bottom: var(--ag-tool-panel-separator-border); + border-top: var(--ag-tool-panel-separator-border); +} +.ag-dnd-ghost { + align-items: center; + background-color: var(--ag-drag-ghost-background-color); + border: var(--ag-drag-ghost-border); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-drag-ghost-shadow); + color: var(--ag-text-color); + cursor: move; + font-weight: 500; + gap: var(--ag-cell-widget-spacing); + height: var(--ag-header-height) !important; + max-width: 200px; + padding-left: var(--ag-cell-horizontal-padding); + padding-right: var(--ag-cell-horizontal-padding); + position: absolute; + text-overflow: ellipsis; + transform: translateY(calc(var(--ag-grid-size) * 2)); + z-index: 9999; +} +.ag-dnd-ghost, +.ag-header { + display: flex; + overflow: hidden; + white-space: nowrap; +} +.ag-header { + background-color: var(--ag-header-background-color); + border-bottom: var(--ag-header-border); + color: var(--ag-header-text-color); + font-family: var(--ag-header-font-family); + font-size: var(--ag-header-font-size); + font-weight: var(--ag-header-font-weight); + width: 100%; +} +.ag-header-row { + height: var(--ag-header-height); + position: absolute; +} +.ag-header-row:not(:first-child) .ag-header-cell:not(.ag-header-span-height.ag-header-span-total), +.ag-header-row:not(:first-child) .ag-header-group-cell.ag-header-group-cell-with-group { + border-top: var(--ag-header-border); +} +.ag-header-row:not(.ag-header-row-column-group) { + overflow: hidden; +} +.ag-header.ag-header-allow-overflow .ag-header-row { + overflow: visible; +} +.ag-header-cell, +.ag-header-group-cell { + align-items: center; + display: inline-flex; + gap: var(--ag-cell-widget-spacing); + height: 100%; + padding: 0 var(--ag-cell-horizontal-padding); + position: absolute; +} +:is(.ag-header-cell:not(.ag-floating-filter), .ag-header-group-cell):before { + background-color: transparent; + content: ''; + inset: 0; + position: absolute; + transition: background-color var(--ag-header-cell-hover-background-transition-duration); +} +.ag-header-cell-moving:is(.ag-header-cell:not(.ag-floating-filter), .ag-header-group-cell):before, +:is(.ag-header-cell:not(.ag-floating-filter), .ag-header-group-cell):hover:before { + background-color: var(--ag-header-cell-hover-background-color); +} +:where(.ag-header-cell:not(.ag-floating-filter) *, .ag-header-group-cell *) { + position: relative; + z-index: 1; +} +.ag-header-cell-filter-button, +.ag-header-cell.ag-header-active .ag-header-cell-menu-button { + opacity: 1; +} +.ag-header-cell-menu-button:not(.ag-header-menu-always-show) { + opacity: 0; + transition: opacity 0.2s; +} +.ag-header-cell-label, +.ag-header-group-cell-label { + align-items: center; + align-self: stretch; + display: flex; + flex: 1 1 auto; + gap: var(--ag-label-widget-spacing); +} +.ag-header-cell-label { + overflow: hidden; + text-overflow: ellipsis; +} +.ag-header-group-cell-label.ag-sticky-label { + flex: none; + max-width: 100%; + position: sticky; +} +.ag-ltr .ag-header-group-cell-label.ag-sticky-label { + left: var(--ag-cell-horizontal-padding); +} +.ag-rtl .ag-header-group-cell-label.ag-sticky-label { + right: var(--ag-cell-horizontal-padding); +} +.ag-header-group-text { + white-space: nowrap; +} +.ag-header-cell-text, +.ag-header-group-text { + overflow: hidden; + text-overflow: ellipsis; +} +.ag-header-cell:not(.ag-header-cell-auto-height) .ag-header-cell-comp-wrapper { + align-items: center; + display: flex; + height: 100%; +} +.ag-header-cell-comp-wrapper { + width: 100%; +} +.ag-header-cell-wrap-text .ag-header-cell-comp-wrapper { + white-space: normal; +} +.ag-right-aligned-header .ag-header-cell-label { + flex-direction: row-reverse; +} +.ag-floating-filter-button-button, +.ag-header-cell-filter-button, +.ag-header-cell-menu-button, +.ag-header-cell-sortable .ag-header-cell-label, +.ag-header-expand-icon, +.ag-panel-title-bar-button, +.ag-side-button-button { + cursor: pointer; +} +.ag-advanced-filter-header-cell:focus-visible, +.ag-header-cell:focus-visible, +.ag-header-group-cell:focus-visible { + box-shadow: inset var(--ag-focus-shadow); +} +.ag-header-cell:after, +.ag-header-group-cell:not(.ag-header-span-height.ag-header-group-cell-no-group):after { + content: ''; + height: var(--ag-column-header-border-height); + position: absolute; + top: calc(50% - var(--ag-column-header-border-height) * 0.5); + z-index: 1; +} +.ag-ltr .ag-header-cell:after, +.ag-ltr .ag-header-group-cell:not(.ag-header-span-height.ag-header-group-cell-no-group):after { + border-right: var(--ag-column-header-border); + right: 0; +} +.ag-rtl .ag-header-cell:after, +.ag-rtl .ag-header-group-cell:not(.ag-header-span-height.ag-header-group-cell-no-group):after { + border-left: var(--ag-column-header-border); + left: 0; +} +.ag-header-cell-resize { + align-items: center; + cursor: ew-resize; + display: flex; + height: 100%; + position: absolute; + top: 0; + width: 8px; + z-index: 2; +} +.ag-ltr .ag-header-cell-resize { + right: -4px; +} +.ag-rtl .ag-header-cell-resize { + left: -4px; +} +.ag-header-cell-resize:after { + background-color: var(--ag-header-column-resize-handle-color); + content: ''; + display: var(--ag-header-column-resize-handle-display); + height: var(--ag-header-column-resize-handle-height); + position: absolute; + top: calc(50% - var(--ag-header-column-resize-handle-height) * 0.5); + width: var(--ag-header-column-resize-handle-width); + z-index: 1; +} +.ag-ltr .ag-header-cell-resize:after { + left: calc(50% - var(--ag-header-column-resize-handle-width)); +} +.ag-rtl .ag-header-cell-resize:after { + right: calc(50% - var(--ag-header-column-resize-handle-width)); +} +.ag-header-cell.ag-header-span-height .ag-header-cell-resize:after { + height: calc(100% - var(--ag-grid-size) * 4); + top: calc(var(--ag-grid-size) * 2); +} +.ag-header-group-cell-no-group.ag-header-span-height .ag-header-cell-resize { + display: none; +} +.ag-menu { + background-color: var(--ag-menu-background-color); + border: var(--ag-menu-border); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-menu-shadow); + color: var(--ag-menu-text-color); + max-height: 100%; + overflow-y: auto; + position: absolute; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-menu-list { + cursor: default; + display: table; + padding: var(--ag-grid-size) 0; + width: 100%; +} +.ag-menu-option, +.ag-menu-separator { + display: table-row; +} +.ag-menu-option-part, +.ag-menu-separator-part { + display: table-cell; + vertical-align: middle; +} +.ag-menu-option-text { + white-space: nowrap; +} +.ag-menu-option-custom { + display: contents; +} +.ag-compact-menu-option { + display: flex; + flex-wrap: nowrap; + width: 100%; +} +.ag-compact-menu-option-text { + flex: 1 1 auto; + white-space: nowrap; +} +.ag-menu-separator { + height: calc(var(--ag-grid-size) * 2 + 1px); +} +.ag-menu-separator-part:after { + border-top: 1px solid var(--ag-menu-separator-color); + content: ''; + display: block; +} +.ag-compact-menu-option-active, +.ag-menu-option-active { + background-color: var(--ag-row-hover-color); +} +.ag-compact-menu-option-part, +.ag-menu-option-part { + line-height: var(--ag-icon-size); + padding: calc(var(--ag-grid-size) + 2px) 0; +} +.ag-compact-menu-option-disabled, +.ag-menu-option-disabled { + cursor: not-allowed; + opacity: 0.5; +} +.ag-compact-menu-option-icon, +.ag-menu-option-icon { + width: var(--ag-icon-size); +} +.ag-ltr .ag-compact-menu-option-icon, +.ag-ltr .ag-menu-option-icon { + padding-left: calc(var(--ag-grid-size) * 2); +} +.ag-rtl .ag-compact-menu-option-icon, +.ag-rtl .ag-menu-option-icon { + padding-right: calc(var(--ag-grid-size) * 2); +} +.ag-compact-menu-option-text, +.ag-menu-option-text { + padding-left: calc(var(--ag-grid-size) * 2); + padding-right: calc(var(--ag-grid-size) * 2); +} +.ag-ltr .ag-compact-menu-option-shortcut, +.ag-ltr .ag-menu-option-shortcut { + padding-right: var(--ag-grid-size); +} +.ag-rtl .ag-compact-menu-option-shortcut, +.ag-rtl .ag-menu-option-shortcut { + padding-left: var(--ag-grid-size); +} +.ag-ltr .ag-compact-menu-option-popup-pointer, +.ag-ltr .ag-menu-option-popup-pointer { + padding-right: var(--ag-grid-size); +} +.ag-rtl .ag-compact-menu-option-popup-pointer, +.ag-rtl .ag-menu-option-popup-pointer { + padding-left: var(--ag-grid-size); +} +.ag-menu-column-select-wrapper { + height: 265px; + overflow: auto; +} +.ag-menu-column-select-wrapper .ag-column-select { + height: 100%; +} +.ag-menu.ag-tabs { + min-width: 290px; +} +.ag-filter-separator { + border-top: 1px solid var(--menu-separator-color); +} +.ag-filter-select .ag-picker-field-wrapper { + width: 0; +} +.ag-filter-condition-operator { + height: 17px; +} +.ag-ltr .ag-filter-condition-operator-or { + margin-left: calc(var(--ag-grid-size) * 2); +} +.ag-rtl .ag-filter-condition-operator-or { + margin-right: calc(var(--ag-grid-size) * 2); +} +.ag-set-filter-select-all { + padding-top: var(--ag-widget-container-vertical-padding); +} +.ag-filter-no-matches, +.ag-set-filter-list { + height: calc(var(--ag-list-item-height) * 6); +} +.ag-filter-no-matches { + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-set-filter-tree-list { + height: calc(var(--ag-list-item-height) * 10); +} +.ag-set-filter-filter { + margin-left: var(--ag-widget-container-horizontal-padding); + margin-right: var(--ag-widget-container-horizontal-padding); + margin-top: var(--ag-widget-container-vertical-padding); +} +.ag-filter-to { + margin-top: var(--ag-widget-vertical-spacing); +} +.ag-mini-filter { + margin: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-set-filter-item { + padding: 0 var(--ag-widget-container-horizontal-padding); +} +.ag-ltr .ag-set-filter-add-group-indent { + margin-left: calc(var(--ag-icon-size) + var(--ag-widget-container-horizontal-padding)); +} +.ag-rtl .ag-set-filter-add-group-indent { + margin-right: calc(var(--ag-icon-size) + var(--ag-widget-container-horizontal-padding)); +} +.ag-ltr .ag-set-filter-group-icons { + margin-right: var(--ag-widget-container-horizontal-padding); +} +.ag-rtl .ag-set-filter-group-icons { + margin-left: var(--ag-widget-container-horizontal-padding); +} +.ag-filter-menu .ag-set-filter-list { + min-width: 200px; +} +.ag-filter-virtual-list-item:focus-visible { + box-shadow: inset var(--ag-focus-shadow); +} +.ag-filter-apply-panel { + display: flex; + justify-content: flex-end; + overflow: hidden; + padding: var(--ag-widget-vertical-spacing) var(--ag-widget-container-horizontal-padding) + var(--ag-widget-container-vertical-padding); +} +.ag-filter-apply-panel-button { + line-height: 1.5; +} +.ag-ltr .ag-filter-apply-panel-button { + margin-left: calc(var(--ag-grid-size) * 2); +} +.ag-rtl .ag-filter-apply-panel-button { + margin-right: calc(var(--ag-grid-size) * 2); +} +.ag-simple-filter-body-wrapper { + display: flex; + flex-direction: column; + gap: var(--ag-widget-vertical-spacing); + min-height: calc( + var(--ag-list-item-height) + var(--ag-widget-container-vertical-padding) + + var(--ag-widget-vertical-spacing) + ); + overflow-y: auto; + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-simple-filter-body-wrapper .ag-resizer-wrapper { + margin: 0; +} +.ag-multi-filter-menu-item { + margin: var(--ag-grid-size) 0; +} +.ag-multi-filter-group-title-bar { + background-color: transparent; + color: var(--ag-header-text-color); + font-weight: 500; + padding: calc(var(--ag-grid-size) * 1.5) var(--ag-grid-size); +} +.ag-multi-filter-group-title-bar:focus-visible { + box-shadow: var(--ag-focus-shadow); +} +.ag-group-filter-field-select-wrapper { + display: flex; + flex-direction: column; + gap: var(--ag-widget-vertical-spacing); + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-menu-option .ag-icon { + opacity: 65%; +} +.ag-menu-option { + cursor: pointer; + font-weight: 500; +} +.ag-ltr .ag-menu-option-popup-pointer .ag-icon { + text-align: right; +} +.ag-rtl .ag-menu-option-popup-pointer .ag-icon { + text-align: left; +} +.ag-panel { + background-color: var(--ag-panel-background-color); + display: flex; + flex-direction: column; + overflow: hidden; + position: relative; +} +.ag-dialog { + border: var(--ag-dialog-border); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-dialog-shadow); + position: absolute; +} +.ag-panel-title-bar { + align-items: center; + background-color: var(--ag-panel-title-bar-background-color); + border-bottom: var(--ag-panel-title-bar-border); + color: var(--ag-header-text-color); + cursor: default; + display: flex; + flex: none; + height: var(--ag-header-height); + padding: var(--ag-grid-size) var(--ag-cell-horizontal-padding); +} +.ag-ltr .ag-panel-title-bar-button { + margin-left: calc(var(--ag-grid-size) * 2); + margin-right: var(--ag-grid-size); +} +.ag-rtl .ag-panel-title-bar-button { + margin-left: var(--ag-grid-size); + margin-right: calc(var(--ag-grid-size) * 2); +} +.ag-panel-title-bar-title { + color: var(--ag-header-text-color); + flex: 1 1 auto; + font-weight: 500; +} +.ag-panel-title-bar-buttons { + display: flex; +} +.ag-panel-title-bar-button { + cursor: pointer; +} +.ag-panel-content-wrapper { + display: flex; + flex: 1 1 auto; + overflow: hidden; + position: relative; +} +.ag-resizer { + pointer-events: none; + position: absolute; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + z-index: 1; +} +.ag-resizer.ag-resizer-topLeft { + height: 5px; + left: 0; + top: 0; + width: 5px; +} +.ag-ltr .ag-resizer.ag-resizer-topLeft { + cursor: nwse-resize; +} +.ag-rtl .ag-resizer.ag-resizer-topLeft { + cursor: nesw-resize; +} +.ag-resizer.ag-resizer-top { + cursor: ns-resize; + height: 5px; + left: 5px; + right: 5px; + top: 0; +} +.ag-resizer.ag-resizer-topRight { + height: 5px; + right: 0; + top: 0; + width: 5px; +} +.ag-ltr .ag-resizer.ag-resizer-topRight { + cursor: nesw-resize; +} +.ag-rtl .ag-resizer.ag-resizer-topRight { + cursor: nwse-resize; +} +.ag-resizer.ag-resizer-right { + bottom: 5px; + cursor: ew-resize; + right: 0; + top: 5px; + width: 5px; +} +.ag-resizer.ag-resizer-bottomRight { + bottom: 0; + height: 5px; + right: 0; + width: 5px; +} +.ag-ltr .ag-resizer.ag-resizer-bottomRight { + cursor: nwse-resize; +} +.ag-rtl .ag-resizer.ag-resizer-bottomRight { + cursor: nesw-resize; +} +.ag-resizer.ag-resizer-bottom { + bottom: 0; + cursor: ns-resize; + height: 5px; + left: 5px; + right: 5px; +} +.ag-resizer.ag-resizer-bottomLeft { + bottom: 0; + height: 5px; + left: 0; + width: 5px; +} +.ag-ltr .ag-resizer.ag-resizer-bottomLeft { + cursor: nesw-resize; +} +.ag-rtl .ag-resizer.ag-resizer-bottomLeft { + cursor: nwse-resize; +} +.ag-resizer.ag-resizer-left { + bottom: 5px; + cursor: ew-resize; + left: 0; + top: 5px; + width: 5px; +} +.ag-dragging-fill-handle .ag-dialog, +.ag-dragging-range-handle .ag-dialog { + opacity: 0.7; + pointer-events: none; +} +.ag-pinned-left-header, +.ag-pinned-right-header { + display: inline-block; + overflow: hidden; + position: relative; +} +.ag-body-horizontal-scroll:not(.ag-scrollbar-invisible) + .ag-horizontal-left-spacer:not(.ag-scroller-corner) { + border-right: var(--ag-pinned-column-border); +} +.ag-body-horizontal-scroll:not(.ag-scrollbar-invisible) + .ag-horizontal-right-spacer:not(.ag-scroller-corner), +.ag-pinned-right-header { + border-left: var(--ag-pinned-column-border); +} +.ag-pinned-left-header { + border-right: var(--ag-pinned-column-border); +} +.ag-cell.ag-cell-first-right-pinned:not(.ag-cell-range-left):not(.ag-cell-range-single-cell) { + border-left: var(--ag-pinned-column-border); +} +.ag-cell.ag-cell-last-left-pinned:not(.ag-cell-range-right):not(.ag-cell-range-single-cell) { + border-right: var(--ag-pinned-column-border); +} +.ag-pinned-left-header .ag-header-cell-resize:after { + left: calc(50% - var(--ag-header-column-resize-handle-width)); +} +.ag-pinned-right-header .ag-header-cell-resize:after { + left: 50%; +} +.ag-pinned-left-header, +.ag-pinned-right-header { + height: 100%; +} +.ag-pinned-left-header .ag-header-cell-resize { + right: -4px; +} +.ag-pinned-right-header .ag-header-cell-resize { + left: -4px; +} +.ag-layout-print.ag-body { + display: block; + height: unset; +} +.ag-layout-print.ag-root-wrapper { + display: inline-block; +} +.ag-layout-print .ag-body-horizontal-scroll, +.ag-layout-print .ag-body-vertical-scroll { + display: none; +} +.ag-layout-print.ag-force-vertical-scroll { + overflow-y: visible !important; +} +@media print { + .ag-root-wrapper.ag-layout-print { + display: table; + } + .ag-root-wrapper.ag-layout-print .ag-body-horizontal-scroll-viewport, + .ag-root-wrapper.ag-layout-print .ag-body-viewport, + .ag-root-wrapper.ag-layout-print .ag-center-cols-container, + .ag-root-wrapper.ag-layout-print .ag-center-cols-viewport, + .ag-root-wrapper.ag-layout-print .ag-root, + .ag-root-wrapper.ag-layout-print .ag-root-wrapper-body, + .ag-root-wrapper.ag-layout-print .ag-virtual-list-viewport { + display: block !important; + height: auto !important; + overflow: hidden !important; + } + .ag-root-wrapper.ag-layout-print .ag-cell, + .ag-root-wrapper.ag-layout-print .ag-row { + -moz-column-break-inside: avoid; + break-inside: avoid; + } +} +.ag-select { + align-items: center; + display: flex; + flex-direction: row; +} +.ag-select .ag-picker-field-wrapper { + cursor: default; + min-height: var(--ag-list-item-height); +} +.ag-ltr .ag-select .ag-picker-field-wrapper { + padding-left: calc(var(--ag-cell-horizontal-padding) / 2); + padding-right: var(--ag-grid-size); +} +.ag-rtl .ag-select .ag-picker-field-wrapper { + padding-left: var(--ag-grid-size); + padding-right: calc(var(--ag-cell-horizontal-padding) / 2); +} +.ag-select.ag-disabled .ag-picker-field-wrapper:focus { + box-shadow: none; +} +.ag-select:not(.ag-cell-editor, .ag-label-align-top) { + min-height: var(--ag-list-item-height); +} +.ag-select .ag-picker-field-display { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-select .ag-picker-field-icon { + align-items: center; + display: flex; +} +.ag-select.ag-disabled { + opacity: 0.5; +} +.ag-rich-select { + cursor: default; + height: 100%; +} +.ag-rich-select-value { + align-items: center; + background-color: var(--ag-input-background-color); + display: flex; + height: 100%; + padding: var(--ag-grid-size); +} +.ag-rich-select-value .ag-picker-field-display { + overflow: hidden; + text-overflow: ellipsis; +} +.ag-rich-select-value .ag-picker-field-display.ag-display-as-placeholder { + opacity: 0.5; +} +.ag-rich-select-list { + background-color: var(--ag-input-background-color); + border: var(--ag-input-border); + border-radius: var(--ag-input-border-radius); + box-shadow: var(--ag-dropdown-shadow); + height: auto; + position: relative; + width: 100%; +} +.ag-rich-select-list .ag-loading-text { + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); +} +.ag-rich-select-row { + align-items: center; + display: flex; + flex: 1 1 auto; + height: 100%; + overflow: hidden; + padding: 0 var(--ag-grid-size); + white-space: nowrap; +} +.ag-rich-select-row-selected { + background-color: var(--ag-selected-row-background-color); +} +.ag-rich-select-row-text-highlight { + font-weight: 700; +} +.ag-rich-select-field-input { + flex: 1 1 auto; +} +.ag-ltr .ag-rich-select-field-input { + left: var(--ag-grid-size); +} +.ag-rtl .ag-rich-select-field-input { + right: var(--ag-grid-size); +} +.ag-rich-select-field-input .ag-input-field-input { + border: none !important; + box-shadow: none !important; + padding: 0 !important; + text-overflow: ellipsis; +} +.ag-rich-select-field-input .ag-input-field-input::-moz-placeholder { + opacity: 0.8; +} +.ag-rich-select-field-input .ag-input-field-input::placeholder { + opacity: 0.8; +} +.ag-popup-editor .ag-rich-select-value { + height: var(--ag-row-height); + min-width: 200px; +} +.ag-rich-select-virtual-list-item { + cursor: default; + height: var(--ag-list-item-height); +} +.ag-rich-select-virtual-list-item:hover { + background-color: var(--ag-row-hover-color); +} +.ag-root-wrapper { + cursor: default; + display: flex; + flex-direction: column; + line-height: normal; + overflow: hidden; + position: relative; + white-space: normal; + -webkit-font-smoothing: antialiased; + background-color: var(--ag-background-color); + border: var(--ag-wrapper-border); + border-radius: var(--ag-wrapper-border-radius); + color: var(--ag-text-color); + font-family: var(--ag-font-family); + font-size: var(--ag-font-size); +} +.ag-root-wrapper.ag-layout-normal { + height: 100%; +} +.ag-ltr .ag-side-bar-left .ag-tool-panel-horizontal-resize { + right: -3px; +} +.ag-ltr .ag-side-bar-right .ag-tool-panel-horizontal-resize, +.ag-rtl .ag-side-bar-left .ag-tool-panel-horizontal-resize { + left: -3px; +} +.ag-rtl .ag-side-bar-right .ag-tool-panel-horizontal-resize { + right: -3px; +} +.ag-tool-panel-wrapper { + width: var(--ag-side-bar-panel-width); +} +.ag-side-bar { + background-color: var(--ag-side-bar-background-color); + display: flex; + flex-direction: row-reverse; + position: relative; +} +.ag-side-bar-left { + flex-direction: row; + order: -1; +} +.ag-side-buttons { + position: relative; + width: calc(var(--ag-icon-size) + var(--ag-grid-size) * 2); +} +.ag-side-button.ag-selected { + background-color: var(--ag-side-button-selected-background-color); + border-bottom: var(--ag-side-button-selected-border); +} +.ag-side-button.ag-selected:not(:first-of-type) { + border-top: var(--ag-side-button-selected-border); +} +.ag-side-button-button { + align-items: center; + display: flex; + flex-direction: column; + gap: var(--ag-label-widget-spacing); + padding: calc(var(--ag-grid-size) * 3) 0; + position: relative; + white-space: nowrap; + width: 100%; +} +.ag-side-button-button:focus { + box-shadow: none; +} +.ag-side-button-button:focus-visible { + box-shadow: inset var(--ag-focus-shadow); +} +.ag-side-button-label { + writing-mode: vertical-lr; +} +@media (max-resolution: 1.5x) { + .ag-side-button-label { + font-family: 'Segoe UI', var(--ag-font-family); + } + .ag-ltr .ag-side-button-label { + transform: rotate(0.05deg); + } + .ag-rtl .ag-side-button-label { + transform: rotate(-0.05deg); + } +} +.ag-ltr .ag-side-bar-left, +.ag-rtl .ag-side-bar-right { + border-right: var(--ag-side-panel-border); +} +.ag-ltr .ag-side-bar-left .ag-tool-panel-wrapper, +.ag-ltr .ag-side-bar-right, +.ag-rtl .ag-side-bar-left, +.ag-rtl .ag-side-bar-right .ag-tool-panel-wrapper { + border-left: var(--ag-side-panel-border); +} +.ag-ltr .ag-side-bar-right .ag-tool-panel-wrapper, +.ag-rtl .ag-side-bar-left .ag-tool-panel-wrapper { + border-right: var(--ag-side-panel-border); +} +.ag-ltr .ag-chart-menu-panel { + border-left: var(--ag-side-panel-border); +} +.ag-rtl .ag-chart-menu-panel { + border-right: var(--ag-side-panel-border); +} +.ag-button { + border-radius: 0; +} +.ag-standard-button { + -moz-appearance: none; + appearance: none; + -webkit-appearance: none; + background-color: var(--ag-background-color); + border: var(--ag-input-border); + border-radius: var(--ag-border-radius); + cursor: pointer; + font-family: inherit; + padding: var(--ag-grid-size) calc(var(--ag-grid-size) * 2); +} +.ag-standard-button:hover { + background-color: var(--ag-row-hover-color); +} +.ag-standard-button:active { + border-color: var(--ag-accent-color); +} +.ag-standard-button:disabled { + background-color: var(--ag-input-disabled-background-color); + border: var(--ag-input-disabled-border); + color: var(--ag-input-disabled-text-color); +} +:where(input[class^='ag-'][type='button'], button[class^='ag-']):focus-visible { + box-shadow: var(--ag-focus-shadow); +} +.ag-checkbox-input-wrapper, +.ag-radio-button-input-wrapper { + background-color: var(--ag-checkbox-unchecked-background-color); + border: solid var(--ag-checkbox-border-width) var(--ag-checkbox-unchecked-border-color); + flex: none; + height: var(--ag-icon-size); + position: relative; + width: var(--ag-icon-size); +} +.ag-checkbox-input-wrapper input, +.ag-radio-button-input-wrapper input { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 100%; + opacity: 0; + width: 100%; +} +.ag-checkbox-input-wrapper:after, +.ag-radio-button-input-wrapper:after { + content: ''; + display: block; + inset: 0; + -webkit-mask-position: center; + mask-position: center; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + pointer-events: none; + position: absolute; +} +.ag-checkbox-input-wrapper.ag-checked, +.ag-radio-button-input-wrapper.ag-checked { + background-color: var(--ag-checkbox-checked-background-color); + border-color: var(--ag-checkbox-checked-border-color); +} +.ag-checkbox-input-wrapper.ag-checked:after, +.ag-radio-button-input-wrapper.ag-checked:after { + background-color: var(--ag-checkbox-checked-shape-color); +} +.ag-checkbox-input-wrapper:active, +.ag-checkbox-input-wrapper:focus-within, +.ag-radio-button-input-wrapper:active, +.ag-radio-button-input-wrapper:focus-within { + box-shadow: var(--ag-focus-shadow); +} +.ag-checkbox-input-wrapper.ag-disabled, +.ag-radio-button-input-wrapper.ag-disabled { + filter: grayscale(); + opacity: 0.5; +} +.ag-checkbox-input-wrapper { + border-radius: var(--ag-checkbox-border-radius); +} +.ag-checkbox-input-wrapper.ag-checked:after { + -webkit-mask-image: var(--ag-checkbox-checked-shape-image); + mask-image: var(--ag-checkbox-checked-shape-image); +} +.ag-checkbox-input-wrapper.ag-indeterminate { + background-color: var(--ag-checkbox-indeterminate-background-color); + border-color: var(--ag-checkbox-indeterminate-border-color); +} +.ag-checkbox-input-wrapper.ag-indeterminate:after { + background-color: var(--ag-checkbox-indeterminate-shape-color); + -webkit-mask-image: var(--ag-checkbox-indeterminate-shape-image); + mask-image: var(--ag-checkbox-indeterminate-shape-image); +} +.ag-radio-button-input-wrapper { + border-radius: 100%; +} +.ag-radio-button-input-wrapper.ag-checked:after { + -webkit-mask-image: var(--ag-radio-checked-shape-image); + mask-image: var(--ag-radio-checked-shape-image); +} +.ag-drag-handle { + color: varXXX(--ag-icon-font-color); + cursor: grab; +} +.ag-list-item, +.ag-virtual-list-item { + height: var(--ag-list-item-height); +} +.ag-virtual-list-item { + position: absolute; + width: 100%; +} +.ag-select-list { + background-color: var(--ag-background-color); + border: var(--ag-input-border); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-dropdown-shadow); + overflow-x: hidden; + overflow-y: auto; +} +.ag-list-item { + align-items: center; + display: flex; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-list-item.ag-active-item { + background-color: var(--ag-row-hover-color); +} +.ag-select-list-item { + cursor: default; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-ltr .ag-select-list-item { + padding-left: calc(var(--ag-cell-horizontal-padding) / 2); +} +.ag-rtl .ag-select-list-item { + padding-right: calc(var(--ag-cell-horizontal-padding) / 2); +} +.ag-select-list-item span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-list-item-hovered:after { + background-color: var(--ag-range-selection-border-color); + content: ''; + height: 1px; + left: 0; + position: absolute; + right: 0; +} +.ag-item-highlight-top:after { + top: 0; +} +.ag-item-highlight-bottom:after { + bottom: 0; +} +.ag-range-field { + align-items: center; + display: flex; +} +.ag-range-field .ag-input-wrapper { + height: 100%; +} +input[class^='ag-'][type='range'] { + -webkit-appearance: none; + background: none; + height: 100%; + overflow: visible; + padding: 0; + width: 100%; +} +input[class^='ag-'][type='range']::-webkit-slider-runnable-track { + background-color: var(--ag-border-color); + border-radius: 1.5px; + height: 3px; + margin: 0; + padding: 0; + width: 100%; +} +input[class^='ag-'][type='range']::-moz-range-track { + background-color: var(--ag-border-color); + border-radius: 1.5px; + height: 3px; + margin: 0; + padding: 0; + width: 100%; +} +input[class^='ag-'][type='range']::-webkit-slider-thumb { + -webkit-appearance: none; + background-color: var(--ag-background-color); + border: 1px solid var(--ag-border-color); + border-radius: 100%; + height: var(--ag-icon-size); + margin: 0; + padding: 0; + transform: translateY(calc(var(--ag-icon-size) * -0.5 + 1.5px)); + width: var(--ag-icon-size); +} +input[class^='ag-'][type='range']::-moz-ag-range-thumb { + -webkit-appearance: none; + background-color: var(--ag-background-color); + border: 1px solid var(--ag-border-color); + border-radius: 100%; + height: var(--ag-icon-size); + margin: 0; + padding: 0; + transform: translateY(calc(var(--ag-icon-size) * -0.5 + 1.5px)); + width: var(--ag-icon-size); +} +input[class^='ag-'][type='range']:focus::-webkit-slider-thumb { + border-color: var(--ag-accent-color); + box-shadow: var(--ag-focus-shadow); +} +input[class^='ag-'][type='range']:focus::-moz-ag-range-thumb { + border-color: var(--ag-accent-color); + box-shadow: var(--ag-focus-shadow); +} +input[class^='ag-'][type='range']:active::-webkit-slider-runnable-track { + background-color: var(--ag-accent-color); +} +input[class^='ag-'][type='range']:active::-moz-ag-range-track { + background-color: var(--ag-accent-color); +} +input[class^='ag-'][type='range']:disabled { + opacity: 0.5; +} +.ag-toggle-button { + flex: none; + min-width: unset; + width: unset; +} +.ag-toggle-button-input-wrapper { + background-color: var(--ag-toggle-button-off-background-color); + border: solid var(--ag-toggle-button-border-width) var(--ag-toggle-button-off-border-color); + border-radius: calc(var(--ag-toggle-button-height) * 0.5); + flex: none; + height: var(--ag-toggle-button-height); + max-width: var(--ag-toggle-button-width); + min-width: var(--ag-toggle-button-width); + position: relative; +} +.ag-toggle-button-input-wrapper input { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 100%; + opacity: 0; + width: 100%; +} +.ag-toggle-button-input-wrapper:before { + background-color: var(--ag-toggle-button-switch-background-color); + border: var(--ag-toggle-button-border-width) solid var(--ag-toggle-button-switch-border-color); + border-radius: 100%; + content: ''; + display: block; + height: var(--ag-toggle-button-height); + pointer-events: none; + position: absolute; + top: calc(0px - var(--ag-toggle-button-border-width)); + width: var(--ag-toggle-button-height); +} +.ag-ltr .ag-toggle-button-input-wrapper:before { + left: calc(0px - var(--ag-toggle-button-border-width)); + transition: left 0.1s; +} +.ag-rtl .ag-toggle-button-input-wrapper:before { + right: calc(0px - var(--ag-toggle-button-border-width)); + transition: right 0.1s; +} +.ag-toggle-button-input-wrapper.ag-checked { + background-color: var(--ag-toggle-button-on-background-color); +} +.ag-toggle-button-input-wrapper.ag-checked, +.ag-toggle-button-input-wrapper.ag-checked:before { + border-color: var(--ag-toggle-button-on-border-color); +} +.ag-ltr .ag-toggle-button-input-wrapper.ag-checked:before { + left: calc(100% - var(--ag-toggle-button-height) + var(--ag-toggle-button-border-width)); +} +.ag-rtl .ag-toggle-button-input-wrapper.ag-checked:before { + right: calc(100% - var(--ag-toggle-button-height) + var(--ag-toggle-button-border-width)); +} +.ag-toggle-button-input-wrapper:focus-within { + box-shadow: var(--ag-focus-shadow); +} +.ag-toggle-button-input-wrapper.ag-disabled { + opacity: 0.5; +} +.ag-autocomplete { + align-items: center; + display: flex; + width: 100%; +} +.ag-autocomplete > * { + flex: 1 1 auto; +} +.ag-autocomplete-list-popup { + position: absolute; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ag-autocomplete-list { + height: calc(var(--ag-row-height) * 6.5); + min-width: 200px; + position: relative; + width: 100%; +} +.ag-autocomplete-virtual-list-item { + cursor: default; + display: flex; + height: var(--ag-list-item-height); +} +.ag-autocomplete-virtual-list-item:focus-visible:after { + content: none; +} +.ag-autocomplete-virtual-list-item:hover { + background-color: var(--ag-row-hover-color); +} +.ag-autocomplete-row { + align-items: center; + display: flex; + flex: 1 1 auto; + overflow: hidden; +} +.ag-autocomplete-row-label { + margin: 0 var(--ag-widget-container-horizontal-padding); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ag-autocomplete-row-selected { + background-color: var(--ag-selected-row-background-color); +} +.ag-tooltip { + background-color: var(--ag-tooltip-background-color); + border: var(--ag-tooltip-border); + border-radius: var(--ag-border-radius); + color: var(--ag-tooltip-text-color); + padding: var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding); + white-space: normal; +} +.ag-tooltip, +.ag-tooltip-custom { + position: absolute; + z-index: 99999; +} +.ag-tooltip-custom:not(.ag-tooltip-interactive), +.ag-tooltip:not(.ag-tooltip-interactive) { + pointer-events: none; +} +.ag-tooltip-custom.ag-tooltip-animate, +.ag-tooltip.ag-tooltip-animate { + transition: opacity 1s; +} +.ag-tooltip-custom.ag-tooltip-animate.ag-tooltip-hiding, +.ag-tooltip.ag-tooltip-animate.ag-tooltip-hiding { + opacity: 0; +} +.ag-angle-select { + align-items: center; + display: flex; +} +.ag-angle-select-wrapper { + display: flex; +} +.ag-angle-select-parent-circle { + display: block; + position: relative; +} +.ag-angle-select-child-circle { + position: absolute; +} +.ag-slider-wrapper { + display: flex; +} +.ag-picker-field-display, +.ag-slider-wrapper .ag-input-field { + flex: 1 1 auto; +} +.ag-picker-field { + align-items: center; + display: flex; +} +.ag-picker-field-icon { + border: 0; + cursor: pointer; + display: flex; + margin: 0; + padding: 0; +} +.ag-color-panel { + display: flex; + flex-direction: column; + text-align: center; + width: 100%; +} +.ag-spectrum-color { + cursor: default; + flex: 1 1 auto; + overflow: hidden; + position: relative; +} +.ag-spectrum-fill { + inset: 0; + position: absolute; +} +.ag-spectrum-val { + cursor: pointer; +} +.ag-spectrum-dragger { + cursor: pointer; + pointer-events: none; + position: absolute; +} +.ag-spectrum-hue { + background: linear-gradient( + 270deg, + red 3%, + #ff0 17%, + #0f0 33%, + #0ff 50%, + #00f 67%, + #f0f 83%, + red + ); + cursor: default; +} +.ag-spectrum-alpha { + cursor: default; +} +.ag-spectrum-hue-background { + height: 100%; + width: 100%; +} +.ag-spectrum-alpha-background { + background-image: linear-gradient(90deg, transparent, #000); + height: 100%; + width: 100%; +} +.ag-spectrum-tool { + cursor: pointer; +} +.ag-spectrum-slider { + pointer-events: none; + position: absolute; +} +.ag-recent-colors { + display: flex; + gap: 6px; +} +.ag-recent-color { + cursor: pointer; +} +.ag-angle-select[disabled] { + opacity: 0.5; + pointer-events: none; +} +.ag-ltr .ag-angle-select-field, +.ag-ltr .ag-slider-field { + margin-right: calc(var(--ag-grid-size) * 2); +} +.ag-rtl .ag-angle-select-field, +.ag-rtl .ag-slider-field { + margin-left: calc(var(--ag-grid-size) * 2); +} +.ag-angle-select-parent-circle { + background-color: var(--ag-background-color); + border: 1px solid; + border-color: var(--ag-border-color); + border-radius: 12px; + height: 24px; + width: 24px; +} +.ag-angle-select-child-circle { + background-color: var(--ag-foreground-color); + border-radius: 3px; + height: 6px; + left: 12px; + margin-left: -3px; + margin-top: -4px; + top: 4px; + width: 6px; +} +.ag-picker-field-wrapper { + background-color: var(--ag-background-color); + border: var(--ag-input-border); + border-radius: 5px; + min-height: calc(var(--ag-grid-size) * 4); + overflow: hidden; +} +.ag-picker-field-wrapper:disabled { + opacity: 0.5; +} +.ag-picker-field-wrapper.ag-picker-has-focus, +.ag-picker-field-wrapper:focus-within { + border: var(--ag-input-focus-border); + box-shadow: var(--ag-focus-shadow); +} +.ag-picker-field-button { + background-color: var(--ag-background-color); +} +.ag-dialog.ag-color-dialog { + border-radius: 5px; +} +.ag-color-picker .ag-picker-field-display { + height: var(--ag-icon-size); +} +.ag-color-picker .ag-picker-field-wrapper { + max-width: 45px; + min-width: 45px; +} +.ag-color-panel { + padding: var(--ag-grid-size); +} +.ag-color-picker .ag-picker-field-wrapper { + max-width: 55px; + min-width: 55px; +} +.ag-color-picker .ag-picker-field-display { + border: var(--ag-input-border); + border-radius: 2px; + flex: auto 0 0; + height: 18px; + margin: 6px; + width: 18px; +} +.ag-ltr .ag-color-picker .ag-picker-field-icon { + margin-right: 4px; +} +.ag-rtl .ag-color-picker .ag-picker-field-icon { + margin-left: 4px; +} +.ag-spectrum-color { + background-color: red; + border-radius: 2px; +} +.ag-spectrum-tools { + padding: 10px; +} +.ag-spectrum-sat { + background-image: linear-gradient(90deg, #fff, hsla(20, 42%, 65%, 0)); +} +.ag-spectrum-val { + background-image: linear-gradient(0deg, #000, hsla(20, 42%, 65%, 0)); +} +.ag-spectrum-dragger { + background: #000; + border: 1px solid #fff; + border-radius: 12px; + box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.24); + height: 12px; + width: 12px; +} +.ag-spectrum-alpha-background, +.ag-spectrum-hue-background { + border-radius: 2px; +} +.ag-spectrum-tool { + border-radius: 2px; + height: 11px; + margin-bottom: 10px; +} +.ag-spectrum-slider { + background-color: #f8f8f8; + border-radius: 13px; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37); + height: 13px; + margin-top: -12px; + width: 13px; +} +.ag-recent-color:focus-visible:not(:disabled):not([readonly]), +.ag-spectrum-color:focus-visible:not(:disabled):not([readonly]), +.ag-spectrum-slider:focus-visible:not(:disabled):not([readonly]) { + box-shadow: var(--ag-focus-shadow); +} +.ag-filter-toolpanel { + flex: 1 1 0px; + min-width: 0; +} +.ag-filter-toolpanel-header { + position: relative; +} +.ag-filter-toolpanel-header, +.ag-filter-toolpanel-header > *, +.ag-filter-toolpanel-search, +.ag-filter-toolpanel-search > * { + align-items: center; + display: flex; +} +.ag-filter-toolpanel-header { + height: calc(var(--ag-grid-size) * 6); +} +.ag-filter-toolpanel-header:focus-visible { + border-radius: var(--ag-border-radius); + box-shadow: inset var(--ag-focus-shadow); +} +.ag-filter-toolpanel-header, +.ag-filter-toolpanel-search { + padding: 0 var(--ag-grid-size); +} +.ag-filter-toolpanel-group:not(.ag-has-filter) + > .ag-group-title-bar + .ag-filter-toolpanel-group-instance-header-icon { + display: none; +} +.ag-filter-toolpanel-group-level-0-header { + height: calc(var(--ag-grid-size) * 8); +} +.ag-filter-toolpanel-group-item { + margin-bottom: calc(var(--ag-grid-size) * 0.5); + margin-top: calc(var(--ag-grid-size) * 0.5); +} +.ag-filter-toolpanel-search { + margin-top: var(--ag-widget-container-vertical-padding); +} +.ag-filter-toolpanel-search-input { + flex-grow: 1; + height: calc(var(--ag-grid-size) * 4); +} +.ag-ltr .ag-filter-toolpanel-expand, +.ag-ltr .ag-filter-toolpanel-group-title-bar-icon { + margin-right: var(--ag-grid-size); +} +.ag-rtl .ag-filter-toolpanel-expand, +.ag-rtl .ag-filter-toolpanel-group-title-bar-icon { + margin-left: var(--ag-grid-size); +} +.ag-ltr .ag-filter-toolpanel-instance-header { + padding-left: calc(var(--ag-filter-tool-panel-group-indent) * var(--ag-indentation-level)); +} +.ag-rtl .ag-filter-toolpanel-instance-header { + padding-right: calc(var(--ag-filter-tool-panel-group-indent) * var(--ag-indentation-level)); +} +.ag-ltr .ag-filter-toolpanel-instance-header.ag-filter-toolpanel-group-level-1-header { + padding-left: var(--ag-grid-size); +} +.ag-rtl .ag-filter-toolpanel-instance-header.ag-filter-toolpanel-group-level-1-header { + padding-right: var(--ag-grid-size); +} +.ag-filter-toolpanel-instance-filter { + margin-top: var(--ag-grid-size); +} +.ag-ltr .ag-filter-toolpanel-group-instance-header-icon, +.ag-ltr .ag-filter-toolpanel-instance-header-icon { + margin-left: var(--ag-grid-size); +} +.ag-rtl .ag-filter-toolpanel-group-instance-header-icon, +.ag-rtl .ag-filter-toolpanel-instance-header-icon { + margin-right: var(--ag-grid-size); +} +.ag-ltr .ag-filter-toolpanel-group-container { + padding-left: var(--ag-grid-size); +} +.ag-rtl .ag-filter-toolpanel-group-container { + padding-right: var(--ag-grid-size); +} +.ag-filter-toolpanel-instance-filter { + background-color: var(--ag-chrome-background-color); + border: none; +} +.ag-ltr .ag-filter-toolpanel-instance-filter { + margin-left: calc(var(--ag-icon-size) * 0.5); +} +.ag-rtl .ag-filter-toolpanel-instance-filter { + margin-right: calc(var(--ag-icon-size) * 0.5); +} +.ag-filter-toolpanel-group-level-0 { + border-top: none; +} +.ag-filter-toolpanel-header { + height: auto; + padding-bottom: var(--ag-grid-size); + padding-top: var(--ag-grid-size); +} +.ag-filter-toolpanel-group-item { + margin: 0; +} +.ag-filter-toolpanel-header, +.ag-filter-toolpanel-search { + color: var(--ag-header-text-color); + font-weight: 500; +} +.ag-paging-panel { + align-items: center; + border-top: var(--ag-footer-border); + display: flex; + gap: calc(var(--ag-grid-size) * 4); + height: max(var(--ag-row-height), 22px); + justify-content: flex-end; + padding: 0 var(--ag-cell-horizontal-padding); +} +.ag-paging-page-size .ag-wrapper { + min-width: 50px; +} +.ag-paging-page-summary-panel { + align-items: center; + display: flex; + gap: var(--ag-cell-widget-spacing); +} +.ag-disabled .ag-paging-page-summary-panel { + pointer-events: none; +} +.ag-paging-button { + cursor: pointer; + position: relative; +} +.ag-paging-button:focus-visible { + box-shadow: var(--ag-focus-shadow); +} +.ag-paging-button.ag-disabled { + cursor: default; + opacity: 0.5; +} +.ag-paging-number, +.ag-paging-row-summary-panel-number { + font-weight: 500; +} +.ag-status-bar { + border-top: var(--ag-footer-border); + display: flex; + justify-content: space-between; + line-height: 1.5; + overflow: hidden; + padding-left: calc(var(--ag-grid-size) * 4); + padding-right: calc(var(--ag-grid-size) * 4); +} +.ag-status-panel { + display: inline-flex; +} +.ag-status-name-value { + white-space: nowrap; +} +.ag-status-bar-center, +.ag-status-bar-left, +.ag-status-bar-right { + display: inline-flex; +} +.ag-status-bar-center { + text-align: center; +} +.ag-status-name-value { + margin-left: var(--ag-grid-size); + margin-right: var(--ag-grid-size); + padding-bottom: var(--ag-widget-container-vertical-padding); + padding-top: var(--ag-widget-container-vertical-padding); +} +.ag-status-name-value-value { + font-weight: 500; +} +.ag-overlay { + inset: 0; + pointer-events: none; + position: absolute; + z-index: 2; +} +.ag-overlay-panel, +.ag-overlay-wrapper { + display: flex; + height: 100%; + width: 100%; +} +.ag-overlay-wrapper { + align-items: center; + flex: none; + justify-content: center; + text-align: center; +} +.ag-overlay-loading-wrapper { + pointer-events: all; +} +.ag-overlay-loading-center { + background: var(--ag-background-color); + border: 1px solid var(--ag-border-color); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-popup-shadow); + padding: var(--ag-grid-size); +} +.ag-icon { + display: block; + height: var(--ag-icon-size); + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + width: var(--ag-icon-size); +} +.ag-column-select-column-group-readonly .ag-icon, +.ag-disabled .ag-icon, +[disabled] .ag-icon { + opacity: 0.5; +} +.ag-icon-grip { + opacity: 0.7; +} +.ag-column-select-column-readonly .ag-icon-grip, +.ag-column-select-column-readonly.ag-icon-grip { + opacity: 0.35; +} +:is( + .ag-header-cell-menu-button, + .ag-header-cell-filter-button, + .ag-panel-title-bar-button, + .ag-header-expand-icon, + .ag-column-group-icons, + .ag-set-filter-group-icons, + .ag-group-expanded .ag-icon, + .ag-group-contracted .ag-icon, + .ag-chart-settings-prev, + .ag-chart-settings-next, + .ag-group-title-bar-icon, + .ag-column-select-header-icon, + .ag-floating-filter-button-button, + .ag-filter-toolpanel-expand, + .ag-panel-title-bar-button-icon, + .ag-chart-menu-icon, + .ag-chart-menu-close + ):hover { + background-color: var(--ag-icon-button-hover-color); + border-radius: 1px; + box-shadow: 0 0 0 4px var(--ag-icon-button-hover-color); +} +.ag-filter-active { + --ag-icon-button-hover-color: color-mix(in srgb, transparent, var(--ag-accent-color) 28%); + background-color: color-mix(in srgb, transparent, var(--ag-accent-color) 14%); + border-radius: 1px; + box-shadow: 0 0 0 4px color-mix(in srgb, transparent, var(--ag-accent-color) 14%); + position: relative; +} +.ag-filter-active:after { + background-color: var(--ag-accent-color); + border-radius: 50%; + content: ''; + height: 6px; + position: absolute; + top: -1px; + width: 6px; +} +.ag-ltr .ag-filter-active:after { + right: -1px; +} +.ag-rtl .ag-filter-active:after { + left: -1px; +} +.ag-filter-active .ag-icon-filter { + -webkit-clip-path: path('M8,0C8,4.415 11.585,8 16,8L16,16L0,16L0,0L8,0Z'); + clip-path: path('M8,0C8,4.415 11.585,8 16,8L16,16L0,16L0,0L8,0Z'); +} +.ag-row-group-indent-0 { + --ag-indentation-level: 0; +} +.ag-row-group-indent-1 { + --ag-indentation-level: 1; +} +.ag-row-group-indent-2 { + --ag-indentation-level: 2; +} +.ag-row-group-indent-3 { + --ag-indentation-level: 3; +} +.ag-row-group-indent-4 { + --ag-indentation-level: 4; +} +.ag-row-group-indent-5 { + --ag-indentation-level: 5; +} +.ag-row-group-indent-6 { + --ag-indentation-level: 6; +} +.ag-row-group-indent-7 { + --ag-indentation-level: 7; +} +.ag-row-group-indent-8 { + --ag-indentation-level: 8; +} +.ag-row-group-indent-9 { + --ag-indentation-level: 9; +} +.ag-row-group-indent-10 { + --ag-indentation-level: 10; +} +.ag-row-group-indent-11 { + --ag-indentation-level: 11; +} +.ag-row-group-indent-12 { + --ag-indentation-level: 12; +} +.ag-row-group-indent-13 { + --ag-indentation-level: 13; +} +.ag-row-group-indent-14 { + --ag-indentation-level: 14; +} +.ag-row-group-indent-15 { + --ag-indentation-level: 15; +} +.ag-row-group-indent-16 { + --ag-indentation-level: 16; +} +.ag-row-group-indent-17 { + --ag-indentation-level: 17; +} +.ag-row-group-indent-18 { + --ag-indentation-level: 18; +} +.ag-row-group-indent-19 { + --ag-indentation-level: 19; +} +.ag-row-group-indent-20 { + --ag-indentation-level: 20; +} +.ag-row-group-indent-21 { + --ag-indentation-level: 21; +} +.ag-row-group-indent-22 { + --ag-indentation-level: 22; +} +.ag-row-group-indent-23 { + --ag-indentation-level: 23; +} +.ag-row-group-indent-24 { + --ag-indentation-level: 24; +} +.ag-row-group-indent-25 { + --ag-indentation-level: 25; +} +.ag-row-group-indent-26 { + --ag-indentation-level: 26; +} +.ag-row-group-indent-27 { + --ag-indentation-level: 27; +} +.ag-row-group-indent-28 { + --ag-indentation-level: 28; +} +.ag-row-group-indent-29 { + --ag-indentation-level: 29; +} +.ag-row-group-indent-30 { + --ag-indentation-level: 30; +} +.ag-row-group-indent-31 { + --ag-indentation-level: 31; +} +.ag-row-group-indent-32 { + --ag-indentation-level: 32; +} +.ag-row-group-indent-33 { + --ag-indentation-level: 33; +} +.ag-row-group-indent-34 { + --ag-indentation-level: 34; +} +.ag-row-group-indent-35 { + --ag-indentation-level: 35; +} +.ag-row-group-indent-36 { + --ag-indentation-level: 36; +} +.ag-row-group-indent-37 { + --ag-indentation-level: 37; +} +.ag-row-group-indent-38 { + --ag-indentation-level: 38; +} +.ag-row-group-indent-39 { + --ag-indentation-level: 39; +} +.ag-row-group-indent-40 { + --ag-indentation-level: 40; +} +.ag-row-group-indent-41 { + --ag-indentation-level: 41; +} +.ag-row-group-indent-42 { + --ag-indentation-level: 42; +} +.ag-row-group-indent-43 { + --ag-indentation-level: 43; +} +.ag-row-group-indent-44 { + --ag-indentation-level: 44; +} +.ag-row-group-indent-45 { + --ag-indentation-level: 45; +} +.ag-row-group-indent-46 { + --ag-indentation-level: 46; +} +.ag-row-group-indent-47 { + --ag-indentation-level: 47; +} +.ag-row-group-indent-48 { + --ag-indentation-level: 48; +} +.ag-row-group-indent-49 { + --ag-indentation-level: 49; +} +.ag-column-select-indent-0 { + --ag-indentation-level: 0; +} +.ag-column-select-indent-1 { + --ag-indentation-level: 1; +} +.ag-column-select-indent-2 { + --ag-indentation-level: 2; +} +.ag-column-select-indent-3 { + --ag-indentation-level: 3; +} +.ag-column-select-indent-4 { + --ag-indentation-level: 4; +} +.ag-column-select-indent-5 { + --ag-indentation-level: 5; +} +.ag-column-select-indent-6 { + --ag-indentation-level: 6; +} +.ag-column-select-indent-7 { + --ag-indentation-level: 7; +} +.ag-column-select-indent-8 { + --ag-indentation-level: 8; +} +.ag-column-select-indent-9 { + --ag-indentation-level: 9; +} +.ag-set-filter-indent-0 { + --ag-indentation-level: 0; +} +.ag-set-filter-indent-1 { + --ag-indentation-level: 1; +} +.ag-set-filter-indent-2 { + --ag-indentation-level: 2; +} +.ag-set-filter-indent-3 { + --ag-indentation-level: 3; +} +.ag-set-filter-indent-4 { + --ag-indentation-level: 4; +} +.ag-set-filter-indent-5 { + --ag-indentation-level: 5; +} +.ag-set-filter-indent-6 { + --ag-indentation-level: 6; +} +.ag-set-filter-indent-7 { + --ag-indentation-level: 7; +} +.ag-set-filter-indent-8 { + --ag-indentation-level: 8; +} +.ag-set-filter-indent-9 { + --ag-indentation-level: 9; +} +.ag-filter-toolpanel-group-level-0-header { + --ag-indentation-level: 0; +} +.ag-filter-toolpanel-group-level-1-header { + --ag-indentation-level: 1; +} +.ag-filter-toolpanel-group-level-2-header { + --ag-indentation-level: 2; +} +.ag-filter-toolpanel-group-level-3-header { + --ag-indentation-level: 3; +} +.ag-filter-toolpanel-group-level-4-header { + --ag-indentation-level: 4; +} +.ag-filter-toolpanel-group-level-5-header { + --ag-indentation-level: 5; +} +.ag-filter-toolpanel-group-level-6-header { + --ag-indentation-level: 6; +} +.ag-filter-toolpanel-group-level-7-header { + --ag-indentation-level: 7; +} +.ag-filter-toolpanel-group-level-8-header { + --ag-indentation-level: 8; +} +.ag-filter-toolpanel-group-level-9-header { + --ag-indentation-level: 9; +} + +/* Part iconSet/quartzRegular */ +.ag-icon::before { + content: ''; + display: block; + width: var(--ag-icon-size); + height: var(--ag-icon-size); + background-color: currentColor; + mask-size: contain; +} +.ag-icon-aggregation::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-aggregation%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M18%207V4H6l6%208-6%208h12v-3%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-arrows::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-arrows%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpolyline%20points%3D%225%209%202%2012%205%2015%22%2F%3E%3Cpolyline%20points%3D%229%205%2012%202%2015%205%22%2F%3E%3Cpolyline%20points%3D%2215%2019%2012%2022%209%2019%22%2F%3E%3Cpolyline%20points%3D%2219%209%2022%2012%2019%2015%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%2222%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%222%22%20y2%3D%2222%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-asc::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-asc%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m5%2012%207-7%207%207%22%2F%3E%3Cpath%20d%3D%22M12%2019V5%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-cancel::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-cancel%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22m15%209-6%206%22%2F%3E%3Cpath%20d%3D%22m9%209%206%206%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-chart::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-chart%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%2218%22%20x2%3D%2218%22%20y1%3D%2220%22%20y2%3D%2210%22%2F%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%2220%22%20y2%3D%224%22%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226%22%20y1%3D%2220%22%20y2%3D%2214%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-color-picker::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-color-picker%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m19%2011-8-8-8.6%208.6a2%202%200%200%200%200%202.8l5.2%205.2c.8.8%202%20.8%202.8%200L19%2011Z%22%2F%3E%3Cpath%20d%3D%22m5%202%205%205%22%2F%3E%3Cpath%20d%3D%22M2%2013h15%22%2F%3E%3Cpath%20d%3D%22M22%2020a2%202%200%201%201-4%200c0-1.6%201.7-2.4%202-4%20.3%201.6%202%202.4%202%204Z%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-columns::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-columns%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9%203H5a2%202%200%200%200-2%202v4m6-6h10a2%202%200%200%201%202%202v4M9%203v18m0%200h10a2%202%200%200%200%202-2V9M9%2021H5a2%202%200%200%201-2-2V9m0%200h18%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-contracted::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-contracted%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-copy::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-copy%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%20x%3D%228%22%20y%3D%228%22%20rx%3D%222%22%20ry%3D%222%22%2F%3E%3Cpath%20d%3D%22M4%2016c-1.1%200-2-.9-2-2V4c0-1.1.9-2%202-2h10c1.1%200%202%20.9%202%202%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-cross::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-cross%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M18%206%206%2018%22%2F%3E%3Cpath%20d%3D%22m6%206%2012%2012%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-csv::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-csv%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M14.5%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V7.5L14.5%202z%22%2F%3E%3Cpolyline%20points%3D%2214%202%2014%208%2020%208%22%2F%3E%3Cpath%20d%3D%22M8%2013h2%22%2F%3E%3Cpath%20d%3D%22M8%2017h2%22%2F%3E%3Cpath%20d%3D%22M14%2013h2%22%2F%3E%3Cpath%20d%3D%22M14%2017h2%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-cut::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-cut%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%2F%3E%3Cpath%20d%3D%22M8.12%208.12%2012%2012%22%2F%3E%3Cpath%20d%3D%22M20%204%208.12%2015.88%22%2F%3E%3Ccircle%20cx%3D%226%22%20cy%3D%2218%22%20r%3D%223%22%2F%3E%3Cpath%20d%3D%22M14.8%2014.8%2020%2020%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-desc::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-desc%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M12%205v14%22%2F%3E%3Cpath%20d%3D%22m19%2012-7%207-7-7%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-down::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-down%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M12%205v14%22%2F%3E%3Cpath%20d%3D%22m19%2012-7%207-7-7%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-excel::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-excel%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M14.5%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V7.5L14.5%202z%22%2F%3E%3Cpolyline%20points%3D%2214%202%2014%208%2020%208%22%2F%3E%3Cpath%20d%3D%22M8%2013h2%22%2F%3E%3Cpath%20d%3D%22M8%2017h2%22%2F%3E%3Cpath%20d%3D%22M14%2013h2%22%2F%3E%3Cpath%20d%3D%22M14%2017h2%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-expanded::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-expanded%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m15%2018-6-6%206-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-eye-slash::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-eye-slash%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9.88%209.88a3%203%200%201%200%204.24%204.24%22%2F%3E%3Cpath%20d%3D%22M10.73%205.08A10.43%2010.43%200%200%201%2012%205c7%200%2010%207%2010%207a13.16%2013.16%200%200%201-1.67%202.68%22%2F%3E%3Cpath%20d%3D%22M6.61%206.61A13.526%2013.526%200%200%200%202%2012s3%207%2010%207a9.74%209.74%200%200%200%205.39-1.61%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%2222%22%20y1%3D%222%22%20y2%3D%2222%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-eye::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-eye%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M2%2012s3-7%2010-7%2010%207%2010%207-3%207-10%207-10-7-10-7Z%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%223%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-filter::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-filter%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M3%206h18%22%2F%3E%3Cpath%20d%3D%22M7%2012h10%22%2F%3E%3Cpath%20d%3D%22M10%2018h4%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-first::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-first%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m17%2018-6-6%206-6%22%2F%3E%3Cpath%20d%3D%22M7%206v12%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-group::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-group%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M16%2012H3%22%2F%3E%3Cpath%20d%3D%22M16%2018H3%22%2F%3E%3Cpath%20d%3D%22M10%206H3%22%2F%3E%3Cpath%20d%3D%22M21%2018V8a2%202%200%200%200-2-2h-5%22%2F%3E%3Cpath%20d%3D%22m16%208-2-2%202-2%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-last::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-last%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m7%2018%206-6-6-6%22%2F%3E%3Cpath%20d%3D%22M17%206v12%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-left::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-left%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m12%2019-7-7%207-7%22%2F%3E%3Cpath%20d%3D%22M19%2012H5%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-linked::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-linked%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9%2017H7A5%205%200%200%201%207%207h2%22%2F%3E%3Cpath%20d%3D%22M15%207h2a5%205%200%201%201%200%2010h-2%22%2F%3E%3Cline%20x1%3D%228%22%20x2%3D%2216%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-loading::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-loading%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%222%22%20y2%3D%226%22%2F%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%2218%22%20y2%3D%2222%22%2F%3E%3Cline%20x1%3D%224.93%22%20x2%3D%227.76%22%20y1%3D%224.93%22%20y2%3D%227.76%22%2F%3E%3Cline%20x1%3D%2216.24%22%20x2%3D%2219.07%22%20y1%3D%2216.24%22%20y2%3D%2219.07%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%226%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%2218%22%20x2%3D%2222%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%224.93%22%20x2%3D%227.76%22%20y1%3D%2219.07%22%20y2%3D%2216.24%22%2F%3E%3Cline%20x1%3D%2216.24%22%20x2%3D%2219.07%22%20y1%3D%227.76%22%20y2%3D%224.93%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-maximize::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-maximize%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpolyline%20points%3D%2215%203%2021%203%2021%209%22%2F%3E%3Cpolyline%20points%3D%229%2021%203%2021%203%2015%22%2F%3E%3Cline%20x1%3D%2221%22%20x2%3D%2214%22%20y1%3D%223%22%20y2%3D%2210%22%2F%3E%3Cline%20x1%3D%223%22%20x2%3D%2210%22%20y1%3D%2221%22%20y2%3D%2214%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-menu::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-menu%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%224%22%20x2%3D%2220%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%224%22%20x2%3D%2220%22%20y1%3D%226%22%20y2%3D%226%22%2F%3E%3Cline%20x1%3D%224%22%20x2%3D%2220%22%20y1%3D%2218%22%20y2%3D%2218%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-menu-alt::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-menu-alt%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%225%22%20r%3D%220.75%22%20fill%3D%22%23D9D9D9%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%220.75%22%20fill%3D%22%23D9D9D9%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2219%22%20r%3D%220.75%22%20fill%3D%22%23D9D9D9%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-minimize::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-minimize%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpolyline%20points%3D%224%2014%2010%2014%2010%2020%22%2F%3E%3Cpolyline%20points%3D%2220%2010%2014%2010%2014%204%22%2F%3E%3Cline%20x1%3D%2214%22%20x2%3D%2221%22%20y1%3D%2210%22%20y2%3D%223%22%2F%3E%3Cline%20x1%3D%223%22%20x2%3D%2210%22%20y1%3D%2221%22%20y2%3D%2214%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-minus::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-minus%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22M8%2012h8%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-next::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-next%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-none::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-none%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m7%2015%205%205%205-5%22%2F%3E%3Cpath%20d%3D%22m7%209%205-5%205%205%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-not-allowed::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-not-allowed%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22m4.9%204.9%2014.2%2014.2%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-paste::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-paste%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M15%202H9a1%201%200%200%200-1%201v2c0%20.6.4%201%201%201h6c.6%200%201-.4%201-1V3c0-.6-.4-1-1-1Z%22%2F%3E%3Cpath%20d%3D%22M8%204H6a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2M16%204h2a2%202%200%200%201%202%202v2M11%2014h10%22%2F%3E%3Cpath%20d%3D%22m17%2010%204%204-4%204%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-pin::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-pin%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%2217%22%20y2%3D%2222%22%2F%3E%3Cpath%20d%3D%22M5%2017h14v-1.76a2%202%200%200%200-1.11-1.79l-1.78-.9A2%202%200%200%201%2015%2010.76V6h1a2%202%200%200%200%200-4H8a2%202%200%200%200%200%204h1v4.76a2%202%200%200%201-1.11%201.79l-1.78.9A2%202%200%200%200%205%2015.24Z%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-pivot::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-pivot%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M15%203v18%22%2F%3E%3Crect%20width%3D%2218%22%20height%3D%2218%22%20x%3D%223%22%20y%3D%223%22%20rx%3D%222%22%2F%3E%3Cpath%20d%3D%22M21%209H3%22%2F%3E%3Cpath%20d%3D%22M21%2015H3%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-plus::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-plus%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22M8%2012h8%22%2F%3E%3Cpath%20d%3D%22M12%208v8%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-previous::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-previous%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m15%2018-6-6%206-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-right::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-right%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M5%2012h14%22%2F%3E%3Cpath%20d%3D%22m12%205%207%207-7%207%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-save::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-save%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M12%2017V3%22%2F%3E%3Cpath%20d%3D%22m6%2011%206%206%206-6%22%2F%3E%3Cpath%20d%3D%22M19%2021H5%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-small-down::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-down%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m6%209%206%206%206-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-small-left::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-left%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m15%2018-6-6%206-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-small-right::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-right%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-small-up::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-up%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m18%2015-6-6-6%206%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-tick::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tick%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M20%206%209%2017l-5-5%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-tree-closed::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tree-closed%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-tree-indeterminate::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tree-indeterminate%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M5%2012h14%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-tree-open::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tree-open%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m6%209%206%206%206-6%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-unlinked::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-unlinked%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9%2017H7A5%205%200%200%201%207%207%22%2F%3E%3Cpath%20d%3D%22M15%207h2a5%205%200%200%201%204%208%22%2F%3E%3Cline%20x1%3D%228%22%20x2%3D%2212%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%2222%22%20y1%3D%222%22%20y2%3D%2222%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-up::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-up%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m5%2012%207-7%207%207%22%2F%3E%3Cpath%20d%3D%22M12%2019V5%22%2F%3E%3C%2Fsvg%3E'); +} +.ag-icon-grip::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-grip%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%225%22%20cy%3D%228%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%228%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%228%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%2216%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2216%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%2216%22%20r%3D%220.5%22%2F%3E%3Cg%20stroke%3D%22none%22%20fill%3D%22currentColor%22%3E%3Ccircle%20cx%3D%225%22%20cy%3D%228%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%228%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%228%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%2216%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2216%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%2216%22%20r%3D%221%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E'); +} +.ag-icon-settings::before { + mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-settings%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M20%207h-9%22%2F%3E%3Cpath%20d%3D%22M14%2017H5%22%2F%3E%3Ccircle%20cx%3D%2217%22%20cy%3D%2217%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%227%22%20cy%3D%227%22%20r%3D%223%22%2F%3E%3C%2Fsvg%3E'); +} + +/* Part tabStyle/quartz */ +.ag-tabs-header { + background-color: var(--ag-tab-bar-background-color); + border-bottom: var(--ag-tab-bar-border); + gap: var(--ag-tab-spacing); + padding: var(--ag-tab-bar-top-padding) var(--ag-tab-bar-horizontal-padding) 0; +} +.ag-tabs-header-wrapper { + display: flex; +} +.ag-tabs-header-wrapper .ag-tabs-header { + flex: 1; +} +.ag-tabs-close-button-wrapper { + border: 0; + padding: var(--ag-grid-size); +} +.ag-ltr .ag-tabs-close-button-wrapper { + border-right: 1px solid var(--ag-border-color); +} +.ag-rtl .ag-tabs-close-button-wrapper { + border-left: 1px solid var(--ag-border-color); +} +.ag-tabs-close-button { + background-color: unset; + border: 0; + cursor: pointer; + padding: 0; +} +.ag-tab { + align-items: center; + background-color: var(--ag-tab-background-color); + border-left: var(--ag-tab-selected-border-width) solid transparent; + border-right: var(--ag-tab-selected-border-width) solid transparent; + color: var(--ag-tab-text-color); + display: flex; + flex: 1; + justify-content: center; + padding: var(--ag-tab-top-padding) var(--ag-tab-horizontal-padding) var(--ag-tab-bottom-padding); + position: relative; +} +.ag-tab:hover { + background-color: var(--ag-tab-hover-background-color); + color: var(--ag-tab-hover-text-color); +} +.ag-tab.ag-tab-selected { + background-color: var(--ag-tab-selected-background-color); + color: var(--ag-tab-selected-text-color); +} +.ag-ltr .ag-tab.ag-tab-selected:not(:first-of-type) { + border-left-color: var(--ag-tab-selected-border-color); +} +.ag-ltr .ag-tab.ag-tab-selected:not(:last-of-type), +.ag-rtl .ag-tab.ag-tab-selected:not(:first-of-type) { + border-right-color: var(--ag-tab-selected-border-color); +} +.ag-rtl .ag-tab.ag-tab-selected:not(:last-of-type) { + border-left-color: var(--ag-tab-selected-border-color); +} +.ag-tab:after { + background-color: var(--ag-tab-selected-underline-color); + bottom: 0; + content: ''; + display: block; + height: var(--ag-tab-selected-underline-width); + left: 0; + opacity: 0; + position: absolute; + right: 0; + transition: opacity var(--ag-tab-selected-underline-transition-duration); +} +.ag-tab.ag-tab-selected:after { + opacity: 1; +} +.ag-tab:focus-visible { + box-shadow: inset var(--ag-focus-shadow); +} + +/* Part inputStyle/bordered */ +:where(input[class^='ag-'][type='number']:not(.ag-number-field-input-stepper)) { + -moz-appearance: textfield; +} +:where( + input[class^='ag-'][type='number']:not(.ag-number-field-input-stepper) + )::-webkit-inner-spin-button, +:where( + input[class^='ag-'][type='number']:not(.ag-number-field-input-stepper) + )::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} +:where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ) { + background-color: var(--ag-input-background-color); + border: var(--ag-input-border); + border-radius: var(--ag-input-border-radius); + color: var(--ag-input-text-color); + min-height: var(--ag-input-height); +} +.ag-ltr + :where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ) { + padding-left: var(--ag-input-padding-start); +} +.ag-rtl + :where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ) { + padding-right: var(--ag-input-padding-start); +} +:where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ):where(:disabled) { + background-color: var(--ag-input-disabled-background-color); + border: var(--ag-input-disabled-border); + color: var(--ag-input-disabled-text-color); +} +:where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ):where(:focus) { + background-color: var(--ag-input-focus-background-color); + border: var(--ag-input-focus-border); + box-shadow: var(--ag-input-focus-shadow); + color: var(--ag-input-focus-text-color); +} +:where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ):where(:invalid) { + background-color: var(--ag-input-invalid-background-color); + border: var(--ag-input-invalid-border); + color: var(--ag-input-invalid-text-color); +} +:where( + input[class^='ag-']:not([type]), + input[class^='ag-'][type='text'], + input[class^='ag-'][type='number'], + input[class^='ag-'][type='tel'], + input[class^='ag-'][type='date'], + input[class^='ag-'][type='datetime-local'], + textarea[class^='ag-'] + ):where(.invalid) { + background-color: var(--ag-input-invalid-background-color); + border: var(--ag-input-invalid-border); + color: var(--ag-input-invalid-text-color); +} + +.ag-body-horizontal-scroll-container { + scrollbar-width: thin !important; +}