blob: df2bff7ea5ad88f4c0590380745d70e0b0b2a8e0 [file]
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@import "./common";
@import "./node_styling_widgets";
// General widget styles
// List item widget - displays an item with icon, name, description, and action button
.pf-exp-list-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: var(--pf-color-background-secondary);
border: 1px solid var(--pf-color-border);
border-radius: 4px;
transition: all 0.15s ease-in-out;
cursor: pointer;
&:hover {
background: var(--pf-color-background);
border-color: var(--pf-color-primary);
}
&:focus {
outline: 2px solid var(--pf-color-accent, var(--pf-color-primary));
outline-offset: 2px;
}
&:focus:not(:focus-visible) {
outline: none;
}
&:focus-visible {
outline: 2px solid var(--pf-color-accent, var(--pf-color-primary));
outline-offset: 2px;
}
&.pf-joined-source {
border-left: 4px solid var(--pf-color-primary);
}
}
.pf-exp-list-item-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0; // Allow text truncation
}
.pf-exp-list-item-name {
font-size: var(--pf-font-size-m);
font-weight: 600;
color: var(--pf-color-text);
font-family: "Roboto Mono", monospace;
}
.pf-exp-list-item-description {
font-size: var(--pf-font-size-s);
color: var(--pf-color-text-muted);
}
.pf-exp-list-item-actions {
display: flex;
align-items: center;
gap: 4px;
}
// Action buttons widget - horizontal row of action buttons
.pf-exp-action-buttons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
button {
justify-content: flex-start;
}
}
// Labeled control widget - inline label with any control
// Uses <label> as the root element for accessibility
.pf-exp-labeled-control {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin: 0; // Prevent margin stacking with section gaps
span {
color: var(--pf-color-text);
white-space: nowrap;
flex-shrink: 0;
}
// Allow inputs to shrink and not overflow
.pf-text-input {
min-width: 0;
flex: 1 1 auto;
}
// Stack vertically when container is narrow
@container (max-width: 400px) {
flex-direction: column;
align-items: stretch;
gap: 8px;
span {
width: 100%;
white-space: normal;
}
.pf-text-input {
width: 100%;
}
}
}
// Draggable list item widget
.pf-exp-draggable-item {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
background: var(--pf-color-background-secondary);
border: 1px solid var(--pf-color-border);
border-radius: 4px;
cursor: grab;
flex-wrap: wrap;
&:hover {
background: var(--pf-color-background);
}
.pf-exp-drag-handle {
cursor: grab;
color: var(--pf-color-text-muted);
user-select: none;
flex-shrink: 0;
}
// Ensure checkbox doesn't grow
.pf-checkbox {
flex-shrink: 0;
}
}
// Issue list widget - bulleted list inside a callout
.pf-exp-issue-list {
margin-top: 4px;
margin-bottom: 0;
padding-left: 20px;
}
// Interval node input row widget
.pf-exp-interval-node {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 8px;
span {
flex: 1;
}
}
// Advanced mode change button - subtle text-like button for mode switching
// Overrides Button widget styles for a more subtle appearance
.pf-exp-advanced-mode-button.pf-button {
font-size: var(--pf-font-size-s);
color: var(--pf-color-text-muted);
&:hover {
color: var(--pf-color-primary);
background: var(--pf-color-background-secondary);
}
.pf-left-icon {
font-size: var(--pf-font-size-l);
}
.pf-button__label {
text-decoration: underline;
text-decoration-style: dotted;
text-underline-offset: 2px;
}
}
// Modifiable item list - generic container for lists of editable items
.pf-modifiable-item-list {
display: flex;
flex-direction: column;
gap: 8px;
container-type: inline-size;
}
// Sort criteria list - list of draggable sort items with gaps
.pf-sort-criteria-list {
display: flex;
flex-direction: column;
gap: 8px;
}
// Limit and offset list - list of limit/offset items with gaps
.pf-limit-offset-list {
display: flex;
flex-direction: column;
gap: 8px;
// Number inputs in limit/offset should be narrow
.pf-inline-field .pf-text-input[type="number"] {
flex: 0 0 auto;
width: 80px;
min-width: 80px;
max-width: 80px;
}
// Keep number inputs narrow even in responsive mode
@container (max-width: 400px) {
.pf-inline-field .pf-text-input[type="number"] {
width: 80px;
min-width: 80px;
max-width: 80px;
}
}
}
// Info box widget - displays informational text in a styled box
.pf-exp-info-box {
font-size: 13px;
color: var(--pf-color-text-muted);
padding: 12px 16px;
line-height: 1.5;
background: var(--pf-color-background-secondary);
border: 1px solid var(--pf-color-border);
border-radius: 4px;
margin-bottom: 12px;
}
// Secondary inputs container - vertical stack of input items
.pf-exp-secondary-inputs {
display: flex;
flex-direction: column;
gap: 8px;
}
// Inline edit list container - vertical stack with spacing
.pf-inline-edit-list {
display: flex;
flex-direction: column;
gap: 8px;
container-type: inline-size;
}
// Form list item widget - inline form editing in a list item
.pf-exp-form-list-item {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
min-height: 40px;
background: var(--pf-color-background-secondary);
border: 1px solid var(--pf-color-border);
border-radius: 4px;
transition: all 0.15s ease-in-out;
&.pf-valid {
background: var(--pf-color-background-secondary);
border-color: var(--pf-color-border);
&:hover {
background: var(--pf-color-background);
border-color: var(--pf-color-primary);
}
}
&.pf-invalid {
border-color: var(--pf-color-danger);
}
}
.pf-exp-form-list-item-content {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
flex-wrap: wrap;
// Ensure form controls don't overflow
.pf-select,
.pf-text-input {
min-width: 80px;
}
// Stack vertically when container is narrow
@container (max-width: 400px) {
flex-direction: column;
align-items: stretch;
gap: 8px;
.pf-select,
.pf-text-input,
.pf-outlined-field,
.pf-outlined-multiselect {
width: 100%;
min-width: 0;
}
}
}
.pf-exp-form-list-item-actions {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}
// Material Design outlined input field with label on border
.pf-outlined-field {
position: relative;
min-width: 120px;
flex: 1;
margin: 0;
padding: 0;
border: 1px solid var(--pf-color-border);
border-radius: 4px;
transition: border-color 0.15s ease-in-out;
&:hover:not(:disabled) {
border-color: var(--pf-color-text-muted);
}
&:focus-within:not(:disabled) {
// Use thicker border instead of box-shadow to avoid covering the legend
border-color: var(--pf-color-primary);
border-width: 2px;
.pf-outlined-field-legend {
color: var(--pf-color-primary);
}
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
background: var(--pf-color-background-secondary);
}
.pf-outlined-field-legend {
padding: 0 4px;
margin-left: 8px;
font-size: var(--pf-font-size-s);
font-weight: 500;
color: var(--pf-color-text-muted);
user-select: none;
transition: color 0.15s ease-in-out;
}
.pf-outlined-field-input {
width: 100%;
padding: 4px 8px;
border: none;
background: transparent;
color: var(--pf-color-text);
font-size: var(--pf-font-size-m);
font-family: inherit;
outline: none;
&:disabled {
cursor: not-allowed;
}
}
select.pf-outlined-field-input {
cursor: pointer;
&:disabled {
cursor: not-allowed;
}
}
}
// Outlined multiselect - styles the PopupMultiSelect button to look like a form field
.pf-outlined-multiselect {
flex: 1;
.pf-button {
@extend .pf-exp-column-name;
width: 100%;
padding: 4px 8px;
border: 1px solid var(--pf-color-border) !important;
white-space: normal;
min-width: 0;
&:hover {
border-color: var(--pf-color-primary) !important;
background: var(--pf-color-background-secondary) !important;
}
&:focus {
border-color: var(--pf-color-primary) !important;
}
.pf-button__label {
white-space: normal;
word-break: break-word;
}
}
}
// Button styled like a form list item
.pf-add-item-placeholder {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 8px;
padding: 4px 8px;
min-height: 40px;
background: var(--pf-color-background-secondary);
border: 1px solid var(--pf-color-border);
border-radius: 4px;
font-size: var(--pf-font-size-m);
font-family: inherit;
color: var(--pf-color-text-muted);
cursor: pointer;
transition: all 0.15s ease-in-out;
&:hover {
border-color: var(--pf-color-primary);
background: var(--pf-color-background);
}
&:focus {
outline: 2px solid var(--pf-color-primary);
outline-offset: 2px;
}
&:focus:not(:focus-visible) {
outline: none;
}
&:focus-visible {
outline: 2px solid var(--pf-color-primary);
outline-offset: 2px;
}
.pf-add-item-placeholder__label {
font-weight: 500;
}
}
// Inline field widget - label on left, editable/read-only value on right
.pf-inline-field {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: var(--pf-color-background-secondary);
border: 1px solid var(--pf-color-border);
border-radius: 4px;
transition: all 0.15s ease-in-out;
&:hover {
background: var(--pf-color-background);
border-color: var(--pf-color-primary);
}
&.pf-invalid {
border-color: var(--pf-color-danger);
}
.pf-inline-field__label {
font-size: var(--pf-font-size-m);
font-weight: 600;
color: var(--pf-color-text);
white-space: nowrap;
min-width: 100px;
}
.pf-inline-field__value {
flex: 1;
font-size: var(--pf-font-size-m);
color: var(--pf-color-text-muted);
font-family: "Roboto Mono", monospace;
}
.pf-text-input {
flex: 1;
min-width: 0;
}
// Stack vertically when container is narrow
@container (max-width: 400px) {
flex-direction: column;
align-items: stretch;
gap: 8px;
.pf-inline-field__label {
min-width: 0;
width: 100%;
}
.pf-text-input {
width: 100%;
}
}
}
// Column list container - used by modify columns and union nodes
.pf-column-list {
display: flex;
flex-direction: column;
gap: 8px;
padding-top: 8px;
padding-bottom: 8px;
}
// Column type selector - aligns to the right in modify columns rows
.pf-column-type {
margin-left: auto;
padding: 2px 4px;
font-size: var(--pf-font-size-s);
font-weight: 400;
color: var(--pf-color-text-muted);
cursor: pointer;
transition: color 0.15s ease-in-out;
flex-shrink: 0;
&:hover {
color: var(--pf-color-primary);
}
&:focus {
outline: 2px solid var(--pf-color-primary);
outline-offset: 2px;
}
}
.pf-select-deselect-all-buttons {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-bottom: 12px;
}
// Non-draggable column row in ColumnSelector
.pf-column-selector-row {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
flex-wrap: wrap;
}
// Wider modal for computed column forms
.pf-computed-column-modal-wide {
min-width: 30vw;
}
// Callout with spacing below
.pf-callout-with-spacing {
margin-bottom: 16px;
}
// Metrics header row with ID prefix and Export button
.pf-metrics-header-row {
display: flex;
gap: 8px;
align-items: flex-start;
// OutlinedField should take most of the space
> .pf-outlined-field {
flex: 1;
}
}
// Metrics V2 Export button - styled to match OutlinedField height
.pf-metrics-v2-export-button.pf-button {
// Match the OutlinedField dimensions
min-height: 44px; // Same as OutlinedField (legend height + input padding)
padding: 8px 16px;
justify-content: center;
}
// Metrics Export Modal - fixed size to prevent layout shifts.
// The modal uses a flex column chain: modal → main → content div → result box
// so the result box fills remaining space while the CodeSnippet keeps its
// intrinsic size (with a max-height cap).
.pf-modal-dialog.pf-metrics-export-modal {
width: 900px;
height: 700px;
display: flex;
flex-direction: column;
overflow: hidden;
main {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
gap: 16px;
// The content() wrapper div created by showModal.
> div {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
gap: 16px;
}
}
// Cap the textproto snippet so it doesn't push the result box off-screen.
.pf-code-snippet {
max-height: 200px;
overflow: auto;
flex-shrink: 0;
}
}
// Bordered box around the result table inside the export modal
.pf-metrics-result-box {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0; // Allow shrinking inside flex parent
border: 1px solid var(--pf-color-border);
border-radius: 8px;
overflow: hidden;
}
.pf-metrics-result-header {
padding: 8px 12px;
font-weight: 500;
background: var(--pf-color-background-secondary);
border-bottom: 1px solid var(--pf-color-border);
}
.pf-metrics-result-content {
flex: 1;
min-height: 0;
overflow: auto;
// DataGrid needs a definite height for virtual scrolling.
.pf-data-grid {
height: 100%;
}
}
// Error / loading states centered inside the result box
.pf-metrics-error {
color: var(--md-sys-color-error);
padding: 16px;
}
.pf-metrics-result-content > .pf-spinner {
display: flex;
justify-content: center;
padding: 24px;
}
// Tabs inside the result box take full height.
.pf-metrics-result-content > .pf-tabs {
display: flex;
flex-direction: column;
height: 100%;
.pf-tabs__content {
flex: 1;
min-height: 0;
overflow: auto;
.pf-data-grid {
height: 100%;
}
}
}
// ─── Two-column drag-and-drop layout (Dimensions | Values) ──────────────────
.pf-metrics-v2-columns-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
min-height: 200px;
}
.pf-metrics-v2-column-panel {
display: flex;
flex-direction: column;
border: 1px solid var(--pf-color-border);
border-radius: 6px;
overflow: hidden;
transition:
border-color 0.15s ease,
background-color 0.15s ease;
&.pf-drop-active {
border-color: var(--pf-color-primary);
background-color: color-mix(
in srgb,
var(--pf-color-primary) 8%,
transparent
);
}
&.pf-drop-rejected {
border-color: var(--md-sys-color-error);
background-color: color-mix(
in srgb,
var(--md-sys-color-error) 8%,
transparent
);
}
}
.pf-metrics-v2-column-panel__header {
padding: 6px 10px;
font-size: var(--pf-font-size-s);
font-weight: 600;
background: var(--pf-color-background-secondary);
border-bottom: 1px solid var(--pf-color-border);
user-select: none;
}
.pf-metrics-v2-column-panel__list {
flex: 1;
overflow-y: auto;
padding: 4px 0;
}
.pf-metrics-v2-empty-hint {
padding: 12px;
color: var(--pf-color-text-secondary);
font-size: var(--pf-font-size-s);
text-align: center;
font-style: italic;
}
// Individual column item row (shared between dimensions and values)
.pf-metrics-v2-column-item {
display: flex;
flex-direction: column;
padding: 4px 8px;
cursor: grab;
user-select: none;
border-bottom: 1px solid var(--pf-color-border);
&:last-child {
border-bottom: none;
}
&:active {
cursor: grabbing;
}
&[draggable="true"]:hover {
background: var(--pf-color-background-secondary);
}
}
.pf-metrics-v2-value-header {
display: flex;
align-items: center;
gap: 4px;
min-height: 28px;
}
.pf-metrics-v2-drag-handle {
color: var(--pf-color-text-secondary);
font-size: 14px;
cursor: grab;
flex-shrink: 0;
}
.pf-metrics-v2-col-name {
flex: 1;
font-family: var(--pf-font-monospace);
font-size: var(--pf-font-size-s);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pf-metrics-v2-col-type {
font-size: var(--pf-font-size-xs);
color: var(--pf-color-text-secondary);
font-style: italic;
flex-shrink: 0;
}
// Value item: config row (unit + polarity selects)
.pf-metrics-v2-value-config {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 4px 0 4px 18px; // Indent to align under column name
> .pf-outlined-field {
flex: 1;
min-width: 100px;
}
}
// "Add value column" dropdown at the bottom of the values panel
.pf-metrics-v2-add-value {
padding: 4px 8px;
border-top: 1px dashed var(--pf-color-border);
> .pf-outlined-field {
width: 100%;
}
}
/// Dimensions item: header is inline, config expands below
.pf-metrics-v2-dim-header {
display: flex;
flex-direction: row;
align-items: center;
gap: 4px;
}
.pf-metrics-v2-dim-config {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 4px 0 4px 18px;
> .pf-outlined-field {
flex: 1;
min-width: 100px;
}
}
// ============================================================================
// Trace Summary node modify view
// ============================================================================
.pf-trace-summary-metric-header {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
}
.pf-trace-summary-metric-badge {
font-size: 11px;
color: var(--md-sys-color-outline);
}
.pf-trace-summary-metric-detail {
display: flex;
flex-direction: column;
gap: 6px;
padding: 4px 0;
}
.pf-trace-summary-detail-row {
display: flex;
gap: 8px;
align-items: baseline;
flex-wrap: wrap;
}
.pf-trace-summary-detail-label {
font-weight: 500;
font-size: 11px;
color: var(--md-sys-color-outline);
min-width: 70px;
text-transform: uppercase;
}
.pf-trace-summary-detail-none {
color: var(--md-sys-color-outline);
font-style: italic;
}
.pf-trace-summary-value-item {
display: flex;
align-items: center;
gap: 8px;
padding-left: 78px;
}
.pf-trace-summary-value-meta {
font-size: 11px;
color: var(--md-sys-color-outline);
}