Widget support for Data.fetch and Data.post. (#11199)

- Add `pretty` for `Date` and `Time`.
- Add constructors for `JS_Object` and `Dictionary` to the component browser.
- Add widgets to `Dictionary` methods.
![image](https://github.com/user-attachments/assets/4f6c58d5-9eb5-40e5-96c1-2e06e23051d0)
- Add conversion from Vector to Dictionary.
- Add `pair` method shorthand for `Pair.Value`.
- Created widget for `Header`.
- Added widgets for `Data.fetch` and `Data.post`.
- Added widgets for `Request_Body` constructors.
- Update the Forbidden Operation message to be friendlier.
![image](https://github.com/user-attachments/assets/eaac5def-a91f-450f-b814-d776311962e3)

Video before fixing Forbidden Message:

https://github.com/user-attachments/assets/f9c4bde4-3f0a-49f1-a3ca-a0aaa3219286
This commit is contained in:
James Dunkerley 2024-09-27 19:08:12 +01:00 committed by GitHub
parent ecfe959c29
commit 28bbc34257
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 191 additions and 55 deletions

View File

@ -16,7 +16,7 @@ instance =
## PRIVATE ## PRIVATE
create_dry_run_file file copy_original = create_dry_run_file file copy_original =
_ = [file, copy_original] _ = [file, copy_original]
Error.throw (Forbidden_Operation.Error "Currently dry-run is not supported for S3_File, so writing to an S3_File is forbidden if the Output context is disabled.") Error.throw (Forbidden_Operation.Error "As writing is disabled, no action has been performed. Press the Write button ▶ to write the file.")
## PRIVATE ## PRIVATE
remote_write_with_local_file file existing_file_behavior action = remote_write_with_local_file file existing_file_behavior action =

View File

@ -67,7 +67,7 @@ type S3_File
value. The value is returned from this method. value. The value is returned from this method.
with_output_stream : Vector File_Access -> (Output_Stream -> Any ! File_Error) -> Any ! File_Error with_output_stream : Vector File_Access -> (Output_Stream -> Any ! File_Error) -> Any ! File_Error
with_output_stream self (open_options : Vector) action = if self.is_directory then Error.throw (S3_Error.Error "S3 directory cannot be opened as a stream." self.uri) else with_output_stream self (open_options : Vector) action = if self.is_directory then Error.throw (S3_Error.Error "S3 directory cannot be opened as a stream." self.uri) else
Context.Output.if_enabled disabled_message="Writing to an S3_File is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot write to S3. Press the Write button ▶ to perform the operation." panic=False <|
open_as_data_link = (open_options.contains Data_Link_Access.No_Follow . not) && (Data_Link.is_data_link self) open_as_data_link = (open_options.contains Data_Link_Access.No_Follow . not) && (Data_Link.is_data_link self)
if open_as_data_link then Data_Link_Helpers.write_data_link_as_stream self open_options action else if open_as_data_link then Data_Link_Helpers.write_data_link_as_stream self open_options action else
if open_options.contains File_Access.Append then Error.throw (S3_Error.Error "S3 does not support appending to a file. Instead you may read it, modify and then write the new contents." self.uri) else if open_options.contains File_Access.Append then Error.throw (S3_Error.Error "S3 does not support appending to a file. Instead you may read it, modify and then write the new contents." self.uri) else
@ -251,7 +251,7 @@ type S3_File
copy_to : File_Like -> Boolean -> Any ! S3_Error | File_Error copy_to : File_Like -> Boolean -> Any ! S3_Error | File_Error
copy_to self (destination : File_Like) (replace_existing : Boolean = False) = Data_Link_Helpers.disallow_links_in_copy self destination <| copy_to self (destination : File_Like) (replace_existing : Boolean = False) = Data_Link_Helpers.disallow_links_in_copy self destination <|
if self.is_directory then Error.throw (S3_Error.Error "Copying S3 folders is currently not implemented." self.uri) else if self.is_directory then Error.throw (S3_Error.Error "Copying S3 folders is currently not implemented." self.uri) else
Context.Output.if_enabled disabled_message="Copying an S3_File is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot copy to a file. Press the Write button ▶ to perform the operation." panic=False <|
destination_writable = Writable_File.from destination destination_writable = Writable_File.from destination
case destination_writable.file of case destination_writable.file of
# Special shortcut for more efficient handling of S3 file copying (no need to move the data to our machine) # Special shortcut for more efficient handling of S3 file copying (no need to move the data to our machine)
@ -292,7 +292,7 @@ type S3_File
move_to self (destination : File_Like) (replace_existing : Boolean = False) = move_to self (destination : File_Like) (replace_existing : Boolean = False) =
if self.is_directory then Error.throw (S3_Error.Error "Moving S3 folders is currently not implemented." self.uri) else if self.is_directory then Error.throw (S3_Error.Error "Moving S3 folders is currently not implemented." self.uri) else
Data_Link_Helpers.disallow_links_in_move self destination <| Data_Link_Helpers.disallow_links_in_move self destination <|
Context.Output.if_enabled disabled_message="File moving is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot move the file. Press the Write button ▶ to perform the operation." panic=False <|
r = self.copy_to destination replace_existing=replace_existing r = self.copy_to destination replace_existing=replace_existing
r.if_not_error <| r.if_not_error <|
# If source and destination are the same, we do not want to delete the file # If source and destination are the same, we do not want to delete the file
@ -341,7 +341,7 @@ type S3_File
will occur. will occur.
delete_if_exists : Boolean -> Nothing delete_if_exists : Boolean -> Nothing
delete_if_exists self (recursive : Boolean = False) = delete_if_exists self (recursive : Boolean = False) =
Context.Output.if_enabled disabled_message="Deleting an S3_File is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot delete the file. Press the Write button ▶ to perform the operation." panic=False <|
case self.is_directory of case self.is_directory of
True -> True ->
# This is a temporary simplified implementation to ensure cleaning up after tests # This is a temporary simplified implementation to ensure cleaning up after tests

View File

@ -196,8 +196,9 @@ list (directory:(Text | File)=enso_project.root) (name_filter:Text="") recursive
Data.fetch URL . body . write file Data.fetch URL . body . write file
@uri Text_Input @uri Text_Input
@format Data_Read_Helpers.format_widget_with_raw_response @format Data_Read_Helpers.format_widget_with_raw_response
@headers Header.default_widget
fetch : (URI | Text) -> HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any ! Request_Error | HTTP_Error fetch : (URI | Text) -> HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any ! Request_Error | HTTP_Error
fetch (uri:(URI | Text)) (method:HTTP_Method=HTTP_Method.Get) (headers:(Vector (Header | Pair Text Text))=[]) (format = Auto_Detect) = fetch (uri:(URI | Text)) (method:HTTP_Method=..Get) (headers:(Vector (Header | Pair Text Text))=[]) (format = Auto_Detect) =
Data_Read_Helpers.fetch_following_data_links uri method headers (Data_Read_Helpers.handle_legacy_format "fetch" "format" format) Data_Read_Helpers.fetch_following_data_links uri method headers (Data_Read_Helpers.handle_legacy_format "fetch" "format" format)
## ALIAS http post, upload ## ALIAS http post, upload
@ -321,9 +322,10 @@ fetch (uri:(URI | Text)) (method:HTTP_Method=HTTP_Method.Get) (headers:(Vector (
form_data = Dictionary.from_vector [["key", "val"], ["a_file", test_file]] form_data = Dictionary.from_vector [["key", "val"], ["a_file", test_file]]
response = Data.post url_post (Request_Body.Form_Data form_data url_encoded=True) response = Data.post url_post (Request_Body.Form_Data form_data url_encoded=True)
@uri Text_Input @uri Text_Input
@headers Header.default_widget
@response_format Data_Read_Helpers.format_widget_with_raw_response @response_format Data_Read_Helpers.format_widget_with_raw_response
post : (URI | Text) -> Request_Body -> HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any ! Request_Error | HTTP_Error post : (URI | Text) -> Request_Body -> HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any ! Request_Error | HTTP_Error
post (uri:(URI | Text)) (body:Request_Body=Request_Body.Empty) (method:HTTP_Method=HTTP_Method.Post) (headers:(Vector (Header | Pair Text Text))=[]) (response_format = Auto_Detect) = post (uri:(URI | Text)) (body:Request_Body=..Empty) (method:HTTP_Method=..Post) (headers:(Vector (Header | Pair Text Text))=[]) (response_format = Auto_Detect) =
response = HTTP.post uri body method headers response = HTTP.post uri body method headers
Data_Read_Helpers.decode_http_response_following_data_links response (Data_Read_Helpers.handle_legacy_format "post" "response_format" response_format) Data_Read_Helpers.decode_http_response_following_data_links response (Data_Read_Helpers.handle_legacy_format "post" "response_format" response_format)
@ -340,9 +342,10 @@ post (uri:(URI | Text)) (body:Request_Body=Request_Body.Empty) (method:HTTP_Meth
Defaults to `HTTP_Method.Get`. Defaults to `HTTP_Method.Get`.
- headers: The headers to send with the request. Defaults to an empty vector. - headers: The headers to send with the request. Defaults to an empty vector.
@uri Text_Input @uri Text_Input
@headers Header.default_widget
download : (URI | Text) -> Writable_File -> HTTP_Method -> Vector (Header | Pair Text Text) -> File ! Request_Error | HTTP_Error download : (URI | Text) -> Writable_File -> HTTP_Method -> Vector (Header | Pair Text Text) -> File ! Request_Error | HTTP_Error
download (uri:(URI | Text)) file:Writable_File (method:HTTP_Method=HTTP_Method.Get) (headers:(Vector (Header | Pair Text Text))=[]) = download (uri:(URI | Text)) file:Writable_File (method:HTTP_Method=..Get) (headers:(Vector (Header | Pair Text Text))=[]) =
Context.Output.if_enabled disabled_message="Downloading to a file is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot download to a file. Press the Write button ▶ to perform the operation." panic=False <|
response = HTTP.fetch uri method headers response = HTTP.fetch uri method headers
case Data_Link.is_data_link response.body.metadata of case Data_Link.is_data_link response.body.metadata of
True -> True ->

View File

@ -4,12 +4,18 @@ import project.Data.Pair.Pair
import project.Data.Text.Text import project.Data.Text.Text
import project.Data.Vector.Vector import project.Data.Vector.Vector
import project.Error.Error import project.Error.Error
import project.Errors.Common.Missing_Argument
import project.Errors.Illegal_Argument.Illegal_Argument import project.Errors.Illegal_Argument.Illegal_Argument
import project.Errors.No_Such_Key.No_Such_Key import project.Errors.No_Such_Key.No_Such_Key
import project.Meta
import project.Metadata.Widget
import project.Nothing.Nothing import project.Nothing.Nothing
import project.Panic.Panic import project.Panic.Panic
from project.Data.Boolean import Boolean, False, True from project.Data.Boolean import Boolean, False, True
from project.Data.Text.Extensions import all from project.Data.Text.Extensions import all
from project.Metadata.Choice import Option
from project.Metadata.Widget import Single_Choice, Vector_Editor
from project.Widget_Helpers import make_all_selector
## A key-value store. It is possible to use any type as keys and values and mix ## A key-value store. It is possible to use any type as keys and values and mix
them in one Dictionary. Keys are checked for equality based on their hash them in one Dictionary. Keys are checked for equality based on their hash
@ -32,14 +38,12 @@ from project.Data.Text.Extensions import all
to pass a foreign map into Enso, where it will be treated as a Dictionary. to pass a foreign map into Enso, where it will be treated as a Dictionary.
@Builtin_Type @Builtin_Type
type Dictionary key value type Dictionary key value
## PRIVATE ## ICON array_new2
ADVANCED
Returns an empty dictionary. Returns an empty dictionary.
empty : Dictionary empty : Dictionary
empty = @Builtin_Method "Dictionary.empty" empty = @Builtin_Method "Dictionary.empty"
## PRIVATE ## ICON array_new2
ADVANCED
Returns a single-element dictionary with the given key and value. Returns a single-element dictionary with the given key and value.
A Call to `Dictionary.singleton key value` is the same as a call to A Call to `Dictionary.singleton key value` is the same as a call to
`Dictionary.empty.insert key value`. `Dictionary.empty.insert key value`.
@ -53,12 +57,14 @@ type Dictionary key value
value 2. value 2.
example_singleton = Dictionary.singleton "my_key" 2 example_singleton = Dictionary.singleton "my_key" 2
@key (make_all_selector ..Always)
@value (make_all_selector ..Always)
singleton : Any -> Any -> Dictionary singleton : Any -> Any -> Dictionary
singleton key value = Dictionary.empty.insert key value singleton key value = Dictionary.empty.insert key value
## ALIAS dictionary, lookup table ## ALIAS dictionary, lookup table
GROUP Constants GROUP Constants
ICON convert ICON array_new2
Builds a dictionary from two Vectors. The first vector contains the keys, Builds a dictionary from two Vectors. The first vector contains the keys,
and the second vector contains the values. The two vectors must be of the and the second vector contains the values. The two vectors must be of the
same length. same length.
@ -71,6 +77,8 @@ type Dictionary key value
meaning that if two entries in the vector share the same key, an meaning that if two entries in the vector share the same key, an
`Illegal_Argument` error is raised. If set to `False`, the last entry `Illegal_Argument` error is raised. If set to `False`, the last entry
with a given key will be kept. with a given key will be kept.
@keys (Vector_Editor item_editor=make_all_selector display=..Always item_default="Nothing")
@values (Vector_Editor item_editor=make_all_selector display=..Always item_default="Nothing")
from_keys_and_values : Vector Any -> Vector Any -> Boolean -> Dictionary ! Illegal_Argument from_keys_and_values : Vector Any -> Vector Any -> Boolean -> Dictionary ! Illegal_Argument
from_keys_and_values keys:Vector values:Vector error_on_duplicates:Boolean=True = from_keys_and_values keys:Vector values:Vector error_on_duplicates:Boolean=True =
if keys.length != values.length then Error.throw (Illegal_Argument.Error "`Dictionary.from_keys_and_values` encountered two vectors of different lengths.") else if keys.length != values.length then Error.throw (Illegal_Argument.Error "`Dictionary.from_keys_and_values` encountered two vectors of different lengths.") else
@ -80,7 +88,7 @@ type Dictionary key value
## ALIAS dictionary, lookup table ## ALIAS dictionary, lookup table
GROUP Constants GROUP Constants
ICON convert ICON array_new2
Builds a dictionary from a vector of key-value pairs, with each key-value Builds a dictionary from a vector of key-value pairs, with each key-value
pair represented as a 2 element vector. pair represented as a 2 element vector.
@ -96,8 +104,9 @@ type Dictionary key value
Building a dictionary containing two key-value pairs. Building a dictionary containing two key-value pairs.
example_from_vector = Dictionary.from_vector [["A", 1], ["B", 2]] example_from_vector = Dictionary.from_vector [["A", 1], ["B", 2]]
@vec key_value_widget
from_vector : Vector Any -> Boolean -> Dictionary ! Illegal_Argument from_vector : Vector Any -> Boolean -> Dictionary ! Illegal_Argument
from_vector vec error_on_duplicates=True = from_vector vec error_on_duplicates:Boolean=True =
vec.fold Dictionary.empty m-> el-> if el.length != 2 then Error.throw (Illegal_Argument.Error "`Dictionary.from_vector` encountered an invalid value. Each value in the vector has to be a key-value pair - it must have exactly 2 elements.") else vec.fold Dictionary.empty m-> el-> if el.length != 2 then Error.throw (Illegal_Argument.Error "`Dictionary.from_vector` encountered an invalid value. Each value in the vector has to be a key-value pair - it must have exactly 2 elements.") else
key = el.at 0 key = el.at 0
value = el.at 1 value = el.at 1
@ -152,8 +161,11 @@ type Dictionary key value
import Standard.Examples import Standard.Examples
example_insert = Examples.dictionary.insert 7 "seven" example_insert = Examples.dictionary.insert 7 "seven"
@key (make_all_selector ..Always)
@value (make_all_selector ..Always)
insert : Any -> Any -> Dictionary insert : Any -> Any -> Dictionary
insert self key value = @Builtin_Method "Dictionary.insert" insert self key=(Missing_Argument.throw "key") value=(Missing_Argument.throw "value") =
self.insert_builtin key value
## GROUP Selections ## GROUP Selections
ICON table_clean ICON table_clean
@ -170,8 +182,9 @@ type Dictionary key value
import Standard.Examples import Standard.Examples
Examples.dictionary.remove "A" Examples.dictionary.remove "A"
@key key_widget
remove : Any -> Dictionary ! No_Such_Key remove : Any -> Dictionary ! No_Such_Key
remove self key = remove self key=(Missing_Argument.throw "key") =
Panic.catch Any (self.remove_builtin key) _-> Panic.catch Any (self.remove_builtin key) _->
Error.throw (No_Such_Key.Error self key) Error.throw (No_Such_Key.Error self key)
@ -191,6 +204,7 @@ type Dictionary key value
import Standard.Examples import Standard.Examples
example_at = Examples.dictionary.at "A" example_at = Examples.dictionary.at "A"
@key key_widget
at : Any -> Any ! No_Such_Key at : Any -> Any ! No_Such_Key
at self key = self.get key (Error.throw (No_Such_Key.Error self key)) at self key = self.get key (Error.throw (No_Such_Key.Error self key))
@ -211,12 +225,14 @@ type Dictionary key value
import Standard.Examples import Standard.Examples
example_get = Examples.dictionary.get 2 "zero" example_get = Examples.dictionary.get 2 "zero"
@key key_widget
get : Any -> Any -> Any get : Any -> Any -> Any
get self key ~if_missing=Nothing = self.get_builtin key if_missing get self key ~if_missing=Nothing = self.get_builtin key if_missing
## GROUP Logical ## GROUP Logical
ICON preparation ICON preparation
Returns True iff the Dictionary contains the given `key`. Returns True iff the Dictionary contains the given `key`.
@key (make_all_selector ..Always)
contains_key : Any -> Boolean contains_key : Any -> Boolean
contains_key self key = @Builtin_Method "Dictionary.contains_key" contains_key self key = @Builtin_Method "Dictionary.contains_key"
@ -423,3 +439,19 @@ type Dictionary key value
## PRIVATE ## PRIVATE
get_builtin : Any -> Any -> Any get_builtin : Any -> Any -> Any
get_builtin self key ~if_missing = @Builtin_Method "Dictionary.get_builtin" get_builtin self key ~if_missing = @Builtin_Method "Dictionary.get_builtin"
## PRIVATE
key_widget dict:Dictionary -> Widget =
values = dict.keys.map k-> Option k.to_text k.pretty
Single_Choice display=..Always values=values
## PRIVATE
key_value_widget -> Widget =
fqn = Meta.get_qualified_type_name Pair . drop (..Last 5)
default = 'pair "key" Nothing'
pair = Option "Pair" fqn+".pair" [["first", make_all_selector], ["second", make_all_selector]]
item_editor = Single_Choice display=..Always values=[pair]
Vector_Editor item_editor=item_editor display=..Always item_default=default
## PRIVATE
Dictionary.from (that:Vector) = Dictionary.from_vector that

View File

@ -29,7 +29,8 @@ from project.Data.Ordering import all
from project.Data.Range.Extensions import all from project.Data.Range.Extensions import all
from project.Data.Text.Extensions import all from project.Data.Text.Extensions import all
from project.Metadata.Choice import Option from project.Metadata.Choice import Option
from project.Metadata.Widget import Single_Choice from project.Metadata.Widget import Single_Choice, Text_Input, Vector_Editor
from project.Widget_Helpers import make_all_selector
polyglot java import com.fasterxml.jackson.core.JsonLocation polyglot java import com.fasterxml.jackson.core.JsonLocation
polyglot java import com.fasterxml.jackson.core.JsonProcessingException polyglot java import com.fasterxml.jackson.core.JsonProcessingException
@ -161,10 +162,11 @@ type JS_Object
loop name_iterator builder loop name_iterator builder
JS_Object.Value object_node (make_field_names object_node) JS_Object.Value object_node (make_field_names object_node)
## PRIVATE ## ICON braces
Creates a Jackson_Object from a list of key-value pairs. Creates a JS_Object from a list of key-value pairs.
Keys must be `Text` values. Keys must be `Text` values.
Values will be recursively converted to JSON serializable as needed. Values will be recursively converted to JSON serializable as needed.
@pairs key_value_widget
from_pairs : Vector -> JS_Object from_pairs : Vector -> JS_Object
from_pairs pairs = from_pairs pairs =
mapper = ObjectMapper.new mapper = ObjectMapper.new
@ -348,7 +350,7 @@ type JS_Object
## PRIVATE ## PRIVATE
Make a field name selector Make a field name selector
make_field_name_selector : JS_Object -> Display -> Widget make_field_name_selector : JS_Object -> Display -> Widget
make_field_name_selector js_object display=Display.Always = make_field_name_selector js_object display:Display=..Always =
Single_Choice display=display values=(js_object.field_names.map n->(Option n n.pretty)) Single_Choice display=display values=(js_object.field_names.map n->(Option n n.pretty))
## PRIVATE ## PRIVATE
@ -423,3 +425,12 @@ make_enso object =
_ -> js_object _ -> js_object
if parsed.is_error then js_object else parsed if parsed.is_error then js_object else parsed
## PRIVATE
key_value_widget : Widget
key_value_widget =
fqn = Meta.get_qualified_type_name Pair . drop (..Last 5)
default = 'pair "key" Nothing'
pair = Option "Pair" fqn+".pair" [["first", Text_Input], ["second", make_all_selector]]
item_editor = Single_Choice display=..Always values=[pair]
Vector_Editor item_editor=item_editor display=..Always item_default=default

View File

@ -295,3 +295,12 @@ check_start_valid start function max=3 =
used_start = if start < 0 then start + 2 else start used_start = if start < 0 then start + 2 else start
if used_start < 0 || used_start >= max then Error.throw (Index_Out_Of_Bounds.Error start max) else if used_start < 0 || used_start >= max then Error.throw (Index_Out_Of_Bounds.Error start max) else
function used_start function used_start
## ICON array_new
Create a new Pair from two elements.
Arguments:
- first: The first element.
- second: The second element.
pair : Any -> Any -> Pair
pair first second -> Pair = Pair.new first second

View File

@ -826,6 +826,11 @@ type Date
format self format:Date_Time_Formatter=Date_Time_Formatter.iso_date = format self format:Date_Time_Formatter=Date_Time_Formatter.iso_date =
format.format_date self format.format_date self
## PRIVATE
Convert to a Enso code representation of this Date.
pretty : Text
pretty self = "(Date.new " + self.year.to_text + " " + self.month.to_text + " " + self.day.to_text + ")"
## PRIVATE ## PRIVATE
week_days_between start end = week_days_between start end =
## We split the interval into 3 periods: the first week (containing the ## We split the interval into 3 periods: the first week (containing the

View File

@ -491,6 +491,18 @@ type Time_Of_Day
format self format:Date_Time_Formatter = format self format:Date_Time_Formatter =
format.format_time self format.format_time self
## PRIVATE
Convert to a Enso code representation of this Time_Of_Day.
pretty : Text
pretty self = "(Time_Of_Day.new "
+ (if self.hour == 0 then "" else " hour="+self.hour.to_text)
+ (if self.minute == 0 then "" else " minute="+self.minute.to_text)
+ (if self.second == 0 then "" else " second="+self.second.to_text)
+ (if self.millisecond == 0 then "" else " millisecond="+self.millisecond.to_text)
+ (if self.microsecond == 0 then "" else " microsecond="+self.microsecond.to_text)
+ (if self.nanosecond == 0 then "" else " nanosecond="+self.nanosecond.to_text)
+ ")"
## PRIVATE ## PRIVATE
Time_Of_Day.from (that:JS_Object) = Time_Of_Day.from (that:JS_Object) =
## Must have hour and minute but second and nanosecond are optional ## Must have hour and minute but second and nanosecond are optional

View File

@ -211,7 +211,7 @@ type Enso_File
value. The value is returned from this method. value. The value is returned from this method.
with_output_stream : Vector File_Access -> (Output_Stream -> Any ! File_Error) -> Any ! File_Error with_output_stream : Vector File_Access -> (Output_Stream -> Any ! File_Error) -> Any ! File_Error
with_output_stream self (open_options : Vector) action = with_output_stream self (open_options : Vector) action =
Context.Output.if_enabled disabled_message="Writing to an Enso_File is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot write to a file. Press the Write button ▶ to perform the operation." panic=False <|
is_data_link = Data_Link.is_data_link self is_data_link = Data_Link.is_data_link self
open_as_data_link = (open_options.contains Data_Link_Access.No_Follow . not) && is_data_link open_as_data_link = (open_options.contains Data_Link_Access.No_Follow . not) && is_data_link
if open_as_data_link then Data_Link_Helpers.write_data_link_as_stream self open_options action else if open_as_data_link then Data_Link_Helpers.write_data_link_as_stream self open_options action else

View File

@ -13,7 +13,6 @@ import project.Errors.Common.Not_Found
import project.Errors.Illegal_Argument.Illegal_Argument import project.Errors.Illegal_Argument.Illegal_Argument
import project.Network.HTTP.HTTP import project.Network.HTTP.HTTP
import project.Network.HTTP.HTTP_Method.HTTP_Method import project.Network.HTTP.HTTP_Method.HTTP_Method
import project.Network.HTTP.Request_Body.Request_Body
import project.Network.URI.URI import project.Network.URI.URI
import project.Nothing.Nothing import project.Nothing.Nothing
import project.Runtime.Context import project.Runtime.Context
@ -45,7 +44,7 @@ type Enso_Secret
created in the current working directory. created in the current working directory.
create : Text -> Text -> Enso_File | Nothing -> Enso_Secret create : Text -> Text -> Enso_File | Nothing -> Enso_Secret
create name:Text value:Text parent:(Enso_File | Nothing)=Nothing = if name == "" then Error.throw (Illegal_Argument.Error "Secret name cannot be empty") else create name:Text value:Text parent:(Enso_File | Nothing)=Nothing = if name == "" then Error.throw (Illegal_Argument.Error "Secret name cannot be empty") else
Context.Output.if_enabled disabled_message="Creating a secret is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot create a secret. Press the Write button ▶ to perform the operation." panic=False <|
if name.starts_with "connection-" then Error.throw (Illegal_Argument.Error "Secret name cannot start with 'connection-'") else if name.starts_with "connection-" then Error.throw (Illegal_Argument.Error "Secret name cannot start with 'connection-'") else
parent_dir = parent.if_nothing Enso_File.current_working_directory parent_dir = parent.if_nothing Enso_File.current_working_directory
path = if name.contains "/" then Error.throw (Illegal_Argument.Error "Secret name cannot contain `/`.") else parent_dir.enso_path.resolve name path = if name.contains "/" then Error.throw (Illegal_Argument.Error "Secret name cannot contain `/`.") else parent_dir.enso_path.resolve name
@ -65,7 +64,7 @@ type Enso_Secret
Deletes a secret. Deletes a secret.
delete : Enso_Secret delete : Enso_Secret
delete self = delete self =
Context.Output.if_enabled disabled_message="Deleting a secret is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot delete secret. Press the Write button ▶ to perform the operation." panic=False <|
uri = URI.from (secret_asset_uri self) . add_query_argument "force" "true" uri = URI.from (secret_asset_uri self) . add_query_argument "force" "true"
response = Utils.http_request HTTP_Method.Delete uri response = Utils.http_request HTTP_Method.Delete uri
response.if_not_error self response.if_not_error self
@ -140,7 +139,7 @@ type Enso_Secret
- new_value: The new value of the secret - new_value: The new value of the secret
update_value : Text -> Enso_Secret update_value : Text -> Enso_Secret
update_value self (new_value : Text) = update_value self (new_value : Text) =
Context.Output.if_enabled disabled_message="Updating a secret is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot update secret. Press the Write button ▶ to perform the operation." panic=False <|
body = JS_Object.from_pairs [["value", new_value]] body = JS_Object.from_pairs [["value", new_value]]
response = Utils.http_request HTTP_Method.Put (secret_resource_uri self) body response = Utils.http_request HTTP_Method.Put (secret_resource_uri self) body
response.if_not_error <| response.if_not_error <|

View File

@ -22,7 +22,7 @@ instance =
## PRIVATE ## PRIVATE
create_dry_run_file file copy_original = create_dry_run_file file copy_original =
_ = [file, copy_original] _ = [file, copy_original]
Error.throw (Forbidden_Operation.Error "Currently dry-run is not supported for Enso_File, so writing to an Enso_File is forbidden if the Output context is disabled.") Error.throw (Forbidden_Operation.Error "As writing is disabled, no action has been performed. Press the Write button ▶ to write the file.")
## PRIVATE ## PRIVATE

View File

@ -72,7 +72,7 @@ flush_caches = CloudAPI.flushCloudCaches
## PRIVATE ## PRIVATE
Performs a standard request to the Enso Cloud API, Performs a standard request to the Enso Cloud API,
parsing the result as JSON. parsing the result as JSON.
http_request_as_json (method : HTTP_Method) (url : URI) (body : Request_Body = Request_Body.Empty) (additional_headers : Vector = []) (error_handlers : Dictionary Text (Any -> Any) = Dictionary.empty) (retries : Integer = 3) -> Any ! Enso_Cloud_Error = http_request_as_json (method : HTTP_Method) (url : URI) (body : Request_Body = ..Empty) (additional_headers : Vector = []) (error_handlers : Dictionary Text (Any -> Any) = Dictionary.empty) (retries : Integer = 3) -> Any ! Enso_Cloud_Error =
response = http_request method url body additional_headers error_handlers retries response = http_request method url body additional_headers error_handlers retries
response.decode_as_json.catch Invalid_JSON error-> response.decode_as_json.catch Invalid_JSON error->
Error.throw (Enso_Cloud_Error.Invalid_Response_Payload error) Error.throw (Enso_Cloud_Error.Invalid_Response_Payload error)
@ -87,7 +87,7 @@ http_request_as_json (method : HTTP_Method) (url : URI) (body : Request_Body = R
Custom error handlers can be provided as a mapping from error codes Custom error handlers can be provided as a mapping from error codes
(defined in the cloud project) to functions that take the full JSON payload (defined in the cloud project) to functions that take the full JSON payload
and return a custom error. and return a custom error.
http_request (method : HTTP_Method) (url : URI) (body : Request_Body = Request_Body.Empty) (additional_headers : Vector = []) (error_handlers : Dictionary Text (Any -> Any) = Dictionary.empty) (retries : Integer = 3) -> Response ! Enso_Cloud_Error = method.if_not_error <| url.if_not_error <| body.if_not_error <| additional_headers.if_not_error <| http_request (method : HTTP_Method) (url : URI) (body : Request_Body = ..Empty) (additional_headers : Vector = []) (error_handlers : Dictionary Text (Any -> Any) = Dictionary.empty) (retries : Integer = 3) -> Response ! Enso_Cloud_Error = method.if_not_error <| url.if_not_error <| body.if_not_error <| additional_headers.if_not_error <|
all_headers = [authorization_header] + additional_headers all_headers = [authorization_header] + additional_headers
as_connection_error err = Error.throw (Enso_Cloud_Error.Connection_Error err) as_connection_error err = Error.throw (Enso_Cloud_Error.Connection_Error err)

View File

@ -431,7 +431,7 @@ type Forbidden_Operation
## PRIVATE ## PRIVATE
Convert the Forbidden_Operation error to a human-readable format. Convert the Forbidden_Operation error to a human-readable format.
to_display_text : Text to_display_text : Text
to_display_text self = "Forbidden operation: "+self.message to_display_text self = self.message
type Dry_Run_Operation type Dry_Run_Operation
## PRIVATE ## PRIVATE

View File

@ -32,6 +32,7 @@ export project.Data.Numeric.Rounding_Mode.Rounding_Mode
export project.Data.Ordering.Comparable export project.Data.Ordering.Comparable
export project.Data.Ordering.Natural_Order export project.Data.Ordering.Natural_Order
export project.Data.Ordering.Ordering export project.Data.Ordering.Ordering
export project.Data.Pair.pair
export project.Data.Pair.Pair export project.Data.Pair.Pair
export project.Data.Range.Extensions.down_to export project.Data.Range.Extensions.down_to
export project.Data.Range.Extensions.up_to export project.Data.Range.Extensions.up_to

View File

@ -44,7 +44,7 @@ Text.to_uri self = URI.parse self
cannot be determined automatically, a raw HTTP `Response` will be returned. cannot be determined automatically, a raw HTTP `Response` will be returned.
@format Data_Read_Helpers.format_widget_with_raw_response @format Data_Read_Helpers.format_widget_with_raw_response
URI.fetch : HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any URI.fetch : HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any
URI.fetch self (method:HTTP_Method=HTTP_Method.Get) headers=[] format=Auto_Detect = URI.fetch self (method:HTTP_Method=..Get) headers=[] format=Auto_Detect =
Data.fetch self method headers format Data.fetch self method headers format
## ALIAS http post, upload ## ALIAS http post, upload
@ -85,7 +85,8 @@ URI.fetch self (method:HTTP_Method=HTTP_Method.Get) headers=[] format=Auto_Detec
- Text: shorthand for `Request_Body.Text that_text`. - Text: shorthand for `Request_Body.Text that_text`.
- File: shorthand for `Request_Body.Binary that_file`. - File: shorthand for `Request_Body.Binary that_file`.
- Any other Enso object: shorthand for `Request_Body.Json that_object`. - Any other Enso object: shorthand for `Request_Body.Json that_object`.
@headers Header.default_widget
@response_format Data_Read_Helpers.format_widget_with_raw_response @response_format Data_Read_Helpers.format_widget_with_raw_response
URI.post : Request_Body -> HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any URI.post : Request_Body -> HTTP_Method -> Vector (Header | Pair Text Text) -> File_Format -> Any
URI.post self (body:Request_Body=Request_Body.Empty) (method:HTTP_Method=HTTP_Method.Post) (headers:(Vector (Header | Pair Text Text))=[]) (response_format = Auto_Detect) = URI.post self (body:Request_Body=..Empty) (method:HTTP_Method=..Post) (headers:(Vector (Header | Pair Text Text))=[]) (response_format = Auto_Detect) =
Data.post self body method headers response_format Data.post self body method headers response_format

View File

@ -11,6 +11,7 @@ import project.Enso_Cloud.Enso_Secret.Enso_Secret
import project.Error.Error import project.Error.Error
import project.Errors.Common.Forbidden_Operation import project.Errors.Common.Forbidden_Operation
import project.Errors.Illegal_Argument.Illegal_Argument import project.Errors.Illegal_Argument.Illegal_Argument
import project.Function.Function
import project.Meta import project.Meta
import project.Network.HTTP.Header.Header import project.Network.HTTP.Header.Header
import project.Network.HTTP.HTTP_Error.HTTP_Error import project.Network.HTTP.HTTP_Error.HTTP_Error
@ -106,7 +107,7 @@ type HTTP
# Prevent request if the method is a write-like method and output context is disabled. # Prevent request if the method is a write-like method and output context is disabled.
check_output_context ~action = check_output_context ~action =
if fetch_methods.contains req.method || Context.Output.is_enabled then action else if fetch_methods.contains req.method || Context.Output.is_enabled then action else
Error.throw (Forbidden_Operation.Error ("Method " + req.method.to_text + " requests are forbidden as the Output context is disabled.")) Error.throw (Forbidden_Operation.Error ("As writing is disabled, " + req.method.to_text + " request not sent. Press the Write button ▶ to send it."))
handle_request_error = handle_request_error =
handler caught_panic = handler caught_panic =
exception = caught_panic.payload exception = caught_panic.payload
@ -137,7 +138,7 @@ type HTTP
## PRIVATE ## PRIVATE
Static helper for get-like methods Static helper for get-like methods
fetch : (URI | Text) -> HTTP_Method -> Vector (Header | Pair Text Text) -> Response ! Request_Error | HTTP_Error fetch : (URI | Text) -> HTTP_Method -> Vector (Header | Pair Text Text) -> Response ! Request_Error | HTTP_Error
fetch (uri:(URI | Text)) (method:HTTP_Method=HTTP_Method.Get) (headers:(Vector (Header | Pair Text Text))=[]) = fetch (uri:(URI | Text)) (method:HTTP_Method=..Get) (headers:(Vector (Header | Pair Text Text))=[]) =
check_method fetch_methods method <| check_method fetch_methods method <|
request = Request.new method uri (parse_headers headers) Request_Body.Empty request = Request.new method uri (parse_headers headers) Request_Body.Empty
HTTP.new.request request HTTP.new.request request
@ -187,6 +188,7 @@ parse_headers headers =
headers . map on_problems=No_Wrap h-> case h of headers . map on_problems=No_Wrap h-> case h of
_ : Vector -> Header.new (h.at 0) (h.at 1) _ : Vector -> Header.new (h.at 0) (h.at 1)
_ : Pair -> Header.new (h.at 0) (h.at 1) _ : Pair -> Header.new (h.at 0) (h.at 1)
_ : Function -> h:Header
_ : Header -> h _ : Header -> h
_ -> Error.throw (Illegal_Argument.Error "Invalid header type - all values must be Vector, Pair or Header (got "+(Meta.get_simple_type_name h)+").") _ -> Error.throw (Illegal_Argument.Error "Invalid header type - all values must be Vector, Pair or Header (got "+(Meta.get_simple_type_name h)+").")

View File

@ -3,11 +3,18 @@ import project.Data.Text.Encoding.Encoding
import project.Data.Text.Text import project.Data.Text.Text
import project.Enso_Cloud.Enso_Secret.Derived_Secret_Value import project.Enso_Cloud.Enso_Secret.Derived_Secret_Value
import project.Enso_Cloud.Enso_Secret.Enso_Secret import project.Enso_Cloud.Enso_Secret.Enso_Secret
import project.Meta
import project.Metadata.Display
import project.Metadata.Widget
import project.Nothing.Nothing import project.Nothing.Nothing
from project.Data.Boolean import Boolean, False, True from project.Data.Boolean import Boolean, False, True
from project.Data.Ordering import all from project.Data.Ordering import all
from project.Data.Text.Extensions import all from project.Data.Text.Extensions import all
from project.Enso_Cloud.Enso_Secret import as_hideable_value from project.Enso_Cloud.Enso_Secret import as_hideable_value
from project.Metadata import make_single_choice
from project.Metadata.Choice import Option
from project.Metadata.Widget import Single_Choice, Vector_Editor
from project.Widget_Helpers import make_text_secret_selector
polyglot java import org.graalvm.collections.Pair as Java_Pair polyglot java import org.graalvm.collections.Pair as Java_Pair
@ -213,6 +220,22 @@ type Header
to_java_pair self = to_java_pair self =
Java_Pair.create self.name (as_hideable_value self.value) Java_Pair.create self.name (as_hideable_value self.value)
## PRIVATE
default_widget (display : Display = ..When_Modified) -> Widget =
fqn = "Header"
secret_selector = make_text_secret_selector
custom = [Option "Custom" fqn+".new '' ''"]
accept = [Option "Accept" fqn+".accept '*/*'"]
authorization = [Option "Authorization" fqn+".authorization ''" [["value", secret_selector]]]
basic_auth = [Option "HTTP Basic Auth" fqn+".authorization_basic '' ''" [["user", secret_selector], ["pass", secret_selector]]]
bearer_auth = [Option "Bearer Auth" fqn+".authorization_bearer ''" [["token", secret_selector]]]
content_type = [Option "Content-Type" fqn+".content_type ''" [["value", content_type_widget], ["encoding", Encoding.default_widget]]]
values = custom + accept + authorization + basic_auth + bearer_auth + content_type
item_editor = Single_Choice values=values display=..Always
Vector_Editor item_editor item_default='Header.new "header" "value"' display=display
## PRIVATE ## PRIVATE
type Header_Comparator type Header_Comparator
## PRIVATE ## PRIVATE
@ -229,3 +252,7 @@ type Header_Comparator
## PRIVATE ## PRIVATE
Comparable.from (that:Header) = Comparable.new that Header_Comparator Comparable.from (that:Header) = Comparable.new that Header_Comparator
## PRIVATE
content_type_widget -> Widget =
make_single_choice [["Custom", "*"], "application/json", "application/octet-stream", "application/x-www-form-urlencoded", "multipart/form-data", "text/csv", "text/html", "text/plain", "text/xml"]

View File

@ -34,7 +34,7 @@ type Request
example_new = Request.new Method.Post (URI.parse "http://example.com") example_new = Request.new Method.Post (URI.parse "http://example.com")
new : HTTP_Method -> URI -> Vector Header -> Request_Body -> Request new : HTTP_Method -> URI -> Vector Header -> Request_Body -> Request
new (method:HTTP_Method) (url:URI) (headers:(Vector Header)=[]) (body:Request_Body=Request_Body.Empty) = new (method:HTTP_Method) (url:URI) (headers:(Vector Header)=[]) (body:Request_Body=..Empty) =
Request.Value method url headers body Request.Value method url headers body
## ICON find ## ICON find

View File

@ -1,11 +1,21 @@
import project.Any.Any import project.Any.Any
import project.Data.Dictionary.Dictionary import project.Data.Dictionary.Dictionary
import project.Data.Pair.Pair
import project.Data.Text.Encoding.Encoding import project.Data.Text.Encoding.Encoding
import project.Data.Text.Text import project.Data.Text.Text
import project.Errors.Common.Missing_Argument
import project.Meta
import project.Metadata.Widget
import project.Network.HTTP.Header.Header import project.Network.HTTP.Header.Header
import project.Nothing.Nothing import project.Nothing.Nothing
import project.System.File.File import project.System.File.File
from project.Data.Boolean import Boolean, False, True from project.Data.Boolean import Boolean, False, True
from project.Data.Json import key_value_widget
from project.Data.Text.Extensions import all
from project.Metadata.Choice import Option
from project.Metadata.Widget import File_Browse, Single_Choice, Text_Input, Vector_Editor
from project.Network.HTTP.Header import content_type_widget
from project.Widget_Helpers import make_all_selector
## The HTTP POST request body. ## The HTTP POST request body.
type Request_Body type Request_Body
@ -16,19 +26,22 @@ type Request_Body
- text: The plain text in the request body. - text: The plain text in the request body.
- encoding: the text encoding to send as a Content-Encoding header - encoding: the text encoding to send as a Content-Encoding header
- content_type: the content_type to send as a Content-Type header - content_type: the content_type to send as a Content-Type header
Text (text:Text) (encoding:(Encoding|Nothing)=Nothing) (content_type:(Text|Nothing)=Nothing) @encoding Encoding.default_widget
@content_type content_type_widget
Text (text:Text="") (encoding:(Encoding|Nothing)=Nothing) (content_type:(Text|Nothing)=Nothing)
## Request body with an object to be sent as JSON. ## Request body with an object to be sent as JSON.
Arguments: Arguments:
- x: The object to convert to JSON using `.to_json`. - x: The object to convert to JSON using `.to_json`.
Json (x:Any) @x make_all_with_json
Json (x:Any=(Missing_Argument.throw "x"))
## Request body with an object to be sent as a binary file. ## Request body with an object to be sent as a binary file.
Arguments: Arguments:
- file: The file to send. - file: The file to send.
Binary (file:File) Binary (file:File=(Missing_Argument.throw "file"))
## Request body with form data. ## Request body with form data.
@ -36,7 +49,8 @@ type Request_Body
- form_data: the form fields (text or file) to be sent - form_data: the form fields (text or file) to be sent
- url_encoded: if true, use a URL-encoded form; otherwise, use a - url_encoded: if true, use a URL-encoded form; otherwise, use a
multi-part encoding. multi-part encoding.
Form_Data (form_data:(Dictionary Text (Text | File))) (url_encoded:Boolean=False) @form_data dictionary_widget
Form_Data (form_data:Dictionary=(Missing_Argument.throw "form_data")) (url_encoded:Boolean=False)
## Empty request body; used for GET ## Empty request body; used for GET
Empty Empty
@ -61,3 +75,18 @@ Request_Body.from (that:File) = Request_Body.Binary that
## PRIVATE ## PRIVATE
Request_Body.from (that:Any) = Request_Body.Json that Request_Body.from (that:Any) = Request_Body.Json that
## PRIVATE
make_all_with_json =
base_selector = make_all_selector Request_Body
values = [Option "JSON Object" key_value_widget] + base_selector.values
Single_Choice display=..Always values=values
## PRIVATE
dictionary_widget -> Widget =
fqn = Meta.get_qualified_type_name Pair . drop (..Last 5)
default = 'pair "key" ""'
value_editor = Single_Choice display=..Always values=[Option "Text" '""', Option "File" "File.new ''"]
pair = Option "Pair" fqn+".pair" [["first", Text_Input], ["second", value_editor]]
item_editor = Single_Choice display=..Always values=[pair]
Vector_Editor item_editor=item_editor display=..Always item_default=default

View File

@ -195,7 +195,7 @@ type File
_ -> stream _ -> stream
Output_Stream.new wrapped (File_Error.handle_java_exceptions self) Output_Stream.new wrapped (File_Error.handle_java_exceptions self)
Context.Output.if_enabled disabled_message="File writing is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot write to a file. Press the Write button ▶ to perform the operation." panic=False <|
open_as_data_link = (open_options.contains Data_Link_Access.No_Follow . not) && (Data_Link.is_data_link self) open_as_data_link = (open_options.contains Data_Link_Access.No_Follow . not) && (Data_Link.is_data_link self)
if open_as_data_link then Data_Link_Helpers.write_data_link_as_stream self open_options action else if open_as_data_link then Data_Link_Helpers.write_data_link_as_stream self open_options action else
# We ignore the Data_Link_Access options at this stage: # We ignore the Data_Link_Access options at this stage:
@ -515,7 +515,7 @@ type File
(Examples.data_dir / "my_directory") . create_directory (Examples.data_dir / "my_directory") . create_directory
create_directory : File ! File_Error create_directory : File ! File_Error
create_directory self = create_directory self =
Context.Output.if_enabled disabled_message="Directory creation is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot create directory. Press the Write button ▶ to perform the operation." panic=False <|
File_Error.handle_java_exceptions self self.create_directory_builtin . if_not_error self File_Error.handle_java_exceptions self self.create_directory_builtin . if_not_error self
## PRIVATE ## PRIVATE
@ -665,7 +665,7 @@ type File
file.delete file.delete
delete : Boolean -> Nothing ! File_Error delete : Boolean -> Nothing ! File_Error
delete self (recursive : Boolean = False) -> Nothing ! File_Error = delete self (recursive : Boolean = False) -> Nothing ! File_Error =
Context.Output.if_enabled disabled_message="File deleting is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot delete file. Press the Write button ▶ to perform the operation." panic=False <|
File_Error.handle_java_exceptions self (self.delete_builtin recursive) File_Error.handle_java_exceptions self (self.delete_builtin recursive)
## ICON data_output ## ICON data_output
@ -677,7 +677,7 @@ type File
destination file already exists. Defaults to `False`. destination file already exists. Defaults to `False`.
copy_to : File_Like -> Boolean -> Any ! File_Error copy_to : File_Like -> Boolean -> Any ! File_Error
copy_to self (destination : File_Like) (replace_existing : Boolean = False) = Data_Link_Helpers.disallow_links_in_copy self destination <| copy_to self (destination : File_Like) (replace_existing : Boolean = False) = Data_Link_Helpers.disallow_links_in_copy self destination <|
Context.Output.if_enabled disabled_message="File copying is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot copy file. Press the Write button ▶ to perform the operation." panic=False <|
## We defer the `Writable_File` conversion after the 'disallow links' check, ## We defer the `Writable_File` conversion after the 'disallow links' check,
because the conversion would already start resolving the data link too soon. because the conversion would already start resolving the data link too soon.
destination_writable = Writable_File.from destination destination_writable = Writable_File.from destination
@ -695,7 +695,7 @@ type File
destination file already exists. Defaults to `False`. destination file already exists. Defaults to `False`.
move_to : File_Like -> Boolean -> Any ! File_Error move_to : File_Like -> Boolean -> Any ! File_Error
move_to self (destination : File_Like) (replace_existing : Boolean = False) = Data_Link_Helpers.disallow_links_in_move self destination <| move_to self (destination : File_Like) (replace_existing : Boolean = False) = Data_Link_Helpers.disallow_links_in_move self destination <|
Context.Output.if_enabled disabled_message="File moving is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot move file. Press the Write button ▶ to perform the operation." panic=False <|
## We defer the `Writable_File` conversion after the 'disallow links' check, ## We defer the `Writable_File` conversion after the 'disallow links' check,
because the conversion would already start resolving the data link too soon. because the conversion would already start resolving the data link too soon.
destination_writable = Writable_File.from destination destination_writable = Writable_File.from destination

View File

@ -131,6 +131,12 @@ make_data_cleanse_vector_selector display:Display=Display.Always =
options = patterns.map f-> Option f (".." + f) options = patterns.map f-> Option f (".." + f)
Widget.Multiple_Choice values=options display=display Widget.Multiple_Choice values=options display=display
## PRIVATE
Creates a Single_Choice Widget for Any selectors with all types enabled.
make_all_selector : Display -> Widget
make_all_selector display:Display=..Always -> Widget =
make_any_selector display add_text=True add_number=True add_boolean=True add_date=True add_time=True add_date_time=True add_nothing=True
## PRIVATE ## PRIVATE
Creates a Single_Choice Widget for Any selectors. Creates a Single_Choice Widget for Any selectors.
make_any_selector : Display -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget make_any_selector : Display -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget

View File

@ -360,7 +360,7 @@ type Connection
representing the query to execute. representing the query to execute.
execute_update : Text | SQL_Statement -> Integer execute_update : Text | SQL_Statement -> Integer
execute_update self query = execute_update self query =
Execution_Context.Output.if_enabled disabled_message="Executing update queries is forbidden as the Output context is disabled." panic=False <| Execution_Context.Output.if_enabled disabled_message="As writing is disabled, cannot execute an update query. Press the Write button ▶ to perform the operation." panic=False <|
statement_setter = self.dialect.get_statement_setter statement_setter = self.dialect.get_statement_setter
self.jdbc_connection.with_prepared_statement query statement_setter stmt-> self.jdbc_connection.with_prepared_statement query statement_setter stmt->
check_statement_is_allowed self stmt check_statement_is_allowed self stmt
@ -384,7 +384,7 @@ type Connection
representing the query to execute. representing the query to execute.
execute : Text | SQL_Statement -> Integer execute : Text | SQL_Statement -> Integer
execute self query = execute self query =
Execution_Context.Output.if_enabled disabled_message="Executing update queries is forbidden as the Output context is disabled." panic=False <| Execution_Context.Output.if_enabled disabled_message="As writing is disabled, cannot execute an update query. Press the Write button ▶ to perform the operation." panic=False <|
result = self.jdbc_connection.execute query result = self.jdbc_connection.execute query
stmt = result.second stmt = result.second
check_statement_is_allowed self stmt check_statement_is_allowed self stmt

View File

@ -21,7 +21,7 @@ type Postgres_Data_Link_Setup
## PRIVATE ## PRIVATE
save_as_data_link self destination on_existing_file:Existing_File_Behavior = case self of save_as_data_link self destination on_existing_file:Existing_File_Behavior = case self of
Postgres_Data_Link_Setup.Available details -> Context.Output.if_enabled disabled_message="Saving a connection to data link requires the Output context." panic=False <| Postgres_Data_Link_Setup.Available details -> Context.Output.if_enabled disabled_message="As writing is disabled, cannot save to a Data Link. Press the Write button ▶ to perform the operation." panic=False <|
case destination of case destination of
_ : Enso_File -> _ : Enso_File ->
replace_existing = case on_existing_file of replace_existing = case on_existing_file of

View File

@ -101,7 +101,7 @@ type Image
@path (Widget.Text_Input display=Display.Always) @path (Widget.Text_Input display=Display.Always)
write : Writable_File -> (Write_Flag | Vector) -> Nothing ! File_Error write : Writable_File -> (Write_Flag | Vector) -> Nothing ! File_Error
write self path:Writable_File flags=[] = write self path:Writable_File flags=[] =
Context.Output.if_enabled disabled_message="Writing the image to a file is forbidden as the Output context is disabled." panic=False <| Context.Output.if_enabled disabled_message="As writing is disabled, cannot write to a file. Press the Write button ▶ to perform the operation." panic=False <|
write_flags = case flags of write_flags = case flags of
_ : Vector -> flags _ : Vector -> flags
_ -> [flags] _ -> [flags]

View File

@ -188,7 +188,7 @@ class RuntimeExecutionEnvironmentTest
IF_ENABLED_METH_CALL, IF_ENABLED_METH_CALL,
Api.ExpressionUpdate.Payload Api.ExpressionUpdate.Payload
.Panic( .Panic(
"Forbidden operation: The Output context is disabled.", "The Output context is disabled.",
Seq(idRes) Seq(idRes)
), ),
false false
@ -292,7 +292,7 @@ class RuntimeExecutionEnvironmentTest
IF_ENABLED_METH_CALL, IF_ENABLED_METH_CALL,
Api.ExpressionUpdate.Payload Api.ExpressionUpdate.Payload
.Panic( .Panic(
"Forbidden operation: The Input context is disabled.", "The Input context is disabled.",
Seq(idRes) Seq(idRes)
), ),
false false

View File

@ -20,12 +20,11 @@ import org.enso.interpreter.runtime.error.PanicException;
@BuiltinMethod( @BuiltinMethod(
type = "Dictionary", type = "Dictionary",
name = "insert", name = "insert_builtin",
description = description =
""" """
Returns newly created hash map with the given key value mapping. Returns newly created hash map with the given key value mapping.
""", """)
autoRegister = false)
@GenerateUncached @GenerateUncached
public abstract class HashMapInsertNode extends Node { public abstract class HashMapInsertNode extends Node {

View File

@ -84,7 +84,7 @@ type Arity_Error
type Forbidden_Operation type Forbidden_Operation
Error message Error message
to_display_text self = "Forbidden operation: "+self.message to_display_text self = self.message
## PRIVATE ## PRIVATE
A helper that replaces complicated `Text.replace` from main distribution, used for simple error message formatting. A helper that replaces complicated `Text.replace` from main distribution, used for simple error message formatting.