writer 1.23.0rc6__py3-none-any.whl → 1.26.0rc3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- writer/ai/__init__.py +39 -1
- writer/blocks/__init__.py +2 -0
- writer/blocks/sharedblueprint.py +86 -0
- writer/blueprints.py +57 -64
- writer/journal.py +96 -38
- writer/static/assets/BaseMarkdown-C7JpFNzG.js +1 -0
- writer/static/assets/BlueprintToolbar-Qq1M1yPa.js +1 -0
- writer/static/assets/{BlueprintToolbar-BSIwpBPp.css → BlueprintToolbar-wpfX0jo_.css} +1 -1
- writer/static/assets/{BuilderApp-Df1h8-Eo.js → BuilderApp-CVdXjiyA.js} +3 -3
- writer/static/assets/{BuilderApplicationSelect-C112wzDI.js → BuilderApplicationSelect-BJ3WU4j8.js} +2 -2
- writer/static/assets/BuilderBlueprintLibraryPanel-BB2BzDiO.js +1 -0
- writer/static/assets/BuilderBlueprintLibraryPanel-qrkMQJpE.css +1 -0
- writer/static/assets/{BuilderEmbeddedCodeEditor-DG2PsuIn.js → BuilderEmbeddedCodeEditor-Bp4akO9H.js} +6 -6
- writer/static/assets/{BuilderGraphSelect-CZyeW98W.js → BuilderGraphSelect-DqqflOEF.js} +2 -2
- writer/static/assets/{BuilderInsertionLabel-CdV8k3Zg.js → BuilderInsertionLabel-DcnE9VFH.js} +1 -1
- writer/static/assets/{BuilderInsertionOverlay-DH0Erxyl.js → BuilderInsertionOverlay-CVXHfCDG.js} +1 -1
- writer/static/assets/BuilderJournal-BkdpDeUE.js +7 -0
- writer/static/assets/{BuilderJournal-DAQcshng.css → BuilderJournal-DHv3Pvvm.css} +1 -1
- writer/static/assets/{BuilderModelSelect-Bpt2wAoy.js → BuilderModelSelect-B3mOzDst.js} +2 -2
- writer/static/assets/BuilderSettings-7A3iq6cl.js +16 -0
- writer/static/assets/{BuilderSettings-BDCWmj-0.css → BuilderSettings-BN0g4wlH.css} +1 -1
- writer/static/assets/{BuilderSettingsArtifactAPITriggerDetails-Ce77KBfh.js → BuilderSettingsArtifactAPITriggerDetails-FkIt0kMq.js} +1 -1
- writer/static/assets/BuilderSettingsDeploySharedBlueprint-BdDSjNAL.css +1 -0
- writer/static/assets/BuilderSettingsDeploySharedBlueprint-BuSxeIj-.js +1 -0
- writer/static/assets/BuilderSettingsHandlers-DbeF71aV.js +1 -0
- writer/static/assets/BuilderSidebarComponentTree-C14x1rVr.js +1 -0
- writer/static/assets/BuilderSidebarComponentTree-DYu1F793.css +1 -0
- writer/static/assets/BuilderSidebarToolkit-CwqbjRv8.css +1 -0
- writer/static/assets/BuilderSidebarToolkit-jy_A1o9f.js +7 -0
- writer/static/assets/{BuilderTemplateEditor-C0IFlyo0.js → BuilderTemplateEditor-BIgBS6qi.js} +1 -1
- writer/static/assets/BuilderVault-BgiAbw0w.js +1 -0
- writer/static/assets/{ComponentRenderer-DQTge-u5.js → ComponentRenderer-BJGX_6iU.js} +1 -1
- writer/static/assets/{SharedCopyClipboardButton-DLDKJqmO.js → SharedCopyClipboardButton-ed8bYNvB.js} +1 -1
- writer/static/assets/{WdsCheckbox-DyaMkyjM.js → WdsCheckbox-BYGFbKQr.js} +1 -1
- writer/static/assets/{WdsDropdownMenu-1kTugbx4.js → WdsDropdownMenu-C1nXnj7Y.js} +1 -1
- writer/static/assets/WdsFieldWrapper-DUvtHQhU.js +1 -0
- writer/static/assets/{WdsTabs-cGyj5MvP.js → WdsTabs-D3_pIGba.js} +1 -1
- writer/static/assets/{cssMode-BNzP_LTj.js → cssMode-4RB2gbaz.js} +1 -1
- writer/static/assets/{freemarker2-3oFbujgY.js → freemarker2-DTEq8jtt.js} +1 -1
- writer/static/assets/{handlebars-tosvcMfZ.js → handlebars-Bgenl5pg.js} +1 -1
- writer/static/assets/{html-C40vkof5.js → html-bSIJxImc.js} +1 -1
- writer/static/assets/{htmlMode-IleWCzJi.js → htmlMode-DIJZeCM_.js} +1 -1
- writer/static/assets/{index-DOMal5wc.css → index-BKNuk68o.css} +1 -1
- writer/static/assets/{index-D7Q_1TlJ.js → index-BO2lDBxy.js} +1 -1
- writer/static/assets/{index-522ZtJjE.js → index-CStxQ_Zn.js} +1 -1
- writer/static/assets/{index-Bz7k91zI.js → index-Tfvjt7wd.js} +1684 -1684
- writer/static/assets/{javascript-B93kRLOk.js → javascript-DEKuJ5Kr.js} +1 -1
- writer/static/assets/{jsonMode-BvzFLYFi.js → jsonMode-P6mvp974.js} +1 -1
- writer/static/assets/{liquid-DUum66og.js → liquid-CLV-Oo7T.js} +1 -1
- writer/static/assets/{mapbox-gl-CxU14gUr.js → mapbox-gl-DBM-6gcD.js} +1 -1
- writer/static/assets/{mdx-dIi1xsKV.js → mdx-D9lLpWK9.js} +1 -1
- writer/static/assets/{pdf-C6_Z6EhB.js → pdf-Car1WtOr.js} +1 -1
- writer/static/assets/{plotly.min-B2Fen0AF.js → plotly.min-B_7RxSHC.js} +1 -1
- writer/static/assets/{python-DbQOvIm1.js → python-CKNDy5FF.js} +1 -1
- writer/static/assets/{razor-BmVb2CjQ.js → razor-Hz0J-1ka.js} +1 -1
- writer/static/assets/{tsMode-CA0I8nL6.js → tsMode-CNnhj71T.js} +1 -1
- writer/static/assets/{typescript-DZ0ESF3e.js → typescript-DBSqcEcy.js} +1 -1
- writer/static/assets/{useBlueprintRun-DSOR9GMr.js → useBlueprintRun-BfljCQFl.js} +1 -1
- writer/static/assets/useKeyValueEditor-D9cp0yxU.js +1 -0
- writer/static/assets/{useListResources-yMzGtfQ-.js → useListResources-Dz7zv-sv.js} +1 -1
- writer/static/assets/{xml-C_vN9YaG.js → xml-9fwRtLLU.js} +1 -1
- writer/static/assets/{yaml-CkZwQHIk.js → yaml-COXu8O5A.js} +1 -1
- writer/static/index.html +2 -2
- {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/METADATA +2 -2
- {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/RECORD +69 -64
- writer/static/assets/BaseMarkdown-CkzyohPW.js +0 -1
- writer/static/assets/BlueprintToolbar-Beg4BHcc.js +0 -1
- writer/static/assets/BuilderJournal-Cyr5afZb.js +0 -7
- writer/static/assets/BuilderSettings-oKMwMRAY.js +0 -16
- writer/static/assets/BuilderSettingsHandlers-B3yTZdYU.js +0 -1
- writer/static/assets/BuilderSidebarComponentTree-C5AMKQcR.css +0 -1
- writer/static/assets/BuilderSidebarComponentTree-l1fr5tUm.js +0 -1
- writer/static/assets/BuilderSidebarToolkit-OFxghtWy.css +0 -1
- writer/static/assets/BuilderSidebarToolkit-iUsHlK39.js +0 -1
- writer/static/assets/BuilderVault-CaBwjxyR.js +0 -1
- writer/static/assets/useComponentDescription-CI_QLr37.js +0 -1
- writer/static/assets/useKeyValueEditor-DctSXoZx.js +0 -1
- /writer/static/assets/{useKeyValueEditor-CsemOh8D.css → WdsFieldWrapper-CsemOh8D.css} +0 -0
- {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/WHEEL +0 -0
- {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/entry_points.txt +0 -0
- {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/licenses/LICENSE.txt +0 -0
writer/ai/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
from contextvars import ContextVar
|
|
4
4
|
from datetime import datetime
|
|
5
|
+
from functools import wraps
|
|
5
6
|
from typing import (
|
|
6
7
|
Any,
|
|
7
8
|
Callable,
|
|
@@ -13,6 +14,7 @@ from typing import (
|
|
|
13
14
|
Optional,
|
|
14
15
|
Set,
|
|
15
16
|
TypedDict,
|
|
17
|
+
TypeVar,
|
|
16
18
|
Union,
|
|
17
19
|
cast,
|
|
18
20
|
)
|
|
@@ -20,7 +22,7 @@ from uuid import uuid4
|
|
|
20
22
|
|
|
21
23
|
from httpx import Timeout
|
|
22
24
|
from writerai import DefaultHttpxClient, Writer
|
|
23
|
-
from writerai._exceptions import WriterError
|
|
25
|
+
from writerai._exceptions import BadRequestError, WriterError
|
|
24
26
|
from writerai._response import BinaryAPIResponse
|
|
25
27
|
from writerai._streaming import Stream
|
|
26
28
|
from writerai._types import Body, Headers, NotGiven, Query
|
|
@@ -1041,6 +1043,39 @@ def delete_file(
|
|
|
1041
1043
|
return files.delete(file_id, **config)
|
|
1042
1044
|
|
|
1043
1045
|
|
|
1046
|
+
class GuardrailError(Exception):
|
|
1047
|
+
def __init__(self, name: str, message: str, *args):
|
|
1048
|
+
super().__init__(f"{message}: {name}", *args)
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
R = TypeVar("R")
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
def catch_guardrail_error(func: Callable[..., R]) -> Callable[..., R]:
|
|
1055
|
+
@wraps(func)
|
|
1056
|
+
def wrapper(*args: Any, **kwargs: Any) -> R:
|
|
1057
|
+
try:
|
|
1058
|
+
return func(*args, **kwargs)
|
|
1059
|
+
except BadRequestError as e:
|
|
1060
|
+
parsed = e.response.json()
|
|
1061
|
+
errors = parsed.get("errors")
|
|
1062
|
+
if not errors:
|
|
1063
|
+
raise
|
|
1064
|
+
|
|
1065
|
+
extras = parsed.get("extras")
|
|
1066
|
+
if extras is None:
|
|
1067
|
+
raise
|
|
1068
|
+
guardrail_info = extras.get("guardrail_info")
|
|
1069
|
+
if guardrail_info is None:
|
|
1070
|
+
raise
|
|
1071
|
+
|
|
1072
|
+
raise GuardrailError(
|
|
1073
|
+
name=guardrail_info["guardrail_name"],
|
|
1074
|
+
message=errors[0]["description"],
|
|
1075
|
+
) from None
|
|
1076
|
+
|
|
1077
|
+
return wrapper
|
|
1078
|
+
|
|
1044
1079
|
class Conversation:
|
|
1045
1080
|
"""
|
|
1046
1081
|
Manages messages within a conversation flow with an AI system,
|
|
@@ -1848,6 +1883,7 @@ class Conversation:
|
|
|
1848
1883
|
|
|
1849
1884
|
self.__add__({"role": role, "content": content})
|
|
1850
1885
|
|
|
1886
|
+
@catch_guardrail_error
|
|
1851
1887
|
def _send_chat_request(
|
|
1852
1888
|
self,
|
|
1853
1889
|
request_model: str,
|
|
@@ -2918,6 +2954,7 @@ class Tools:
|
|
|
2918
2954
|
return result.entities
|
|
2919
2955
|
|
|
2920
2956
|
|
|
2957
|
+
@catch_guardrail_error
|
|
2921
2958
|
def complete(
|
|
2922
2959
|
initial_text: str,
|
|
2923
2960
|
config: Optional['CreateOptions'] = None
|
|
@@ -2964,6 +3001,7 @@ def complete(
|
|
|
2964
3001
|
f"{response_data}")
|
|
2965
3002
|
|
|
2966
3003
|
|
|
3004
|
+
@catch_guardrail_error
|
|
2967
3005
|
def stream_complete(
|
|
2968
3006
|
initial_text: str,
|
|
2969
3007
|
config: Optional['CreateOptions'] = None
|
writer/blocks/__init__.py
CHANGED
|
@@ -12,6 +12,7 @@ from writer.blocks.parsejson import ParseJSON
|
|
|
12
12
|
from writer.blocks.returnvalue import ReturnValue
|
|
13
13
|
from writer.blocks.runblueprint import RunBlueprint
|
|
14
14
|
from writer.blocks.setstate import SetState
|
|
15
|
+
from writer.blocks.sharedblueprint import SharedBlueprint
|
|
15
16
|
from writer.blocks.uieventtrigger import UIEventTrigger
|
|
16
17
|
from writer.blocks.writeraddchatmessage import WriterAddChatMessage
|
|
17
18
|
from writer.blocks.writeraddtokg import WriterAddToKG
|
|
@@ -63,3 +64,4 @@ WriterVision.register("blueprints_writervision")
|
|
|
63
64
|
WriterWebSearch.register("blueprints_writerwebsearch")
|
|
64
65
|
WriterKeyValueStorage.register("blueprints_writerkeyvaluestorage")
|
|
65
66
|
WriterChatReplyWithToolConfig.register("blueprints_writerchatreplywithtoolconfig")
|
|
67
|
+
SharedBlueprint.register("blueprints_shared")
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared blueprint implementation for user-created reusable blueprints.
|
|
3
|
+
|
|
4
|
+
Shared blueprints execute stored blueprint components by loading them from the component tree.
|
|
5
|
+
The component's content.sourceBlueprintId field references the source blueprint.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from writer.abstract import register_abstract_template
|
|
9
|
+
from writer.blocks.base_block import BlueprintBlock
|
|
10
|
+
from writer.ss_types import AbstractTemplate
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SharedBlueprint(BlueprintBlock):
|
|
14
|
+
"""
|
|
15
|
+
Shared blueprint that executes components from a source blueprint in the component tree.
|
|
16
|
+
|
|
17
|
+
The source blueprint is identified by the sourceBlueprintId content field.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def register(cls, type: str):
|
|
22
|
+
"""Register the blueprints_shared type with its abstract template."""
|
|
23
|
+
super(SharedBlueprint, cls).register(type)
|
|
24
|
+
register_abstract_template(
|
|
25
|
+
type,
|
|
26
|
+
AbstractTemplate(
|
|
27
|
+
baseType="blueprints_node",
|
|
28
|
+
writer={
|
|
29
|
+
"name": "Shared Blueprint",
|
|
30
|
+
"description": "Executes a shared blueprint from the component tree.",
|
|
31
|
+
"category": "Logic",
|
|
32
|
+
"toolkit": "blueprints",
|
|
33
|
+
"featureFlags": ["shared_blueprints"],
|
|
34
|
+
"fields": {
|
|
35
|
+
"payload": {
|
|
36
|
+
"name": "Payload",
|
|
37
|
+
"desc": "The value specified will be available using the template syntax, e.g. @{payload}.",
|
|
38
|
+
"default": "{}",
|
|
39
|
+
"type": "Text",
|
|
40
|
+
"control": "Textarea",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
"outs": {
|
|
44
|
+
"success": {
|
|
45
|
+
"name": "Success",
|
|
46
|
+
"description": "Blueprint executed successfully.",
|
|
47
|
+
"style": "success",
|
|
48
|
+
},
|
|
49
|
+
"error": {
|
|
50
|
+
"name": "Error",
|
|
51
|
+
"description": "Blueprint execution failed.",
|
|
52
|
+
"style": "error",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def run(self):
|
|
60
|
+
"""Execute the source blueprint's components."""
|
|
61
|
+
source_blueprint_id = self.component.content.get("sourceBlueprintId", "")
|
|
62
|
+
|
|
63
|
+
if not source_blueprint_id:
|
|
64
|
+
raise ValueError("No source blueprint ID specified")
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
payload = self._get_field("payload")
|
|
68
|
+
expanded_execution_environment = self.execution_environment | {"payload": payload}
|
|
69
|
+
|
|
70
|
+
# Get blueprint name for title (matching run_blueprint_by_key pattern)
|
|
71
|
+
source_blueprint = self.runner.session.session_component_tree.get_component(
|
|
72
|
+
source_blueprint_id
|
|
73
|
+
)
|
|
74
|
+
blueprint_name = source_blueprint.content.get("key", "Shared Blueprint") if source_blueprint else "Shared Blueprint"
|
|
75
|
+
|
|
76
|
+
return_value = self.runner.run_blueprint(
|
|
77
|
+
source_blueprint_id,
|
|
78
|
+
expanded_execution_environment,
|
|
79
|
+
title=f"Shared blueprint execution ({blueprint_name})"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self.result = return_value
|
|
83
|
+
self.outcome = "success"
|
|
84
|
+
except BaseException as e:
|
|
85
|
+
self.outcome = "error"
|
|
86
|
+
raise e
|
writer/blueprints.py
CHANGED
|
@@ -8,13 +8,13 @@ import time
|
|
|
8
8
|
from concurrent.futures import FIRST_COMPLETED, Future, ThreadPoolExecutor, wait
|
|
9
9
|
from contextlib import contextmanager
|
|
10
10
|
from contextvars import ContextVar, copy_context
|
|
11
|
-
from typing import Any, Dict, Generator, List, Literal, Optional,
|
|
11
|
+
from typing import Any, Dict, Generator, List, Literal, Optional, Union
|
|
12
12
|
|
|
13
13
|
import writer.blocks
|
|
14
14
|
import writer.blocks.base_block
|
|
15
15
|
import writer.core
|
|
16
16
|
import writer.core_ui
|
|
17
|
-
from writer.journal import
|
|
17
|
+
from writer.journal import use_journal_record_context
|
|
18
18
|
from writer.ss_types import BlueprintExecutionError, BlueprintExecutionLog, WriterConfigurationError
|
|
19
19
|
|
|
20
20
|
MAX_DAG_DEPTH = 32
|
|
@@ -750,68 +750,61 @@ class GraphRunner:
|
|
|
750
750
|
return self._execute(executor, event)
|
|
751
751
|
|
|
752
752
|
def _execute(self, executor: ThreadPoolExecutor, abort_event: threading.Event) -> Optional[Any]:
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
if
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
next_node = self.graph.get_node(to_node_id)
|
|
809
|
-
if next_node:
|
|
810
|
-
self.queue.append(next_node)
|
|
811
|
-
|
|
812
|
-
self.status_logger.log("Execution completed.", entry_type="info", exit="completed")
|
|
813
|
-
journal_record.save(result="success")
|
|
814
|
-
return None
|
|
753
|
+
with use_journal_record_context(self.execution_environment, self.status_logger.title, self.graph) as journal_record:
|
|
754
|
+
while self.queue or self.futures:
|
|
755
|
+
while self.queue:
|
|
756
|
+
node: GraphNode = self.queue.pop(0)
|
|
757
|
+
if node.can_run() and node.outcome is None:
|
|
758
|
+
self.futures.append(node.run(self.execution_environment, self.runner, executor))
|
|
759
|
+
|
|
760
|
+
self.status_logger.log("Executing...")
|
|
761
|
+
done, _ = wait(self.futures, timeout=self.CANCELATION_CHECK_INTERVAL, return_when=FIRST_COMPLETED)
|
|
762
|
+
if not done:
|
|
763
|
+
if abort_event.is_set():
|
|
764
|
+
self._cancel_all_jobs()
|
|
765
|
+
self.status_logger.log("Terminated.", entry_type="info", exit="aborted")
|
|
766
|
+
journal_record.set_result("stopped")
|
|
767
|
+
return None
|
|
768
|
+
else:
|
|
769
|
+
continue
|
|
770
|
+
self.status_logger.log("Executing...")
|
|
771
|
+
for future in done:
|
|
772
|
+
if future in self.futures:
|
|
773
|
+
self.futures.remove(future)
|
|
774
|
+
try:
|
|
775
|
+
result_node: GraphNode = future.result()
|
|
776
|
+
except BlueprintExecutionError as e:
|
|
777
|
+
self._cancel_all_jobs()
|
|
778
|
+
self.status_logger.log("Execution failed", entry_type="error", exit=str(e))
|
|
779
|
+
raise e
|
|
780
|
+
except BaseException as e:
|
|
781
|
+
abort_event.set()
|
|
782
|
+
self._cancel_all_jobs()
|
|
783
|
+
self.status_logger.log("Execution failed.", entry_type="error", exit=str(e))
|
|
784
|
+
raise BlueprintExecutionError(
|
|
785
|
+
f"Blueprint execution was stopped due to an error - {e.__class__.__name__}: {e}"
|
|
786
|
+
) from e
|
|
787
|
+
if result_node.outcome == "stopped":
|
|
788
|
+
continue
|
|
789
|
+
if result_node.return_value is not None:
|
|
790
|
+
self._cancel_local_jobs()
|
|
791
|
+
self.status_logger.log(
|
|
792
|
+
f"Execution completed, node {result_node.id} returned value: {result_node.return_value}",
|
|
793
|
+
entry_type="info",
|
|
794
|
+
exit="return"
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
journal_record.set_result("success")
|
|
798
|
+
return result_node.return_value
|
|
799
|
+
for output in result_node.outputs:
|
|
800
|
+
to_node_id = output.get("toNodeId")
|
|
801
|
+
next_node = self.graph.get_node(to_node_id)
|
|
802
|
+
if next_node:
|
|
803
|
+
self.queue.append(next_node)
|
|
804
|
+
|
|
805
|
+
self.status_logger.log("Execution completed.", entry_type="info", exit="completed")
|
|
806
|
+
journal_record.set_result("success")
|
|
807
|
+
return None
|
|
815
808
|
|
|
816
809
|
def _cancel_local_jobs(self):
|
|
817
810
|
self.queue.clear()
|
writer/journal.py
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
import json
|
|
2
3
|
import logging
|
|
4
|
+
from contextvars import ContextVar
|
|
5
|
+
from copy import deepcopy
|
|
3
6
|
from datetime import datetime, timezone
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Dict, Literal
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict, Literal, Optional
|
|
5
8
|
|
|
6
9
|
import writer.abstract
|
|
7
10
|
from writer.core import Config
|
|
8
11
|
from writer.keyvalue_storage import writer_kv_storage
|
|
9
12
|
|
|
10
13
|
if TYPE_CHECKING:
|
|
11
|
-
from writer.blueprints import Graph
|
|
14
|
+
from writer.blueprints import Graph, GraphNode
|
|
12
15
|
from writer.core import Component
|
|
13
16
|
|
|
14
17
|
|
|
@@ -33,6 +36,7 @@ class JournalRecord:
|
|
|
33
36
|
# All nodes in a blueprint share the same parent blueprint component
|
|
34
37
|
self.blueprint_id = graph.nodes[0].component.parentId if graph.nodes else None
|
|
35
38
|
|
|
39
|
+
self.execution_environment = execution_environment
|
|
36
40
|
self.trigger = {
|
|
37
41
|
"event": execution_environment.get("context", {}).get("event"),
|
|
38
42
|
"payload": execution_environment.get("payload"),
|
|
@@ -61,12 +65,26 @@ class JournalRecord:
|
|
|
61
65
|
self.trigger["type"] = "On demand"
|
|
62
66
|
|
|
63
67
|
self.graph = graph
|
|
68
|
+
self.block_outputs: Dict[str, Any] = {}
|
|
69
|
+
for graph_node in self.graph.nodes:
|
|
70
|
+
block_info = self._get_block_info(graph_node.component)
|
|
71
|
+
self.block_outputs[graph_node.id] = {
|
|
72
|
+
"component": {
|
|
73
|
+
"type": graph_node.component.type,
|
|
74
|
+
"id": graph_node.component.id,
|
|
75
|
+
"title": block_info["title"],
|
|
76
|
+
"category": block_info["category"]
|
|
77
|
+
},
|
|
78
|
+
"executions": []
|
|
79
|
+
}
|
|
80
|
+
|
|
64
81
|
self.is_runable = True
|
|
82
|
+
self.result: Optional[Literal["success", "error", "stopped"]] = None
|
|
65
83
|
|
|
66
84
|
def _get_block_info(self, component: "Component") -> Dict[str, str]:
|
|
67
85
|
block_title = component.content.get("alias")
|
|
68
86
|
component_definition = writer.abstract.templates.get(component.type)
|
|
69
|
-
|
|
87
|
+
|
|
70
88
|
# If component has an alias, use it as title
|
|
71
89
|
if block_title is not None:
|
|
72
90
|
category = "Unknown category"
|
|
@@ -76,7 +94,7 @@ class JournalRecord:
|
|
|
76
94
|
"title": block_title,
|
|
77
95
|
"category": category
|
|
78
96
|
}
|
|
79
|
-
|
|
97
|
+
|
|
80
98
|
# If no component definition found, return defaults
|
|
81
99
|
if component_definition is None:
|
|
82
100
|
return {
|
|
@@ -91,39 +109,9 @@ class JournalRecord:
|
|
|
91
109
|
}
|
|
92
110
|
|
|
93
111
|
def to_dict(self) -> Dict[str, Any]:
|
|
94
|
-
block_outputs =
|
|
112
|
+
block_outputs = deepcopy(self.block_outputs)
|
|
95
113
|
for graph_node in self.graph.nodes:
|
|
96
|
-
|
|
97
|
-
block_data: Dict[str, Any] = {
|
|
98
|
-
"result": graph_node.result,
|
|
99
|
-
"outcome": graph_node.outcome,
|
|
100
|
-
"component": {
|
|
101
|
-
"type": graph_node.component.type,
|
|
102
|
-
"id": graph_node.component.id,
|
|
103
|
-
"title": block_info["title"],
|
|
104
|
-
"category": block_info["category"]
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
# Add timing information if available
|
|
109
|
-
if graph_node.tool:
|
|
110
|
-
if hasattr(graph_node.tool, 'started_at') and graph_node.tool.started_at >= 0:
|
|
111
|
-
block_data["startedAt"] = graph_node.tool.started_at
|
|
112
|
-
if hasattr(graph_node.tool, 'execution_time_in_seconds') and graph_node.tool.execution_time_in_seconds >= 0:
|
|
113
|
-
block_data["executionTimeInSeconds"] = graph_node.tool.execution_time_in_seconds
|
|
114
|
-
|
|
115
|
-
# Add captured logs if available
|
|
116
|
-
if hasattr(graph_node.tool, 'captured_stdout') and graph_node.tool.captured_stdout:
|
|
117
|
-
block_data["stdout"] = graph_node.tool.captured_stdout
|
|
118
|
-
if hasattr(graph_node.tool, 'captured_logs') and graph_node.tool.captured_logs:
|
|
119
|
-
block_data["logs"] = graph_node.tool.captured_logs
|
|
120
|
-
|
|
121
|
-
# Add error message if available (contains the traceback for errors)
|
|
122
|
-
if hasattr(graph_node.tool, 'message') and graph_node.tool.message:
|
|
123
|
-
block_data["message"] = graph_node.tool.message
|
|
124
|
-
|
|
125
|
-
block_outputs[graph_node.id] = block_data
|
|
126
|
-
|
|
114
|
+
block_outputs[graph_node.id]["executions"].append(self.get_execution_data(graph_node))
|
|
127
115
|
|
|
128
116
|
data = {
|
|
129
117
|
"timestamp": self.started_at.isoformat(),
|
|
@@ -131,6 +119,7 @@ class JournalRecord:
|
|
|
131
119
|
"blueprintId": self.blueprint_id,
|
|
132
120
|
"trigger": self.trigger,
|
|
133
121
|
"blockOutputs": block_outputs,
|
|
122
|
+
"result": self.result,
|
|
134
123
|
}
|
|
135
124
|
sanitized_data = self._sanitize_data(data)
|
|
136
125
|
return {
|
|
@@ -138,6 +127,31 @@ class JournalRecord:
|
|
|
138
127
|
"isRunable": self.is_runable,
|
|
139
128
|
}
|
|
140
129
|
|
|
130
|
+
def get_execution_data(self, graph_node: "GraphNode") -> Dict[str, Any]:
|
|
131
|
+
execution_data: Dict[str, Any] = {
|
|
132
|
+
"result": graph_node.result,
|
|
133
|
+
"outcome": graph_node.outcome,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Add timing information if available
|
|
137
|
+
if graph_node.tool:
|
|
138
|
+
if hasattr(graph_node.tool, 'started_at') and graph_node.tool.started_at >= 0:
|
|
139
|
+
execution_data["startedAt"] = graph_node.tool.started_at
|
|
140
|
+
if hasattr(graph_node.tool, 'execution_time_in_seconds') and graph_node.tool.execution_time_in_seconds >= 0:
|
|
141
|
+
execution_data["executionTimeInSeconds"] = graph_node.tool.execution_time_in_seconds
|
|
142
|
+
|
|
143
|
+
# Add captured logs if available
|
|
144
|
+
if hasattr(graph_node.tool, 'captured_stdout') and graph_node.tool.captured_stdout:
|
|
145
|
+
execution_data["stdout"] = graph_node.tool.captured_stdout
|
|
146
|
+
if hasattr(graph_node.tool, 'captured_logs') and graph_node.tool.captured_logs:
|
|
147
|
+
execution_data["logs"] = graph_node.tool.captured_logs
|
|
148
|
+
|
|
149
|
+
# Add error message if available (contains the traceback for errors)
|
|
150
|
+
if hasattr(graph_node.tool, 'message') and graph_node.tool.message:
|
|
151
|
+
execution_data["message"] = graph_node.tool.message
|
|
152
|
+
|
|
153
|
+
return execution_data
|
|
154
|
+
|
|
141
155
|
def _sanitize_data(self, data):
|
|
142
156
|
if data is None:
|
|
143
157
|
return None
|
|
@@ -161,9 +175,53 @@ class JournalRecord:
|
|
|
161
175
|
def construct_key(self) -> str:
|
|
162
176
|
return f"{JOURNAL_KEY_PREFIX}{self.instance_type[0]}-{int(self.started_at.timestamp() * 1000)}"
|
|
163
177
|
|
|
164
|
-
def
|
|
178
|
+
def set_result(self, result: Literal["success", "error", "stopped"]) -> None:
|
|
179
|
+
self.result = result
|
|
180
|
+
|
|
181
|
+
def add_nested_execution(self, nested_record: "JournalRecord") -> None:
|
|
182
|
+
for graph_node in nested_record.graph.nodes:
|
|
183
|
+
if graph_node.id not in self.block_outputs:
|
|
184
|
+
self.block_outputs[graph_node.id] = nested_record.block_outputs[graph_node.id]
|
|
185
|
+
self.block_outputs[graph_node.id]["executions"].append(nested_record.get_execution_data(graph_node))
|
|
186
|
+
|
|
187
|
+
def save(self) -> None:
|
|
165
188
|
if "journal" not in Config.feature_flags or not writer_kv_storage.is_accessible():
|
|
166
189
|
return
|
|
167
190
|
data = self.to_dict()
|
|
168
|
-
data["result"] = result
|
|
169
191
|
writer_kv_storage.save(self.construct_key(), data)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
_parent_journal_record: ContextVar[Optional[JournalRecord]] = ContextVar("parent_journal_record", default=None)
|
|
195
|
+
_current_journal_record: ContextVar[Optional[JournalRecord]] = ContextVar("current_journal_record", default=None)
|
|
196
|
+
|
|
197
|
+
@contextlib.contextmanager
|
|
198
|
+
def use_journal_record_context(
|
|
199
|
+
execution_environment: Dict,
|
|
200
|
+
title: str,
|
|
201
|
+
graph: "Graph"
|
|
202
|
+
):
|
|
203
|
+
parent_record = _parent_journal_record.get()
|
|
204
|
+
current_record = JournalRecord(execution_environment, title, graph)
|
|
205
|
+
_current_journal_record.set(current_record)
|
|
206
|
+
if parent_record is None:
|
|
207
|
+
_parent_journal_record.set(current_record)
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
yield current_record
|
|
211
|
+
except BaseException as e:
|
|
212
|
+
current_record.set_result("error")
|
|
213
|
+
raise e
|
|
214
|
+
finally:
|
|
215
|
+
_current_journal_record.set(None)
|
|
216
|
+
if parent_record is not None:
|
|
217
|
+
parent_record.add_nested_execution(current_record)
|
|
218
|
+
else:
|
|
219
|
+
try:
|
|
220
|
+
current_record.save()
|
|
221
|
+
except Exception:
|
|
222
|
+
logger.exception("Failed to save a Journal entry")
|
|
223
|
+
_parent_journal_record.set(None)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_current_journal_record() -> Optional[JournalRecord]:
|
|
227
|
+
return _current_journal_record.get()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{aV as f}from"./index-Tfvjt7wd.js";export{f as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as E}from"./useBlueprintRun-BfljCQFl.js";import{d as j,c as S,m as I,r as J,aR as M,aS as P,o as c,f as g,g as b,J as N,x as l,y as v,z as _,K as G,R as w,S as A,as as K,G as F,_ as x,i as D,a as $,D as L,E as Y,W as T,t as W,aT as H,Y as Q,b as R,A as z,ae as U}from"./index-Tfvjt7wd.js";const X=["disabled"],Z=["disabled"],tt=j({__name:"WdsButtonSplit",props:{variant:{type:String,default:"primary"},size:{type:String,default:"default"},disabled:{type:Boolean,required:!1}},emits:{mainClick:()=>!0,dropdownOpen:()=>!0,dropdownClose:()=>!0},setup(u,{expose:C,emit:m}){const a=u,d=S(()=>[`WdsButtonSplit--size-${a.size}`,`WdsButtonSplit--variant-${a.variant}`,a.disabled?"WdsButtonSplit--disabled":void 0]),f=m,e=I("btn"),o=I("dropdown"),n=J(!1),{floatingStyles:r}=M(e,o,{placement:"bottom-end",middleware:[P(12)]});function s(B=!n.value){n.value=B,n.value?f("dropdownOpen"):f("dropdownClose")}return C({toggleDropdown:s}),(B,p)=>(c(),g("div",{ref_key:"btn",ref:e,class:F(["WdsButtonSplit",d.value])},[b("button",{type:"button",class:"WdsButtonSplit__main",disabled:u.disabled,onClick:p[0]||(p[0]=y=>B.$emit("mainClick"))},[N(B.$slots,"button",{},void 0,!0)],8,X),p[2]||(p[2]=b("hr",{class:"WdsButtonSplit__divider"},null,-1)),b("button",{class:"WdsButtonSplit__dropdownTrigger",type:"button",disabled:u.disabled,onClickCapture:p[1]||(p[1]=y=>s())},[l(v,{name:n.value?"chevron-up":"chevron-down"},null,8,["name"])],40,Z),l(K,null,{default:_(()=>[n.value?(c(),g("div",{key:0,ref_key:"dropdown",ref:o,style:G(w(r))},[N(B.$slots,"dropdown",{},void 0,!0)],4)):A("",!0)]),_:3})],2))}}),et=x(tt,[["__scopeId","data-v-e9224293"]]),nt={class:"BlueprintToolbarBlocksDropdown"},ot={class:"BlueprintToolbarBlocksDropdown__list"},st={class:"BlueprintToolbarBlocksDropdown__list__item__description"},at={class:"BlueprintToolbarBlocksDropdown__list__item__title"},rt=j({__name:"BlueprintToolbarBlocksDropdown",props:{components:{type:Array,required:!0}},emits:{jumpToComponent:u=>typeof u=="string",runBranch:u=>typeof u=="string"},setup(u){const C=u,m=D($.core);function a(e){const o=m.getComponentDefinition(e.type);return(o==null?void 0:o.name)??e.type}function d(e){if(e.type!=="blueprints_uieventtrigger"||!!e.content.defaultResult)return!0;const n=(e.outs??[]).map(s=>m.getComponentById(s.toNodeId)).flatMap(s=>Object.values(s.content??{}));return n.length===0?!0:!n.some(s=>s.includes("@{result}"))}const f=S(()=>C.components.map(e=>{var s;const o=m.getComponentDefinition(e.type),n=((s=e.content)==null?void 0:s.alias)||a(e),r=(o==null?void 0:o.name)??e.type;return{id:e.id,disabled:!d(e),title:n,description:n===r?void 0:r}}));return(e,o)=>(c(),g("div",nt,[o[0]||(o[0]=b("p",{class:"BlueprintToolbarBlocksDropdown__header"}," Start blueprint from ",-1)),b("div",ot,[(c(!0),g(L,null,Y(f.value,n=>(c(),g("div",{key:n.id,class:F(["BlueprintToolbarBlocksDropdown__list__item",{"BlueprintToolbarBlocksDropdown__list__item--disabled":n.disabled}])},[l(T,{variant:"primary",size:"smallIcon","custom-size":"20px",disabled:n.disabled,"data-writer-tooltip":n.disabled?"Can not run without a default result. Go to this block to define a default result.":"Run the branch",onClick:r=>e.$emit("runBranch",n.id)},{default:_(()=>[l(v,{name:"play"})]),_:2},1032,["disabled","data-writer-tooltip","onClick"]),b("div",null,[b("p",st,W(n.description),1),b("p",at,W(n.title),1)]),l(T,{variant:"neutral",size:"smallIcon","custom-size":"20px","data-writer-tooltip":"Jump to the blueprint",onClick:r=>e.$emit("jumpToComponent",n.id)},{default:_(()=>[l(v,{name:"square-dashed-mouse-pointer"})]),_:2},1032,["onClick"])],2))),128))])]))}}),lt=x(rt,[["__scopeId","data-v-e0d0a711"]]),it={ref:"root",class:"BlueprintToolbar","data-writer-unselectable":!0},ut=j({__name:"BlueprintToolbar",emits:{autogenClick:()=>!0,deploy:()=>!0},setup(u,{emit:C}){const m=C,a=D($.core),d=D($.builderManager),f=D($.componentId),e=I("runBlueprintBtn"),{run:o,stop:n,isRunning:r}=E(a,d,f),s=S(()=>Array.isArray(a.featureFlags.value)&&a.featureFlags.value.includes("blueprint_library")),B=S(()=>{const i=a.getComponentById(f);return H(i)}),p=S(()=>a.getComponents(f).filter(i=>{var t;return((t=a.getComponentDefinition(i.type))==null?void 0:t.category)==="Triggers"})),y=Q([]);function O(){y.value=U(d.selection.value),d.setSelection(null)}function q(){var i;if((i=y.value)!=null&&i.length){d.setSelection(null);for(const t of y.value)d.appendSelection(t.componentId,t.instancePath,t.source);y.value=[]}}function V(i){var t;d.setSelection(i,void 0,"click"),(t=e.value)==null||t.toggleDropdown(!1)}async function h(i){var t;(t=e.value)==null||t.toggleDropdown(!1),await o(i)}return(i,t)=>(c(),g("div",it,[l(T,{variant:"tertiary",size:"icon","data-automation-action":"run-autogen","data-writer-tooltip":"Autogen","data-writer-tooltip-placement":"bottom",onClick:t[0]||(t[0]=k=>m("autogenClick"))},{default:_(()=>[l(v,{name:"wand-sparkles"})]),_:1}),s.value&&B.value?(c(),R(T,{key:0,variant:"special","data-automation-action":"publish-shared-blueprint","data-writer-tooltip":"Publish this shared blueprint","data-writer-tooltip-placement":"bottom",onClick:t[1]||(t[1]=k=>m("deploy"))},{default:_(()=>[l(v,{name:"rocket"}),t[5]||(t[5]=z(" Publish blueprint "))]),_:1})):A("",!0),p.value.length&&!w(r)?(c(),R(et,{key:1,ref_key:"runBlueprintBtn",ref:e,class:"BlueprintToolbar__runBlueprintDropdown",variant:"special",onMainClick:t[3]||(t[3]=k=>h()),onDropdownOpen:O,onDropdownClose:q},{button:_(()=>[l(v,{name:"play"}),t[6]||(t[6]=z(" Run blueprint "))]),dropdown:_(()=>[l(lt,{components:p.value,onJumpToComponent:V,onRunBranch:t[2]||(t[2]=k=>h(k))},null,8,["components"])]),_:1},512)):(c(),R(T,{key:2,class:"BlueprintToolbar__runBlueprint","data-automation-action":"run-blueprint",variant:"special",onClick:t[4]||(t[4]=k=>w(r)?w(n)():h())},{default:_(()=>[l(v,{name:w(r)?"square":"play"},null,8,["name"]),z(" "+W(w(r)?"Stop run":"Run blueprint"),1)]),_:1}))],512))}}),ct=x(ut,[["__scopeId","data-v-5b7eb059"]]);export{ct as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer wf{.WdsButtonSplit[data-v-e9224293]{position:relative;display:flex;border-radius:300px;box-shadow:var(--buttonShadow);border:1px solid transparent;align-items:center;height:40px;gap:8px;padding-left:12px;padding-right:12px}.WdsButtonSplit--disabled[data-v-e9224293]{opacity:40%}.WdsButtonSplit--disabled .WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit--disabled .WdsButtonSplit__main[data-v-e9224293]{cursor:not-allowed}.WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit__main[data-v-e9224293]{background-color:transparent;border:none;cursor:pointer}.WdsButtonSplit__main[data-v-e9224293]{display:flex;align-items:center;justify-content:flex-start;gap:8px;font-weight:600}.WdsButtonSplit__dropdownTrigger[data-v-e9224293]{display:flex;align-items:center;justify-content:center;font-size:20px;border-radius:50%;height:20px;width:20px}.WdsButtonSplit__divider[data-v-e9224293]{display:block;width:1px;height:100%;border:none;height:24px}.WdsButtonSplit--variant-primary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue4)}.WdsButtonSplit--variant-primary[data-v-e9224293],.WdsButtonSplit--variant-primary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-primary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-primary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue6)}.WdsButtonSplit--variant-secondary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray5)}.WdsButtonSplit--variant-secondary[data-v-e9224293],.WdsButtonSplit--variant-secondary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlack)}.WdsButtonSplit--variant-secondary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-secondary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorGray6)}.WdsButtonSplit--variant-tertiary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray2)}.WdsButtonSplit--variant-tertiary[data-v-e9224293],.WdsButtonSplit--variant-tertiary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlack);background:var(--wdsColorWhite)}.WdsButtonSplit--variant-tertiary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-tertiary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{color:var(--wdsColorGray4)}.WdsButtonSplit--variant-special .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-special[data-v-e9224293],.WdsButtonSplit--variant-special .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlue5);background:var(--wdsColorBlue2)}.WdsButtonSplit--variant-special[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-special:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue3)}.WdsButtonSplit--size-default .WdsButtonSplit__main[data-v-e9224293]{font-size:14px}.WdsButtonSplit--size-small .WdsButtonSplit__main[data-v-e9224293]{font-size:12px}}@layer wf{.BlueprintToolbarBlocksDropdown[data-v-e0d0a711]{min-width:185px;border:1px solid var(--wdsColorGray2);border:none;background:#fff;z-index:2;width:100%;max-height:40vh;border-radius:8px;padding:8px 10px;box-shadow:var(--wdsShadowMenu);box-sizing:border-box;color:var(--wdsColorGray6);max-height:300px;overflow-y:auto}.BlueprintToolbarBlocksDropdown__header[data-v-e0d0a711]{font-size:12px;text-transform:uppercase;font-weight:500;margin-bottom:10px}.BlueprintToolbarBlocksDropdown__list[data-v-e0d0a711]{display:flex;flex-direction:column;gap:8px}.BlueprintToolbarBlocksDropdown__list__item[data-v-e0d0a711]{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:16px;align-items:center}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711]{font-weight:400;color:var(--wdsColorGray4)}.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{opacity:50%}}@layer wf{.BlueprintToolbar__runBlueprint[data-v-
|
|
1
|
+
@layer wf{.WdsButtonSplit[data-v-e9224293]{position:relative;display:flex;border-radius:300px;box-shadow:var(--buttonShadow);border:1px solid transparent;align-items:center;height:40px;gap:8px;padding-left:12px;padding-right:12px}.WdsButtonSplit--disabled[data-v-e9224293]{opacity:40%}.WdsButtonSplit--disabled .WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit--disabled .WdsButtonSplit__main[data-v-e9224293]{cursor:not-allowed}.WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit__main[data-v-e9224293]{background-color:transparent;border:none;cursor:pointer}.WdsButtonSplit__main[data-v-e9224293]{display:flex;align-items:center;justify-content:flex-start;gap:8px;font-weight:600}.WdsButtonSplit__dropdownTrigger[data-v-e9224293]{display:flex;align-items:center;justify-content:center;font-size:20px;border-radius:50%;height:20px;width:20px}.WdsButtonSplit__divider[data-v-e9224293]{display:block;width:1px;height:100%;border:none;height:24px}.WdsButtonSplit--variant-primary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue4)}.WdsButtonSplit--variant-primary[data-v-e9224293],.WdsButtonSplit--variant-primary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-primary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-primary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue6)}.WdsButtonSplit--variant-secondary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray5)}.WdsButtonSplit--variant-secondary[data-v-e9224293],.WdsButtonSplit--variant-secondary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlack)}.WdsButtonSplit--variant-secondary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-secondary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorGray6)}.WdsButtonSplit--variant-tertiary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray2)}.WdsButtonSplit--variant-tertiary[data-v-e9224293],.WdsButtonSplit--variant-tertiary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlack);background:var(--wdsColorWhite)}.WdsButtonSplit--variant-tertiary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-tertiary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{color:var(--wdsColorGray4)}.WdsButtonSplit--variant-special .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-special[data-v-e9224293],.WdsButtonSplit--variant-special .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlue5);background:var(--wdsColorBlue2)}.WdsButtonSplit--variant-special[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-special:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue3)}.WdsButtonSplit--size-default .WdsButtonSplit__main[data-v-e9224293]{font-size:14px}.WdsButtonSplit--size-small .WdsButtonSplit__main[data-v-e9224293]{font-size:12px}}@layer wf{.BlueprintToolbarBlocksDropdown[data-v-e0d0a711]{min-width:185px;border:1px solid var(--wdsColorGray2);border:none;background:#fff;z-index:2;width:100%;max-height:40vh;border-radius:8px;padding:8px 10px;box-shadow:var(--wdsShadowMenu);box-sizing:border-box;color:var(--wdsColorGray6);max-height:300px;overflow-y:auto}.BlueprintToolbarBlocksDropdown__header[data-v-e0d0a711]{font-size:12px;text-transform:uppercase;font-weight:500;margin-bottom:10px}.BlueprintToolbarBlocksDropdown__list[data-v-e0d0a711]{display:flex;flex-direction:column;gap:8px}.BlueprintToolbarBlocksDropdown__list__item[data-v-e0d0a711]{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:16px;align-items:center}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711]{font-weight:400;color:var(--wdsColorGray4)}.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{opacity:50%}}@layer wf{.BlueprintToolbar__runBlueprint[data-v-5b7eb059]{min-width:160px}.BlueprintToolbar__runBlueprintDropdown[data-v-5b7eb059]{min-width:185px}}
|