Skip to content

Commit 389b487

Browse files
committed
Add required flag to DIVE_PARAM
Pipelines can now mark a DIVE_PARAM as required by adding `required` as one of the type props in the comment header: # DIVE_PARAM ["My label", float, required] :my:key = 0.5 The parser strips it from `type_props` and sets `required: true` on the param. PipelineParamsDialog shows a red `*` on the label and blocks the Run button via vuetify form validation if the field is empty. Both the desktop common.ts parser and the server pipeline_discovery.py parser handle the keyword.
1 parent 77c22de commit 389b487

5 files changed

Lines changed: 35 additions & 12 deletions

File tree

client/dive-common/apispec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ interface DiveParam {
4242
type_props?: string[];
4343
key: string;
4444
default: string;
45+
/** True if the user must supply a value before the pipeline can run. */
46+
required?: boolean;
4547
}
4648

4749
interface PipeMetadata {

client/dive-common/components/PipelineParamsDialog.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@ export default defineComponent({
5555
strictlyPositive: (value: string | number) => Number(value) > 0 || 'Please enter a number > 0',
5656
};
5757
58-
function getRules(type: PipelineParamType): ValidationRule[] {
59-
const res = [];
58+
function getRules(type: PipelineParamType, required = false): ValidationRule[] {
59+
const res: ValidationRule[] = [];
60+
if (required) {
61+
res.push((value) => {
62+
if (value === undefined || value === null || value === '') return 'Required';
63+
return true;
64+
});
65+
}
6066
if (type.includes('int')) {
6167
res.push(rules.integer);
6268
}
@@ -131,7 +137,7 @@ export default defineComponent({
131137
:for="`input-${param.key}`"
132138
class="text-caption font-weight-bold text-uppercase text--secondary"
133139
>
134-
{{ param.label }}
140+
{{ param.label }}<span v-if="param.required" class="error--text"> *</span>
135141
</label>
136142
</div>
137143

@@ -157,7 +163,7 @@ export default defineComponent({
157163
hide-details="auto"
158164
class="mt-1"
159165
:min="param.type === 'int' ? 'none' : 0"
160-
:rules="getRules(param.type)"
166+
:rules="getRules(param.type, param.required)"
161167
/>
162168
</template>
163169

@@ -171,7 +177,7 @@ export default defineComponent({
171177
hide-details="auto"
172178
class="mt-1"
173179
:min="param.type === 'float' ? 'none' : 0"
174-
:rules="getRules(param.type)"
180+
:rules="getRules(param.type, param.required)"
175181
/>
176182
</template>
177183

@@ -193,7 +199,7 @@ export default defineComponent({
193199
:min="param.type_props?.at(0) || 0"
194200
:max="param.type_props?.at(1) || 100"
195201
:step="param.type_props?.at(2) || 1"
196-
:rules="getRules(param.type)"
202+
:rules="getRules(param.type, param.required)"
197203
outlined
198204
hide-details
199205
/>
@@ -211,6 +217,7 @@ export default defineComponent({
211217
dense
212218
hide-details="auto"
213219
class="mt-1"
220+
:rules="getRules(param.type, param.required)"
214221
/>
215222
</div>
216223
</v-form>

client/platform/desktop/backend/native/common.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ async function extractPipeMetadata(filePath: string): Promise<PipeMetadata> {
109109
const [, label, rawArgs] = diveMatch;
110110
const args = rawArgs.split(',').map((arg) => arg.trim());
111111
const type: PipelineParamType = args[0] as PipelineParamType;
112-
const pipelineTypeArgs = args.slice(1);
112+
const restArgs = args.slice(1);
113+
// `required` is a flag keyword — strip it from type_props,
114+
// everything else stays positional for the type.
115+
const isRequired = restArgs.some((a) => a.toLowerCase() === 'required');
116+
const pipelineTypeArgs = restArgs.filter((a) => a.toLowerCase() !== 'required');
113117

114118
const paramLineMatch = trimmed.match(/^(?:relativepath\s+)?(?::)?([\w:-]+)\s*=?\s*([^#]+)/i);
115119
if (paramLineMatch) {
@@ -122,6 +126,7 @@ async function extractPipeMetadata(filePath: string): Promise<PipeMetadata> {
122126
type_props: pipelineTypeArgs,
123127
key: fullKey,
124128
default: defaultValue,
129+
...(isRequired ? { required: true } : {}),
125130
});
126131
}
127132
}

server/dive_tasks/pipeline_discovery.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ def extract_pipe_metadata(file_path: Path) -> PipeMetadata:
7272
label, raw_args = dive_match.groups()
7373
args = [arg.strip() for arg in raw_args.split(',')]
7474
param_type = args[0]
75-
pipeline_type_args = args[1:]
75+
rest_args = args[1:]
76+
# `required` is a flag keyword — strip it from type_props,
77+
# everything else stays positional for the type.
78+
is_required = any(a.lower() == 'required' for a in rest_args)
79+
pipeline_type_args = [a for a in rest_args if a.lower() != 'required']
7680

7781
param_line_match = re.match(r'^(?:relativepath\s+)?(?::)?([\w:-]+)\s*=?\s*([^#]+)', trimmed,
7882
re.IGNORECASE)
@@ -81,13 +85,16 @@ def extract_pipe_metadata(file_path: Path) -> PipeMetadata:
8185
default_val = param_line_match.group(2).strip()
8286
full_key = ":".join(context_stack + [local_key])
8387

84-
metadata["diveParams"].append({
88+
param_dict = {
8589
"label": label,
8690
"type": param_type,
8791
"type_props": pipeline_type_args,
8892
"key": full_key,
89-
"default": default_val
90-
})
93+
"default": default_val,
94+
}
95+
if is_required:
96+
param_dict["required"] = True
97+
metadata["diveParams"].append(param_dict)
9198

9299
# --- Description extraction (Multiline) ---
93100
desc_start_match = re.match(r'^#\s*Description:\s*(.*)', line_raw, re.IGNORECASE)

server/dive_utils/types.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,14 @@ class Config:
5959
extra = 'forbid'
6060

6161

62-
class DiveParam(TypedDict):
62+
class DiveParam(TypedDict, total=False):
6363
label: str
6464
type: str
6565
type_props: list[str]
6666
key: str
6767
default: str
68+
# True if the pipeline can't run until the user supplies a value
69+
required: bool
6870

6971

7072
class PipeMetadata(TypedDict):

0 commit comments

Comments
 (0)