feat: Ristrutturazione completa del progetto

This commit is contained in:
Maicol Battistini 2023-04-20 20:00:38 +02:00
parent 805cc35334
commit 2ea9606a38
No known key found for this signature in database
224 changed files with 9985 additions and 15363 deletions

View File

@ -1,16 +0,0 @@
{
"directory": [
"resources/js"
],
"delete": true,
"exclude": [
"_material.ts",
"app.ts",
"styles.ts"
],
"include": [
".(?<!d\\.)(ts|tsx)$"
],
"location": "all",
"singleQuotes": true
}

View File

@ -31,61 +31,12 @@ ij_css_hex_color_upper_case = false
ij_css_keep_blank_lines_in_code = 2
ij_css_keep_indents_on_empty_lines = false
ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.feature]
indent_size = 2
ij_gherkin_keep_indents_on_empty_lines = false
[*.less]
indent_size = 2
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_block_comment_add_space = false
ij_less_brace_placement = 0
ij_less_enforce_quotes_on_format = false
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_line_comment_add_space = false
ij_less_line_comment_at_first_column = false
ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_use_double_quotes = true
ij_less_value_alignment = 0
[*.sass]
indent_size = 2
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_enforce_quotes_on_format = false
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_line_comment_add_space = false
ij_sass_line_comment_at_first_column = false
ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_use_double_quotes = true
ij_sass_value_alignment = 0
[*.scss]
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
@ -102,49 +53,12 @@ ij_scss_keep_indents_on_empty_lines = false
ij_scss_keep_single_line_blocks = false
ij_scss_line_comment_add_space = false
ij_scss_line_comment_at_first_column = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[*.styl]
indent_size = 2
ij_stylus_align_closing_brace_with_properties = false
ij_stylus_blank_lines_around_nested_selector = 1
ij_stylus_blank_lines_between_blocks = 1
ij_stylus_brace_placement = 0
ij_stylus_enforce_quotes_on_format = false
ij_stylus_hex_color_long_format = false
ij_stylus_hex_color_lower_case = false
ij_stylus_hex_color_short_format = false
ij_stylus_hex_color_upper_case = false
ij_stylus_keep_blank_lines_in_code = 2
ij_stylus_keep_indents_on_empty_lines = false
ij_stylus_keep_single_line_blocks = false
ij_stylus_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_stylus_space_after_colon = true
ij_stylus_space_before_opening_brace = true
ij_stylus_use_double_quotes = true
ij_stylus_value_alignment = 0
[*.twig]
ij_twig_keep_indents_on_empty_lines = false
ij_twig_spaces_inside_comments_delimiters = true
ij_twig_spaces_inside_delimiters = true
ij_twig_spaces_inside_variable_delimiters = true
[*.vue]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 4
ij_vue_indent_children_of_top_level = template
ij_vue_interpolation_new_line_after_start_delimiter = true
ij_vue_interpolation_new_line_before_end_delimiter = true
ij_vue_interpolation_wrap = off
ij_vue_keep_indents_on_empty_lines = false
ij_vue_spaces_within_interpolation_expressions = true
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
@ -152,6 +66,7 @@ ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
max_line_length = 300
[machete]
indent_style = tab
@ -179,8 +94,8 @@ ij_xml_text_wrap = normal
[{*.ats,*.cts,*.mts,*.ts,*.tsx}]
indent_size = 2
max_line_length = 100
tab_width = 2
max_line_length = 200
ij_continuation_indent_size = 2
ij_wrap_on_typing = true
ij_typescript_align_imports = false
@ -201,7 +116,7 @@ ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
@ -367,7 +282,6 @@ ij_shell_use_google_code_style = false
[{*.cjs,*.js}]
indent_size = 2
max_line_length = 100
tab_width = 2
ij_continuation_indent_size = 2
ij_wrap_on_typing = true
@ -389,7 +303,7 @@ ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
@ -781,23 +695,23 @@ ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}]
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_add_space = false
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_keep_whitespaces_inside = span, pre, textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
@ -808,11 +722,6 @@ ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
[{*.http,*.rest}]
indent_size = 0
ij_continuation_indent_size = 4
ij_http request_call_parameters_wrap = normal
[{*.markdown,*.md}]
ij_markdown_force_one_space_after_blockquote_symbol = true
ij_markdown_force_one_space_after_header_symbol = true
@ -831,102 +740,6 @@ ij_markdown_min_lines_between_paragraphs = 1
ij_markdown_wrap_text_if_long = true
ij_markdown_wrap_text_inside_blockquotes = true
[{*.ps1,*.psd1,*.psm1}]
max_line_length = 115
ij_powershell_align_multiline_binary_operation = false
ij_powershell_align_multiline_chained_methods = false
ij_powershell_align_multiline_for = true
ij_powershell_align_multiline_parameters = true
ij_powershell_align_multiline_parameters_in_calls = false
ij_powershell_binary_operation_wrap = off
ij_powershell_block_brace_style = next_line
ij_powershell_call_parameters_new_line_after_left_paren = false
ij_powershell_call_parameters_right_paren_on_new_line = false
ij_powershell_call_parameters_wrap = off
ij_powershell_catch_on_new_line = true
ij_powershell_class_annotation_wrap = split_into_lines
ij_powershell_class_brace_style = next_line
ij_powershell_else_on_new_line = true
ij_powershell_field_annotation_wrap = off
ij_powershell_finally_on_new_line = true
ij_powershell_for_statement_new_line_after_left_paren = false
ij_powershell_for_statement_right_paren_on_new_line = false
ij_powershell_for_statement_wrap = off
ij_powershell_keep_blank_lines_in_code = 2
ij_powershell_keep_first_column_comment = true
ij_powershell_keep_line_breaks = true
ij_powershell_keep_simple_blocks_in_one_line = false
ij_powershell_keep_simple_classes_in_one_line = false
ij_powershell_keep_simple_lambdas_in_one_line = true
ij_powershell_keep_simple_methods_in_one_line = false
ij_powershell_method_annotation_wrap = split_into_lines
ij_powershell_method_brace_style = next_line
ij_powershell_method_call_chain_wrap = off
ij_powershell_method_parameters_new_line_after_left_paren = false
ij_powershell_method_parameters_right_paren_on_new_line = false
ij_powershell_method_parameters_wrap = off
ij_powershell_parameter_annotation_wrap = off
ij_powershell_parentheses_expression_new_line_after_left_paren = false
ij_powershell_parentheses_expression_right_paren_on_new_line = false
ij_powershell_space_after_colon = true
ij_powershell_space_after_comma = true
ij_powershell_space_after_for_semicolon = true
ij_powershell_space_after_type_cast = false
ij_powershell_space_before_annotation_parameter_list = false
ij_powershell_space_before_array_initializer_left_brace = true
ij_powershell_space_before_catch_keyword = true
ij_powershell_space_before_catch_left_brace = true
ij_powershell_space_before_class_left_brace = true
ij_powershell_space_before_colon = true
ij_powershell_space_before_comma = false
ij_powershell_space_before_do_left_brace = true
ij_powershell_space_before_else_keyword = true
ij_powershell_space_before_else_left_brace = true
ij_powershell_space_before_finally_keyword = true
ij_powershell_space_before_finally_left_brace = true
ij_powershell_space_before_for_left_brace = true
ij_powershell_space_before_for_parentheses = true
ij_powershell_space_before_for_semicolon = false
ij_powershell_space_before_if_left_brace = true
ij_powershell_space_before_if_parentheses = true
ij_powershell_space_before_method_call_parentheses = false
ij_powershell_space_before_method_left_brace = true
ij_powershell_space_before_method_parentheses = false
ij_powershell_space_before_switch_left_brace = true
ij_powershell_space_before_switch_parentheses = true
ij_powershell_space_before_try_left_brace = true
ij_powershell_space_before_while_keyword = true
ij_powershell_space_before_while_left_brace = true
ij_powershell_space_before_while_parentheses = true
ij_powershell_space_within_empty_method_call_parentheses = false
ij_powershell_space_within_empty_method_parentheses = false
ij_powershell_spaces_around_additive_operators = true
ij_powershell_spaces_around_assignment_operators = true
ij_powershell_spaces_around_bitwise_operators = true
ij_powershell_spaces_around_logical_operators = true
ij_powershell_spaces_around_method_ref_dbl_colon = false
ij_powershell_spaces_around_multiplicative_operators = true
ij_powershell_spaces_around_relational_operators = true
ij_powershell_spaces_around_unary_operator = false
ij_powershell_spaces_within_annotation_parentheses = false
ij_powershell_spaces_within_braces = true
ij_powershell_spaces_within_brackets = false
ij_powershell_spaces_within_cast_parentheses = false
ij_powershell_spaces_within_for_parentheses = false
ij_powershell_spaces_within_if_parentheses = false
ij_powershell_spaces_within_method_call_parentheses = false
ij_powershell_spaces_within_method_parentheses = false
ij_powershell_spaces_within_parentheses = false
ij_powershell_spaces_within_switch_parentheses = false
ij_powershell_spaces_within_while_parentheses = false
ij_powershell_special_else_if_treatment = true
ij_powershell_while_on_new_line = false
ij_powershell_wrap_first_method_in_call_chain = false
ij_powershell_wrap_long_lines = false
[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}]
ij_toml_keep_indents_on_empty_lines = false
[{*.yaml,*.yml}]
indent_size = 2
ij_yaml_align_values_properties = do_not_align
@ -938,4 +751,4 @@ ij_yaml_keep_line_breaks = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true
ij_yaml_spaces_within_brackets = true

View File

@ -2,5 +2,8 @@ root: true
extends:
- '@maicol07'
rules:
import/export: 'off'
import/no-cycle: 'off'
import/prefer-default-export: 'warn'
max-len:
- "error"
- "code": 200
consistent-return: 'off'

2
.gitignore vendored
View File

@ -4,6 +4,7 @@ composer.lock
composer.local.json
public/build
public/modules
public/vendor
.idea/inertia.xml
.idea/git_toolbox_prj.xml
.php-cs-fixer.cache
@ -17,6 +18,7 @@ _ide_helper_models.php
.idea/sshConfigs.xml
.idea/watcherTasks.xml
.idea/webServers.xml
storage/dotenv-editor/backups
# Created by https://www.toptal.com/developers/gitignore/api/laravel,composer,phpstorm,phpstorm+iml
# Edit at https://www.toptal.com/developers/gitignore?templates=laravel,composer,phpstorm,phpstorm+iml

6
.idea/GitLink.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="uk.co.ben_gibson.git.link.SettingsState">
<option name="host" value="72037fcc-cb9c-4c22-960a-ffe73fd5e229" />
</component>
</project>

View File

@ -59,6 +59,7 @@
<data directive="@endunless" />
<data directive="@endverbatim" />
<data directive="@endwhile" />
<data directive="@entangle" injection="true" prefix="&lt;?php \print_r(" suffix="); ?&gt;" />
<data directive="@env" injection="true" prefix="&lt;?php if(app()-&gt;environment(" suffix=")): ?&gt;" />
<data directive="@error" injection="true" prefix="&lt;?php $__errorArgs = [" suffix="];&#10;$__bag = $errors-&gt;getBag($__errorArgs[1] ?? 'default');&#10;if ($__bag-&gt;has($__errorArgs[0])) :&#10;if (isset($message)) { $__messageOriginal = $message; }&#10;$message = $__bag-&gt;first($__errorArgs[0]); ?&gt;" />
<data directive="@extends" injection="true" prefix="&lt;?php echo $__env-&gt;make(" suffix=", \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))-&gt;render(); ?&gt;" />
@ -79,6 +80,9 @@
<data directive="@js" injection="true" prefix="&lt;?php _bladeDirective(" suffix="); ?&gt;" />
<data directive="@json" injection="true" prefix="&lt;?php echo json_encode(" suffix=") ?&gt;" />
<data directive="@lang" injection="true" prefix="&lt;?php echo app('translator')-&gt;get(" suffix="); ?&gt;" />
<data directive="@livewire" injection="true" prefix="&lt;?php \Livewire\Livewire::mount(" suffix="); ?&gt;" />
<data directive="@livewireScripts" />
<data directive="@livewireStyles" />
<data directive="@method" injection="true" prefix="&lt;?php echo method_field(" suffix="); ?&gt;" />
<data directive="@once" />
<data directive="@overwrite" />
@ -97,8 +101,11 @@
<data directive="@slot" injection="true" prefix="&lt;?php $__env-&gt;slot(" suffix="); ?&gt;" />
<data directive="@stack" injection="true" prefix="&lt;?php echo $__env-&gt;yieldPushContent(" suffix="); ?&gt;" />
<data directive="@stop" />
<data directive="@style" injection="true" prefix="class=&quot;&lt;?php echo \Illuminate\Support\Arr::toCssStyles(" suffix=")?&gt;&quot;" />
<data directive="@svg" injection="true" prefix="&lt;?php echo e(svg(" suffix=")); ?&gt;" />
<data directive="@switch" injection="true" prefix="&lt;?php switch(" suffix="): ?&gt;" />
<data directive="@tag" injection="true" prefix="&lt;?php echo vite_tag(" suffix="); ?&gt;" />
<data directive="@this" />
<data directive="@unless" injection="true" prefix="&lt;?php if (! (" suffix=")): ?&gt;" />
<data directive="@unset" injection="true" prefix="&lt;?php unset(" suffix="); ?&gt;" />
<data directive="@verbatim" />

View File

@ -1,6 +1,7 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="140" />
<JSCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="USE_DOUBLE_QUOTES" value="false" />
@ -49,13 +50,14 @@
<codeStyleSettings language="SCSS">
<indentOptions>
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="RIGHT_MARGIN" value="100" />
<option name="RIGHT_MARGIN" value="200" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="METHOD_CALL_CHAIN_WRAP" value="2" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="IF_BRACE_FORCE" value="1" />
<option name="DOWHILE_BRACE_FORCE" value="1" />
<option name="WHILE_BRACE_FORCE" value="1" />

15
.idea/codeception.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Codeception">
<option name="configurations">
<list>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
</list>
</option>
</component>
</project>

View File

@ -1,10 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<option name="myName" value="Project Default" />
<inspection_tool class="AnonymousFunctionJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentResultUsedJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToForLoopParameterJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToFunctionParameterJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BadExceptionsProcessingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="BlockStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BreakStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
@ -27,13 +24,18 @@
<inspection_tool class="ConfusingFloatingPointLiteralJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConfusingPlusesOrMinusesJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantOnLHSOfComparisonJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantOnRHSOfComparisonJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ContinueStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ContinueStatementWithLabelJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssBrowserCompatibilityForProperties" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssBrowserCompatibilityForProperties" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myChromeVersion" value="100" />
<option name="myEdgeVersion" value="100" />
<option name="myFirefoxVersion" value="100" />
<option name="myCheckIE" value="false" />
<option name="myOperaVersion" value="100" />
</inspection_tool>
<inspection_tool class="CssConvertColorToHexInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssConvertColorToRgbInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssMissingSemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssNonIntegerLengthInPixels" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="CyclomaticComplexityJS" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="10" />
</inspection_tool>
@ -46,6 +48,7 @@
<inspection_tool class="DuplicateConditionJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DynamicallyGeneratedCodeJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ES6TopLevelAwaitExpression" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="EditorConfigPartialOverride" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="EfferentObjectCouplingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="EmptyCatchBlockJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EmptyClassInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
@ -133,12 +136,10 @@
</inspection_tool>
<inspection_tool class="FunctionNamingConventionJS" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z]*" />
<option name="m_minLength" value="4" />
<option name="m_minLength" value="3" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="FunctionWithInconsistentReturnsJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FunctionWithMultipleLoopsJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FunctionWithMultipleReturnPointsJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GrazieInspection" enabled="true" level="TYPO" enabled_by_default="true" />
<inspection_tool class="HamlNestedTagContent" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HtmlNonExistentInternetResource" enabled="true" level="WARNING" enabled_by_default="true" />
@ -159,26 +160,15 @@
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
<option name="myCustomValuesEnabled" value="false" />
</inspection_tool>
<inspection_tool class="HtmlUnknownBooleanAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<myValues>
<item value="required" />
<item value="raised" />
<item value="outlined" />
<item value="disabled" />
<item value="indeterminate" />
<item value="inner" />
<item value="fixedmenuposition" />
<item value="comfortable" />
<item value="dense" />
<item value="compact" />
</myValues>
<option name="myCustomValuesEnabled" value="false" />
</inspection_tool>
<inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="24">
<list size="9">
<item index="0" class="java.lang.String" itemvalue="nobr" />
<item index="1" class="java.lang.String" itemvalue="noembed" />
<item index="2" class="java.lang.String" itemvalue="comment" />
@ -186,23 +176,8 @@
<item index="4" class="java.lang.String" itemvalue="embed" />
<item index="5" class="java.lang.String" itemvalue="script" />
<item index="6" class="java.lang.String" itemvalue="slot" />
<item index="7" class="java.lang.String" itemvalue="mwc-list-item" />
<item index="8" class="java.lang.String" itemvalue="mwc-menu" />
<item index="9" class="java.lang.String" itemvalue="mwc-list" />
<item index="10" class="java.lang.String" itemvalue="mwc-button" />
<item index="11" class="java.lang.String" itemvalue="mwc-icon-button" />
<item index="12" class="java.lang.String" itemvalue="material-drawer" />
<item index="13" class="java.lang.String" itemvalue="top-app-bar" />
<item index="14" class="java.lang.String" itemvalue="mwc-fab" />
<item index="15" class="java.lang.String" itemvalue="mwc-textfield" />
<item index="16" class="java.lang.String" itemvalue="text-field" />
<item index="17" class="java.lang.String" itemvalue="text-area" />
<item index="18" class="java.lang.String" itemvalue="icon-button" />
<item index="19" class="java.lang.String" itemvalue="mwc-circular-progress" />
<item index="20" class="java.lang.String" itemvalue="mwc-dialog" />
<item index="21" class="java.lang.String" itemvalue="mwc-linear-progress" />
<item index="22" class="java.lang.String" itemvalue="mwc-checkbox" />
<item index="23" class="java.lang.String" itemvalue="mwc-snackbar" />
<item index="7" class="java.lang.String" itemvalue="md-fab" />
<item index="8" class="java.lang.String" itemvalue="md-icon" />
</list>
</value>
</option>
@ -221,7 +196,6 @@
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IncorrectFormatting" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="IncrementDecrementResultUsedJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InnerHTMLJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InvertedIfElseConstructsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="IsNullFunctionUsageInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="JSClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
@ -245,9 +219,8 @@
</inspection_tool>
<inspection_tool class="LongInheritanceChainInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LongLine" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MagicNumberJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MessDetectorValidationInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="MultipleReturnStatementsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodShouldBeFinalInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NegatedConditionalExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NegatedIfStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedAssignmentJS" enabled="true" level="WARNING" enabled_by_default="true" />
@ -261,6 +234,10 @@
<option name="m_limit" value="5" />
</inspection_tool>
<inspection_tool class="NonBlockStatementBodyJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NullPointerExceptionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NullableTypeFormatInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="nullableTypeFormat" value="SHORT" />
</inspection_tool>
<inspection_tool class="ObjectAllocationIgnoredJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OffsetOperationsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="OverlyComplexArithmeticExpressionJS" enabled="true" level="WARNING" enabled_by_default="true">
@ -286,13 +263,13 @@
<option name="ALLOW_RISKY_RULES" value="true" />
</inspection_tool>
<inspection_tool class="PhpCSValidationInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpClassConstantAccessedViaChildClassInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpClassHasTooManyDeclaredMembersInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpClassNamingConventionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpComplexClassInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpComplexFunctionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpCompoundNamespaceDepthInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpConstantNamingConventionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpEnforceDocCommentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpFeatureEnvyLocalInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpFunctionCyclomaticComplexityInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpFunctionNamingConventionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
@ -302,10 +279,11 @@
<inspection_tool class="PhpMemberCanBePulledUpInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodNamingConventionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodOrClassCallIsNotCaseSensitiveInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingDocCommentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingDocCommentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="CHECK_CLASS" value="false" />
</inspection_tool>
<inspection_tool class="PhpMissingParentCallCommonInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingParentCallMagicInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingStrictTypesDeclarationInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingVisibilityInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpModifierOrderInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpNewClassMissingParameterListInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
@ -322,7 +300,9 @@
<inspection_tool class="PhpUnnecessaryDoubleQuotesInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUsageOfSilenceOperatorInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpVarUsageInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpVariableNamingConventionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpVariableNamingConventionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="m_minLength" value="1" />
</inspection_tool>
<inspection_tool class="PhpVariableVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PlatformDetectionJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PointlessBitwiseExpressionJS" enabled="true" level="WARNING" enabled_by_default="true">
@ -401,6 +381,7 @@
<inspection_tool class="StatementsPerFunctionJS" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="30" />
</inspection_tool>
<inspection_tool class="StringCurlyInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="StringLiteralBreaksHTMLJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="TailRecursionJS" enabled="true" level="WARNING" enabled_by_default="true" />
@ -422,12 +403,10 @@
</inspection_tool>
<inspection_tool class="UnusedDefine" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UsingInclusionReturnValueInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="VoidExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="W3CssValidation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myCssVersion" value="css3svg" />
<option name="myIgnoreVendorSpecificProperties" value="false" />
</inspection_tool>
<inspection_tool class="XHTMLIncompatabilitiesJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="bashproExecutableNoShebang" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="bashproShebangNotExecutable" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>

View File

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Default" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{@types/prop-types, osm3/node_modules}" />
<file url="file://$PROJECT_DIR$" libraries="{osm3/node_modules}" />
<file url="PROJECT" libraries="{osm3/node_modules}" />
</component>
</project>

View File

@ -10,10 +10,37 @@
<component name="LaravelIdeaMainSettings">
<option name="codeGeneration">
<LaravelCodeGeneration>
<option name="generationBooleanSettings">
<map>
<entry key="createConfigFile:inModules" value="true" />
<entry key="createConsoleCommand:inModules" value="true" />
<entry key="createDatabaseMigration:inModules" value="true" />
<entry key="createEvent:inModules" value="true" />
<entry key="createListener:inModules" value="true" />
<entry key="createMailable:inModules" value="true" />
<entry key="createMiddleware:inModules" value="true" />
<entry key="createNotification:inModules" value="true" />
</map>
</option>
<option name="generationStringSettings">
<map>
<entry key="createBladeComponent:classSuffix" value="" />
<entry key="createChannel:classSuffix" value="Channel" />
<entry key="createConsoleCommand:classSuffix" value="Command" />
<entry key="createController:classSuffix" value="Controller" />
<entry key="createDatabaseClassFactory:classSuffix" value="Factory" />
<entry key="createEloquentScope:namespace" value="Models\Scopes" />
<entry key="createEvent:classSuffix" value="Event" />
<entry key="createFormRequest:classSuffix" value="Request" />
<entry key="createJob:classSuffix" value="Job" />
<entry key="createListener:classSuffix" value="Listener" />
<entry key="createMailable:classSuffix" value="Mail" />
<entry key="createMiddleware:classSuffix" value="Middleware" />
<entry key="createModel:classSuffix" value="" />
<entry key="createModel:namespace" value="Models" />
<entry key="createNotification:classSuffix" value="Notification" />
<entry key="createResourceController:classSuffix" value="Controller" />
<entry key="createServiceProvider:classSuffix" value="ServiceProvider" />
</map>
</option>
</LaravelCodeGeneration>
@ -26,6 +53,11 @@
<entry key="createModel:namespace" value="Models" />
</map>
</option>
<option name="translation">
<LaravelTranslation>
<option name="defaultPath" value="lang" />
</LaravelTranslation>
</option>
<option name="userClassName" value="App\Models\User" />
</component>
</project>

13
.idea/phpspec.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPSpec">
<suites>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
</suites>
</component>
</project>

View File

@ -5,6 +5,7 @@
<list>
<option value="$PROJECT_DIR$/tests/Unit" />
<option value="$PROJECT_DIR$/tests/Feature" />
<option value="$PROJECT_DIR$/tests" />
</list>
</option>
</component>

View File

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="Frontend" pattern="file[osm3]:resources/js/*.ts||file[osm3]:resources/js/*.tsx" />
</component>

7
.idea/symfony2.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Symfony2PluginSettings">
<option name="dismissEnableNotification" value="true" />
<option name="profilerCsvPath" value="" />
</component>
</project>

4
.npmrc
View File

@ -1,8 +1,6 @@
public-hoist-pattern[]=*@material*
public-hoist-pattern[]=autoprefixer
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=autoprefixer
public-hoist-pattern[]=*postcss*
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*vite*
public-hoist-pattern[]=workbox-window
node-linker=hoisted

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v19.7.0

View File

@ -1,11 +1,24 @@
<?php
// Source: https://github.com/laravel/pint/blob/main/resources/presets/laravel.php
$finder = PhpCsFixer\Finder::create()
->files()
->exclude('.couscous')
->exclude('node_modules')
->exclude('vendor')
->exclude('tests')
->notName([
'_ide_helper_actions.php',
'_ide_helper_models.php',
'_ide_helper.php',
'.phpstorm.meta.php',
'*.blade.php',
])
->exclude([
'bootstrap/cache',
'build',
'node_modules',
'storage',
'vendor',
'tests',
])
->ignoreDotFiles(true)
->ignoreVCS(true)
->in(__DIR__);
@ -16,11 +29,198 @@ $config->setRules([
'array_syntax' => ['syntax' => 'short'],
'yoda_style' => false,
'echo_tag_syntax' => ['format' => 'long'],
'ordered_imports' => true,
'no_alternative_syntax' => true,
'global_namespace_import' => true,
'ordered_class_elements' => true,
'phpdoc_order' => true,
'array_indentation' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => [
'continue',
'return',
],
],
'braces' => [
'allow_single_line_anonymous_class_with_empty_body' => true,
'allow_single_line_closure' => true,
'position_after_control_structures' => 'same',
'position_after_functions_and_oop_constructs' => 'next',
'position_after_anonymous_constructs' => 'next',
],
'curly_braces_position' => [
'control_structures_opening_brace' => 'same_line',
'functions_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_functions_opening_brace' => 'same_line',
'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
'allow_single_line_empty_anonymous_classes' => false,
'allow_single_line_anonymous_functions' => false,
],
'cast_spaces' => true,
'class_attributes_separation' => [
'elements' => [
'const' => 'one',
'method' => 'one',
'property' => 'one',
'trait_import' => 'none',
],
],
'class_definition' => [
'multi_line_extends_each_single_line' => true,
'single_item_single_line' => true,
'single_line' => true,
],
'clean_namespace' => true,
'compact_nullable_typehint' => true,
'concat_space' => [
'spacing' => 'none',
],
'constant_case' => ['case' => 'lower'],
'declare_equal_normalize' => true,
'elseif' => true,
'encoding' => true,
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => true,
'function_typehint_space' => true,
'general_phpdoc_tag_rename' => true,
'heredoc_to_nowdoc' => true,
'include' => true,
'increment_style' => ['style' => 'post'],
'indentation_type' => true,
'integer_literal_case' => true,
'lambda_not_used_import' => true,
'linebreak_after_opening_tag' => true,
'line_ending' => true,
'list_syntax' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_method_casing' => true,
'magic_constant_casing' => true,
'method_argument_space' => [
'on_multiline' => 'ignore',
],
'multiline_whitespace_before_semicolons' => [
'strategy' => 'no_multi_line',
],
'native_function_casing' => true,
'native_function_type_declaration_casing' => true,
'no_alias_functions' => true,
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => true,
'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_closing_tag' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => [
'tokens' => [
'extra',
'throw',
'use',
],
],
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => [
'use' => 'echo',
],
'no_multiline_whitespace_around_double_arrow' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_after_function_name' => true,
'no_space_around_double_colon' => true,
'no_spaces_around_offset' => [
'positions' => ['inside', 'outside'],
],
'no_spaces_inside_parenthesis' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
'allow_unused_params' => true,
],
'no_trailing_comma_in_singleline' => true,
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_unneeded_control_parentheses' => [
'statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield'],
],
'no_unneeded_curly_braces' => true,
'no_unset_cast' => true,
'no_unused_imports' => true,
'no_unreachable_default_argument_value' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'psr_autoloading' => false,
'phpdoc_indent' => true,
'phpdoc_inline_tag_normalizer' => true,
'phpdoc_no_access' => true,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => [
'order' => ['param', 'return', 'throws'],
],
'phpdoc_scalar' => true,
'phpdoc_separation' => [
'groups' => [
['deprecated', 'link', 'see', 'since'],
['author', 'copyright', 'license'],
['category', 'package', 'subpackage'],
['property', 'property-read', 'property-write'],
['param', 'return'],
],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => false,
'phpdoc_to_comment' => false,
'phpdoc_tag_type' => [
'tags' => [
'inheritdoc' => 'inline',
],
],
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => false,
'short_scalar_cast' => true,
'simplified_null_return' => false,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => [
'elements' => ['const', 'property'],
],
'single_import_per_statement' => true,
'single_line_after_imports' => true,
'single_line_comment_style' => [
'comment_types' => ['hash'],
],
'single_quote' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'statement_indentation' => false,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
'trim_array_spaces' => true,
'types_spaces' => true,
'unary_operator_spaces' => true,
'visibility_required' => [
'elements' => ['method', 'property'],
],
'whitespace_after_comma_in_array' => true,
])
->setRiskyAllowed(true)
->setUsingCache(true)
->setFinder($finder);
return $config;

View File

@ -1,13 +1,14 @@
{
"extends": [
"stylelint-config-standard",
"stylelint-config-recommended-scss",
"stylelint-config-idiomatic-order",
"stylelint-config-html"
],
"rules": {
"indentation": 4,
"selector-type-no-unknown": null,
"no-eol-whitespace": null
}
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-clean-order",
"stylelint-config-html"
],
"rules": {
"indentation": 4,
"selector-type-no-unknown": null,
"no-eol-whitespace": null,
"scss/at-extend-no-missing-placeholder": null,
"custom-property-pattern": "^_?([a-z][a-z0-9]*)(-[a-z0-9]+)*$"
}
}

View File

@ -42,7 +42,8 @@ Secondo questa definizione, OpenSTAManager riesce a generalizzare al proprio int
della contabilità e della gestione del magazzino, presentando inoltre moduli piuttosto avanzati e destinati a
complementare l'attività aziendale in relazione agli interventi di assistenza della realtà lavorativa in oggetto.
La documentazione ufficiale è disponibile all'indirizzo [https://docs.openstamanager.com/](https://docs.openstamanager.com/).
La documentazione ufficiale è disponibile
all'indirizzo [https://docs.openstamanager.com/](https://docs.openstamanager.com/).
## Requisiti
@ -50,34 +51,45 @@ L'installazione del gestionale richiede un server web con le seguenti tecnologie
- [PHP](https://php.net) 8.0+
- Un database a scelta tra:
- [MySQL](https://www.mysql.com) 5.7+ (consigliato)
- [PostgreSQL](https://www.postgresql.org) 9.6+
- [SQLite](https://www.sqlite.org) 3.8.8+ (non consigliato, in quanto viene salvato "in chiaro" sul filesystem del
server)
- [SQL Server](https://www.microsoft.com/it-it/sql-server) 2017+
- [MySQL](https://www.mysql.com) 5.7+ (consigliato) / [MariaDB](https://mariadb.org/) 10.3+
- [PostgreSQL](https://www.postgresql.org) 9.6+
- [SQLite](https://www.sqlite.org) 3.8.8+ (non consigliato, in quanto viene salvato "in chiaro" sul filesystem del
server)
- [SQL Server](https://www.microsoft.com/it-it/sql-server) 2017+
- Accesso SSH (**facoltativo**)
- [Composer](https://getcomposer.org/) installato e disponibile da linea di comando (**facoltativo**)
e un dispositivo (client) con le seguenti tecnologie disponibili:
- Browser moderno, a scelta tra:
- [Microsoft Edge](https://www.microsoft.com/it-it/edge) 83+
- [Google Chrome](https://www.google.com/intl/it_it/chrome/) 93+
- [Mozilla Firefox](https://www.mozilla.org/it/firefox/) 92+
- [Opera](https://www.opera.com) 79+
- [Safari](https://www.apple.com/it/safari/) (attualmente solo nella sua versione [Technology Preview](https://developer.apple.com/safari/technology-preview/) 33+)
- [Microsoft Edge](https://www.microsoft.com/it-it/edge) 83+
- [Google Chrome](https://www.google.com/intl/it_it/chrome/) 93+
- [Mozilla Firefox](https://www.mozilla.org/it/firefox/) 92+
- [Opera](https://www.opera.com) 79+
- [Safari](https://www.apple.com/it/safari/) (attualmente solo nella sua
versione [Technology Preview](https://developer.apple.com/safari/technology-preview/) 33+)
_Alcune note:_
- _**Non** è supportato nessun browser diverso dai precedenti, nemmeno in versioni più datate. Pertanto, anche se il
gestionale potrebbe funzionare, non è garantita assistenza su tali browser. Si citano come esempi: Internet Explorer,
Samsung Internet, Opera Mini, Opera Mobile, UC Browser, Safari per iOS._
- _È fortemente consigliato aggiornare sempre il proprio browser alla versione più recente e non interrompere la ricezione degli aggiornamenti raggiunta la versione minima indicata_
- _È fortemente consigliato aggiornare sempre il proprio browser alla versione più recente e non interrompere la
ricezione degli aggiornamenti raggiunta la versione minima indicata_
- _Il gestionale viene testato sui 3 principali browser (Edge, Chrome, Firefox) nella loro versione più recente_
Per ulteriori informazioni sui pacchetti che forniscono questi elementi di default, visitare la
sezione [Installazione](https://docs.openstamanager.com/guide/configurazione/installazione) della documentazione.
### Dipendenze
Per installare le dipendenze del gestionale sono necessari i seguenti strumenti (installati sul server web o su un PC da utilizzare per la
preparazione del progetto):
- [Composer](https://getcomposer.org/)
- [Node.js](https://nodejs.org/) 19+
- [Git](https://git-scm.com/) (facoltativo, ma consigliato)
## Installazione
Per procedere all'installazione è necessario seguire i seguenti punti:
@ -86,10 +98,10 @@ Per procedere all'installazione è necessario seguire i seguenti punti:
2. Creare una cartella (ad esempio `openstamanager`) nella root del server web installato ed estrarvi il contenuto della
release scaricata. Il percorso della cartella root del server varia in base al software in utilizzo:
- LAMP (`/var/www/html`)
- XAMPP (`C:/xampp/htdocs` per Windows, `/opt/lampp/htdocs/` per Linux, `/Applications/XAMPP/htdocs/` per MAC)
- WAMP (`C:\wamp\www`)
- MAMP (`C:\MAMP\htdocs` per Windows, `/Applications/MAMP/htdocs` per MAC)
- LAMP (`/var/www/html`)
- XAMPP (`C:/xampp/htdocs` per Windows, `/opt/lampp/htdocs/` per Linux, `/Applications/XAMPP/htdocs/` per MAC)
- WAMP (`C:\wamp\www`)
- MAMP (`C:\MAMP\htdocs` per Windows, `/Applications/MAMP/htdocs` per MAC)
3. Creare un database vuoto (tramite [PHPMyAdmin](http://localhost/phpmyadmin/) o riga di comando).
4. Accedere a [http://localhost/openstamanager](http://localhost/openstamanager) dal vostro browser.
5. Inserire i dati di configurazione per collegarsi al database.
@ -108,7 +120,8 @@ su GitHub (per versioni precedenti alla 2.3,
visitare [SourceForge](https://sourceforge.net/projects/openstamanager/files)).
Nel caso utilizziate il programma per uso commerciale, si consiglia di scaricare le release disponibili nel sito
ufficiale del progetto ([https://www.openstamanager.com](https://www.openstamanager.com)), evitando di utilizzare direttamente il codice della
ufficiale del progetto ([https://www.openstamanager.com](https://www.openstamanager.com)), evitando di utilizzare
direttamente il codice della
repository. Se siete inoltre interessati a supporto e assistenza professionali, li potete richiedere
nella [sezione dedicata](https://www.openstamanager.com/per-le-aziende/).
@ -147,7 +160,8 @@ La community è una componente importante in un progetto open-source, perché me
di loro e permette pertanto l'individuazione di soluzioni innovative e migliori.
Siamo presenti su [Facebook](https://www.facebook.com/openstamanager), e il nostro forum ufficiale è disponibile
all'indirizzo [https://forum.openstamanager.com](https://forum.openstamanager.com), dove potete segnalare i vostri problemi e soddisfare le vostre
all'indirizzo [https://forum.openstamanager.com](https://forum.openstamanager.com), dove potete segnalare i vostri
problemi e soddisfare le vostre
curiosità nelle sezioni più adeguate:
- [Idee, suggerimenti e consigli](https://forum.openstamanager.com/viewforum.php?f=1)

View File

@ -0,0 +1,40 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\CreatesNewUsers;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Validate and create a newly registered user.
*
* @param array<string, string> $input
*/
public function create(array $input): User
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique(User::class),
],
'password' => $this->passwordRules(),
])->validate();
return User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
]);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Actions\Fortify;
use Laravel\Fortify\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, \Illuminate\Contracts\Validation\Rule|array|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', new Password(), 'confirmed'];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($user->id),
],
])->validateWithBag('updateProfileInformation');
if ($input['email'] !== $user->email &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
])->save();
}
}
/**
* Update the given verified user's profile information.
*
* @param array<string, string> $input
*/
protected function updateVerifiedUser(User $user, array $input): void
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
])->save();
$user->sendEmailVerificationNotification();
}
}

View File

@ -3,7 +3,6 @@
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use LaravelJsonApi\Exceptions\ExceptionParser;
use Throwable;
class Handler extends ExceptionHandler
@ -36,9 +35,5 @@ class Handler extends ExceptionHandler
$this->reportable(static function (Throwable $e): void {
//
});
$this->renderable(
ExceptionParser::make()->renderable()
);
}
}

View File

@ -0,0 +1,204 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use function in_array;
use PDOException;
use RuntimeException;
class SetupController extends Controller
{
public function __construct(private \Jackiedo\DotenvEditor\DotenvEditor $dotenvEditor)
{
}
/**
* Test the database connection with the request data.
*/
final public function testDatabase(Request $request): Response|JsonResponse
{
try {
$request->validate([
'database_driver' => 'required|string',
'database_host' => 'required|string',
'database_username' => 'required|string',
'database_password' => 'nullable|string',
'database_name' => 'required|string',
'database_port' => 'required|integer',
]);
} catch (ValidationException $e) {
return response()->json([
'message' => $e->getMessage(),
'errors' => $e->errors(),
], Response::HTTP_BAD_REQUEST);
}
$database_name = $request->input('database_name');
// Configure test connection
config(['database.connections.testing' => [
'driver' => $request->input('database_driver', 'mysql'),
'host' => $request->input('database_host'),
'port' => $request->input('database_port', '3306'),
'password' => $request->input('database_password'),
'database' => $database_name,
'username' => $request->input('database_username'),
]]);
$connection = DB::connection('testing');
try {
// Check DB connection either by checking if we can get PDO object or DB name
$connection->getPdo();
if (empty($connection->getDatabaseName())) {
throw new RuntimeException(__('Database non trovato'));
}
} catch (PDOException|RuntimeException $e) {
return response()->json([
'message' => __('Impossibile connettersi al database: :message', ['message' => $e->getMessage()]),
Response::HTTP_BAD_REQUEST,
]);
}
// Identifying permissions granted to the user
$database_name = Str::replace('_', '\_', $database_name);
$grants = $connection->select($connection->raw('SHOW GRANTS FOR CURRENT_USER'));
$requirements = [
'SELECT',
'INSERT',
'UPDATE',
'CREATE',
'ALTER',
'DROP',
];
foreach ($grants as $result) {
$privileges = current($result);
if (Str::contains($privileges, [" ON `$database_name`.*", ' ON *.*'])) {
$pieces = explode(', ', explode(' ON ', str_replace('GRANT ', '', (string) $privileges), 2)[0]);
// Database-generic permissions
if (in_array('ALL', $pieces) || in_array('ALL PRIVILEGES', $pieces)) {
$requirements = [];
break;
}
// Database-specific permissions
foreach ($requirements as $key => $value) {
if (in_array($value, $pieces)) {
unset($requirements[$key]);
}
}
}
}
if ($requirements === []) {
return response()->noContent();
}
return response()->json([
'message' => __("L'utente del database non ha i seguenti permessi necessari: :permissions_list",
['permissions_list' => implode(', ', $requirements)]
),
], Response::HTTP_BAD_REQUEST);
}
/**
* Save config.
*/
public function save(Request $request): JsonResponse|Response
{
// Check if the database connection is valid
try {
DB::connection()->getPdo();
} catch (PDOException) {
$response = $this->testDatabase($request);
if ($response->getStatusCode() !== Response::HTTP_NO_CONTENT) {
return $response;
}
}
$chmod_result = File::chmod(base_path('.env'), 0644);
try {
$this->dotenvEditor->setKeys([
'DB_CONNECTION' => $request->input('database_driver', 'mysql'),
'DB_HOST' => $request->input('database_host'),
'DB_PORT' => $request->input('database_port'),
'DB_DATABASE' => $request->input('database_name'),
'DB_USERNAME' => $request->input('database_username'),
'DB_PASSWORD' => $request->input('database_password'),
])->save();
} catch (Exception $e) {
return response()->json([
'message' => __('Impossibile scrivere il file di configurazione. :action', [
'action' => $chmod_result ? $e->getMessage() : 'Controllare i permessi del file .env',
]),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Cache config
Artisan::call('cache:clear');
Artisan::call('config:cache');
// Run migrations
Artisan::call('migrate', ['--force' => true]);
try {
$request->validate([
'date_format_short' => 'required|string',
'date_format_long' => 'required|string',
'time_format' => 'required|string',
'locale' => 'sometimes|string',
]);
} catch (ValidationException $e) {
return response()->json([
'message' => $e->getMessage(),
'errors' => $e->errors(),
], Response::HTTP_BAD_REQUEST);
}
settings($request->only(['date_format_short', 'date_format_long', 'time_format']));
settings('locale', $request->input('locale', app()->getLocale()));
return $this->saveAdmin($request);
}
public function saveAdmin(Request $request): Response|JsonResponse
{
try {
$request->validate([
'admin_username' => 'required|string|min:3|max:255|unique:users,username',
'admin_password' => 'required|string|min:8|max:255',
'admin_password_confirmation' => 'required|string|min:8|max:255|same:admin_password',
'admin_email' => 'required|string|email|max:255|unique:users,email',
]);
} catch (ValidationException $e) {
return response()->json([
'message' => $e->getMessage(),
'errors' => $e->errors(),
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
$user = new User();
$user->username = $request->input('username');
$user->email = $request->input('email');
$user->password = Hash::make($request->input('password'));
$user->save();
return response()->noContent();
}
}

View File

@ -10,37 +10,38 @@ use JetBrains\PhpStorm\ArrayShape;
class AuthController extends Controller
{
/**
* Handle an authentication attempt.
*/
public function login(Request $request): JsonResponse|Response
{
try {
$request->validate($this->rules($request));
} catch (ValidationException $e) {
return response()->json(['errors' => $e->errors()], 422);
}
$credentials = $request->only(['username', 'password']);
if (filter_var($request->get('username'), FILTER_VALIDATE_EMAIL)) {
$credentials['email'] = $credentials['username'];
unset($credentials['username']);
}
if (auth()->attempt($credentials, $request->get('remember') === 'on')) {
$request->session()->regenerate();
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}
return response()->noContent();
}
return response()->json([
'errors' => ['invalid_credentials' => __('Le credenziali non sono valide.')],
], Response::HTTP_BAD_REQUEST);
}
// /**
// * Handle an authentication attempt.
// */
// public function login(Request $request): JsonResponse|Response
// {
// try {
// $request->validate($this->rules($request));
// } catch (ValidationException $e) {
// return response()->json(['message' => $e->getMessage(), 'errors' => $e->errors()], Response::HTTP_UNPROCESSABLE_ENTITY);
// }
//
// $credentials = $request->only(['username', 'password']);
//
// // TODO: Rivedere con Laravel 10
// if (filter_var($request->get('username'), FILTER_VALIDATE_EMAIL)) {
// $credentials['email'] = $credentials['username'];
// unset($credentials['username']);
// }
//
// if (auth()->attempt($credentials, $request->get('remember') === 'on')) {
// $request->session()->regenerate();
// if ($request->hasSession()) {
// $request->session()->put('auth.password_confirmed_at', time());
// }
//
// return response()->noContent();
// }
//
// return response()->json([
// 'message' => __('Le credenziali non sono valide.')
// ], Response::HTTP_BAD_REQUEST);
// }
/**
* Log the user out of the application.
@ -57,23 +58,23 @@ class AuthController extends Controller
return response()->noContent();
}
/**
* @return array{username: string, password: string, remember: string}
*/
#[ArrayShape(['username' => 'string', 'password' => 'string', 'remember' => 'string'])]
private function rules(Request $request): array
{
$additional_validation = '';
$db_field = 'username';
if (filter_var($request->input('username'), FILTER_VALIDATE_EMAIL)) {
$additional_validation = '|email';
$db_field = 'email';
}
return [
'username' => "required|string|exists:users,$db_field|$additional_validation",
'password' => 'required|string',
'remember' => 'string|in:on',
];
}
// /**
// * @return array{username: string, password: string, remember: string}
// */
// #[ArrayShape(['username' => 'string', 'password' => 'string', 'remember' => 'string'])]
// private function rules(Request $request): array
// {
// $additional_validation = '';
// $db_field = 'username';
// if (filter_var($request->input('username'), FILTER_VALIDATE_EMAIL)) {
// $additional_validation = '|email';
// $db_field = 'email';
// }
//
// return [
// 'username' => "required|string|exists:users,$db_field|$additional_validation",
// 'password' => 'required|string',
// 'remember' => 'string|in:on',
// ];
// }
}

View File

@ -1,7 +1,10 @@
<?php
/** @noinspection ClassNameCollisionInspection */
namespace App\Http\Controllers;
use App\ModuleServiceProvider;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
@ -11,6 +14,8 @@ use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Nette\Utils\Json;
use Nette\Utils\JsonException;
use ReflectionClass;
class Controller extends BaseController
{
@ -18,33 +23,67 @@ class Controller extends BaseController
use DispatchesJobs;
use ValidatesRequests;
public function getModules(?Request $request = null): JsonResponse|Collection
public function setLanguage(Request $request): JsonResponse
{
$packages = collect(Json::decode(File::get(base_path('vendor/composer/installed.json')))->packages);
$locale = $request->input('locale');
$languages = self::getLanguages();
if ($languages->contains($locale)) {
session()->put('locale', $locale);
session()->save();
app()->setLocale($locale);
$modules = $packages->filter(static fn($package) => $package->type === 'openstamanager-module');
return response()->json(['locale' => app()->getLocale()]);
}
$modules->transform(static function ($module) {
$osm_modules = collect($module->extra->{'osm-modules'});
$module->config = $osm_modules
->mapWithKeys(
static fn($item, $name) => config($name) ?? include base_path("vendor/$module->name/config/$name.php")
)
->reject(null)
->all();
// Modules
$module->modules = $osm_modules->map(static function ($item, $key) use ($module) {
$split = explode('/', (string)$module->name, 2);
$item->moduleFullName = $module->name;
$item->moduleVendor = $split[0];
$item->moduleName = $key;
return $item;
});
return $module;
});
return response()->json(['success' => false, 'message' => __("Locale isn't available"), 'locale' => app()->getLocale()], 400);
}
$filtered = $modules->only($request?->input('filter'));
/**
* @return Collection<string>
*/
public static function getLanguages(): Collection
{
return collect(File::glob(lang_path('*.json')))
->map(static fn (string $file) => File::name($file));
}
return ($request && $request->wantsJson()) ? response()->json($filtered) : $filtered;
/**
* @return Collection<string>
*
* @throws JsonException
*/
public static function getTranslations(): Collection
{
return self::getLanguages()
->mapWithKeys(fn (string $locale) => [$locale => Json::decode(File::get(lang_path("$locale.json")))]);
}
/**
* @return Collection<array{
* name: string,
* description: string,
* slug: string,
* author: string,
* version: string,
* url: string,
* module_path: string
* }>
*/
public function getModules(): Collection
{
return collect(app()->getLoadedProviders())
->keys()
->filter(static fn (string $provider) => (new ReflectionClass($provider))->isSubclassOf(ModuleServiceProvider::class))
->map(static fn (string $provider) => app()->getProvider($provider))
->mapWithKeys(static fn (ModuleServiceProvider $provider) => [$provider::slug() => [
'name' => $provider::name(),
'description' => $provider::description(),
'slug' => $provider::slug(),
'author' => $provider::author(),
'version' => $provider::version(),
'url' => $provider::url(),
'module_path' => $provider::modulePath(),
'has_bootstrap' => $provider::hasBootstrap(),
]]);
}
}

View File

@ -10,42 +10,57 @@ use Illuminate\Http\Response;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class PasswordController extends Controller
{
public function forgotPassword(Request $request): Response|JsonResponse
{
$request->validate([
'email' => 'required|email|exists:users,email',
]);
$response = Password::broker()->sendResetLink($request->input('email'));
return $response === Password::RESET_LINK_SENT
? response()->noContent()
: \response()->json(['errors' => ['email' => [__($response)]]], Response::HTTP_BAD_REQUEST);
}
public function resetPassword(Request $request): JsonResponse|Response
{
$request->validate([
'token' => 'required|string',
'email' => 'required|email|exists:users,email',
'password' => ['required|string|confirmed', \Illuminate\Validation\Rules\Password::defaults()],
]);
$response = Password::broker()->reset(
$request->only(['email', 'password', 'password_confirmation', 'token']),
static function (User $user, string $password): void {
$user->password = Hash::make($password);
$user->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
}
);
return $response === Password::PASSWORD_RESET
? response()->noContent()
: response()->json(['errors' => ['email' => [__($response)]]], Response::HTTP_BAD_REQUEST);
}
// public function forgotPassword(Request $request): Response|JsonResponse
// {
// try {
// $request->validate([
// 'email' => 'required|email|exists:users,email',
// ]);
// } catch (ValidationException $e) {
// return response()->json([
// 'message' => $e->getMessage(),
// 'errors' => $e->errors(),
// ], Response::HTTP_UNPROCESSABLE_ENTITY);
// }
//
// $response = Password::broker()->sendResetLink($request->input('email'));
//
// return $response === Password::RESET_LINK_SENT
// ? response()->noContent()
// : \response()->json(['message' => __($response)], Response::HTTP_UNPROCESSABLE_ENTITY);
// }
//
// public function resetPassword(Request $request): JsonResponse|Response
// {
// try {
// $request->validate([
// 'token' => 'required|string',
// 'email' => 'required|email|exists:users,email',
// 'password' => ['required|string|confirmed', \Illuminate\Validation\Rules\Password::defaults()],
// ]);
// } catch (ValidationException $e) {
// return response()->json([
// 'message' => $e->getMessage(),
// 'errors' => $e->errors(),
// ], Response::HTTP_UNPROCESSABLE_ENTITY);
// }
//
// $response = Password::broker()->reset(
// $request->only(['email', 'password', 'password_confirmation', 'token']),
// static function (User $user, string $password): void {
// $user->password = Hash::make($password);
// $user->setRememberToken(Str::random(60));
// $user->save();
// event(new PasswordReset($user));
// }
// );
//
// return $response === Password::PASSWORD_RESET
// ? response()->noContent()
// : response()->json(['message' => __($response)], Response::HTTP_UNPROCESSABLE_ENTITY);
// }
}

View File

@ -1,147 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class SetupController extends Controller
{
/**
* Verifica la connessione al database secondo i parametri indicati nella richiesta.
* Restituisce un array di permessi mancanti in caso la connessione avvenga con successo, oppure null in caso contrario.
*/
final public function testDatabase(Request $request): Response|JsonResponse
{
$database_name = $request->input('database_name');
// Configurazione della connessione di test
config(['database.connections.testing' => [
'driver' => 'mysql',
'host' => $request->input('host'),
'port' => '3306',
'password' => $request->input('password'),
'database' => $database_name,
'username' => $request->input('username'),
]]);
try {
$connection = DB::connection('testing');
// Controlla se la connessione al DB è stata stabilita in due modi
$connection->getPdo();
if (empty($connection->getDatabaseName())) {
throw new Exception(__('Impossibile connettersi al database selezionato! Controllare il nome del database'));
}
// Individuazione permessi garantiti all'utente
$database_name = Str::replace('_', '\_', $database_name);
$grants = $connection->select($connection->raw('SHOW GRANTS FOR CURRENT_USER'));
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage(),
], Response::HTTP_BAD_REQUEST);
}
$requirements = [
'SELECT',
'INSERT',
'UPDATE',
'CREATE',
'ALTER',
'DROP',
];
foreach ($grants as $result) {
$privileges = current($result);
if (Str::contains($privileges, [" ON `$database_name`.*", ' ON *.*'])) {
$pieces = explode(', ', explode(' ON ', str_replace('GRANT ', '', (string)$privileges), 2)[0]);
// Permessi generici sul database
if (in_array('ALL', $pieces) || in_array('ALL PRIVILEGES', $pieces)) {
$requirements = [];
break;
}
// Permessi specifici sul database
foreach ($requirements as $key => $value) {
if (in_array($value, $pieces)) {
unset($requirements[$key]);
}
}
}
}
if ($requirements === []) {
return response()->noContent();
}
return response()->json([
'error' => __("L'utente del database non ha i seguenti permessi necessari: ", $requirements),
], Response::HTTP_BAD_REQUEST);
}
/**
* Metodo indirizzato al salvataggio della configurazione.
*/
public function save(Request $request)
{
$text = '<?php return '.var_export(config('database'), true).';';
$result = File::put(config_path('database.php'), $text);
// Errore in caso di fallimento
if ($result === false) {
$chmodded = File::chmod(config_path('database.php'), 0644);
$result = File::put(config_path('database.php'), $text);
if ($result === false) {
return response()->json([
'error' => 'writing',
'error_description' => __('Impossibile scrivere il file di configurazione. :action', ['action' => $chmodded ? '' : 'Controllare i permessi del file config/databasee.php']),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
// Refresh della cache sulla configurazione
Artisan::call('cache:clear');
Artisan::call('config:cache');
// Avvia migrations
Artisan::call('migrate', ['--force' => true]);
setting($request->only(['timestamp_format', 'date_format', 'time_format', 'locale']));
return response()->noContent();
}
public function saveAdmin(Request $request): Response|JsonResponse
{
try {
$request->validate([
'username' => 'required|string|min:3|max:255|unique:users,username',
'password' => 'required|string|min:6|max:255',
'email' => 'required|string|email|max:255|unique:users,email',
]);
} catch (ValidationException $e) {
return response()->json(['errors' => $e->errors()], 422);
}
$user = new User();
$user->username = $request->input('username');
$user->email = $request->input('email');
$user->password = Hash::make($request->input('password'));
$user->save();
return response()->noContent();
}
}

View File

@ -3,14 +3,15 @@
namespace App\Http;
use App\Http\Middleware\Authenticate;
use App\Http\Middleware\CheckConfigurationMiddleware;
use App\Http\Middleware\EncryptCookies;
use App\Http\Middleware\HandleInertiaRequests;
use App\Http\Middleware\LocaleMiddleware;
use App\Http\Middleware\PreventRequestsDuringMaintenance;
use App\Http\Middleware\RedirectIfAuthenticated;
use App\Http\Middleware\TrimStrings;
use App\Http\Middleware\TrustProxies;
use App\Http\Middleware\VerifyCsrfToken;
use Illuminate\Http\Middleware\HandleCors;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
@ -19,12 +20,14 @@ use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
use Illuminate\Http\Middleware\HandleCors;
use Illuminate\Http\Middleware\SetCacheHeaders;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Routing\Middleware\ValidateSignature;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
class Kernel extends HttpKernel
{
@ -59,10 +62,13 @@ class Kernel extends HttpKernel
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
LocaleMiddleware::class,
CheckConfigurationMiddleware::class,
HandleInertiaRequests::class,
],
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:api',
SubstituteBindings::class,
],

View File

@ -3,18 +3,15 @@
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*/
protected function redirectTo($request): string|null
protected function redirectTo(Request $request): ?string
{
if (!$request->expectsJson()) {
return route('auth.login');
}
return null;
return $request->expectsJson() ? null : route('login');
}
}

View File

@ -4,34 +4,43 @@ namespace App\Http\Middleware;
use App\Models\User;
use Closure;
use Illuminate\Database\QueryException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;
use PDOException;
class CheckConfigurationMiddleware
{
public function handle(Request $request, Closure $next): Response|RedirectResponse|JsonResponse
{
$checks = [
empty(DB::connection()->getDatabaseName()) => [
'redirect' => 'setup.index',
'patterns' => [
'setup.index',
'setup.test',
'setup.save',
],
],
empty(User::exists()) => [
'redirect' => 'setup.admin',
'patterns' => 'setup.admin*',
],
'database' => fn () => !empty(DB::connection()->getDatabaseName()) && DB::connection()->getPdo(),
'admin_user' => fn () => !empty(User::exists()),
];
foreach ($checks as $check => $route) {
if ($check) {
return $request->routeIs($route['patterns']) ? $next($request) : redirect()->route($route['redirect']);
foreach ($checks as $check) {
try {
$check = $check();
} catch (QueryException|InvalidArgumentException|PDOException $exception) {
$check = false;
logger()->error(
__('Configurazione del database mancante: ').$exception->getMessage(),
$exception->getTrace()
);
}
if (!$check) {
if (str_starts_with($request->route()?->getName(), 'setup.')) {
return $next($request);
}
return $request->wantsJson()
? \response()->json(['message' => __('Configurazione del database richiesta')], Response::HTTP_SERVICE_UNAVAILABLE)
: redirect()->route('setup.index');
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class LocaleMiddleware
{
public function handle(Request $request, Closure $next): mixed
{
app()->setLocale(session()->get('locale', app()->getLocale()));
return $next($request);
}
}

View File

@ -6,15 +6,17 @@ use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, array $guards = []): mixed
public function handle(Request $request, Closure $next, string ...$guards): Response
{
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {

View File

@ -9,7 +9,7 @@ class TrimStrings extends Middleware
/**
* The names of the attributes that should not be trimmed.
*
* @var array
* @var array<int, string>
*/
protected $except = [
'current_password',

View File

@ -8,6 +8,8 @@ class TrustHosts extends Middleware
{
/**
* Get the host patterns that should be trusted.
*
* @return array<int, string|null>
*/
public function hosts(): array
{

View File

@ -1,46 +0,0 @@
<?php
namespace App\JsonApi\V1;
use App\Http\Controllers\Controller;
use App\JsonApi\V1\Users\UserSchema;
use LaravelJsonApi\Core\Server\Server as BaseServer;
class Server extends BaseServer
{
/**
* The base URI namespace for this server.
*/
protected string $baseUri = '/api/v1';
/**
* Bootstrap the server when it is handling an HTTP request.
*/
public function serving(): void
{
// no-op
}
/**
* Get the server's list of schemas.
*/
protected function allSchemas(): array
{
return app(Controller::class)
->getModules()
->pluck('config.api.schemas')
->reject(null)
->push(UserSchema::class)
->flatten()
->all();
}
/**
* @inheritdoc
* TODO: Temporary: it must be added authentication to API routes
*/
public function authorizable(): bool
{
return false;
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace App\JsonApi\V1\Users;
use LaravelJsonApi\Laravel\Http\Requests\ResourceRequest;
class UserRequest extends ResourceRequest
{
/**
* Get the validation rules for the resource.
*
* @return array{username: string[], email: string[]}
*/
public function rules(): array
{
return [
'username' => ['required', 'string', 'unique:users,username'],
'email' => ['required', 'string', 'email', 'unique:users,email'],
];
}
}

View File

@ -1,54 +0,0 @@
<?php
namespace App\JsonApi\V1\Users;
use App\Models\User;
use LaravelJsonApi\Eloquent\Contracts\Paginator;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Str;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
use LaravelJsonApi\Eloquent\Pagination\PagePagination;
use LaravelJsonApi\Eloquent\Schema;
class UserSchema extends Schema
{
/**
* The model the schema corresponds to.
*/
public static string $model = User::class;
/**
* Get the resource fields.
*/
public function fields(): array
{
return [
ID::make(),
Str::make('username'),
Str::make('email'),
DateTime::make('createdAt')->sortable()->readOnly(),
DateTime::make('updatedAt')->sortable()->readOnly(),
];
}
/**
* Get the resource filters.
*/
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}
/**
* Get the resource paginator.
*/
public function pagination(): ?Paginator
{
return PagePagination::make();
}
}

View File

@ -5,11 +5,15 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Rawilk\Settings\Models\HasSettings;
class User extends Authenticatable
{
use HasSettings;
use HasFactory;
use Notifiable;
use HasApiTokens;
/**
* The attributes that are mass assignable.

View File

@ -0,0 +1,77 @@
<?php
namespace App;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Illuminate\Support\ServiceProvider;
use ReflectionClass;
abstract class ModuleServiceProvider extends ServiceProvider
{
public static string $name = '';
public static string $slug = '';
public static string $author = '';
public static string $description = '';
public static string $version = '';
public static string $url = '';
public static function name(): string
{
return static::$name;
}
public static function description(): string
{
return static::$description;
}
public static function slug(): string
{
$slug = static::$slug;
if (empty($slug)) {
$cachedPackages = require app()->getCachedServicesPath();
$slug = array_key_first(Arr::where($cachedPackages, static fn (array $package) => in_array(static::class, $package['providers'], true)));
static::$slug = $slug;
}
return $slug;
}
public static function author(): string
{
$author = static::$author;
if (empty($author)) {
$slug = static::slug();
$author = explode('/', $slug)[0] ?? '';
static::$author = $author;
}
return $author;
}
public static function version(): string
{
return static::$version;
}
public static function url(): string
{
return static::$url;
}
public static function modulePath(): string
{
return dirname((new ReflectionClass(static::class))->getFileName());
}
public static function hasBootstrap(): bool
{
return File::exists(static::modulePath().DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'ts'.DIRECTORY_SEPARATOR.'bootstrap.tsx');
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Policies;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function allowRestify(User $user = null): bool
{
return true;
}
public function show(User $user = null, User $model): bool
{
return true;
}
public function store(User $user): bool
{
return false;
}
public function storeBulk(User $user): bool
{
return false;
}
public function update(User $user, User $model): bool
{
return false;
}
public function updateBulk(User $user, User $model): bool
{
return false;
}
public function deleteBulk(User $user, User $model): bool
{
return false;
}
public function delete(User $user, User $model): bool
{
return true;
}
}

View File

@ -4,8 +4,8 @@ namespace App\Providers;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;
use Nette\Utils\Json;
class AppServiceProvider extends ServiceProvider
{
@ -18,15 +18,15 @@ class AppServiceProvider extends ServiceProvider
/**
* Bootstrap any application services.
*
* @throws Exception
*
* @noinspection StaticClosureCanBeUsedInspection Throws Cannot bind an instance to a static closure
* @noinspection AnonymousFunctionStaticInspection Throws Cannot bind an instance to a static closure
*/
public function boot(Controller $controller): void
{
cache()->rememberForever(
'translations_' . app()->getLocale(),
static fn() => Json::decode(file_get_contents(resource_path('lang/' . app()->getLocale() . '.json')))
);
view()->share('modules', $controller->getModules(request()));
view()->share('modules', $controller->getModules());
Vite::macro('image', fn ($asset) => Vite::asset("resources/images/$asset"));
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Providers;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use App\Models\User;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Fortify;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::authenticateUsing(static function (Request $request) {
$user = User::where('email', $request->username)
->orWhere('username', $request->username)
->first();
if ($user && Hash::check($request->password, $user->password)) {
return $user;
}
return false;
});
// Fortify::createUsersUsing(CreateNewUser::class);
// Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
// Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
RateLimiter::for('login', function (Request $request) {
$email = (string) $request->email;
return Limit::perMinute(5)->by($email.$request->ip());
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Providers;
use App\Http\Controllers\Controller;
use Binaryk\LaravelRestify\Restify;
use Binaryk\LaravelRestify\RestifyApplicationServiceProvider;
use Illuminate\Support\Facades\Gate;
class RestifyServiceProvider extends RestifyApplicationServiceProvider
{
/**
* Register the Restify gate.
*
* This gate determines who can access Restify in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewRestify', function ($user) {
return in_array($user->email, [
]);
});
}
protected function repositories(): void
{
parent::repositories();
// Register repositories from modules
$modules = app(Controller::class)->getModules();
foreach ($modules as $module) {
Restify::repositoriesFrom($module['module_path'].DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Api', app()->getNamespace());
}
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Restify;
use Binaryk\LaravelRestify\Filters\MatchFilter;
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
use Binaryk\LaravelRestify\Repositories\Repository as RestifyRepository;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;
abstract class Repository extends RestifyRepository
{
public static array $sort = ['id'];
/**
* Build a "show" and "index" query for the given repository.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function mainQuery(RestifyRequest $request, Builder|Relation $query)
{
return $query;
}
/**
* Build an "index" query for the given repository.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function indexQuery(RestifyRequest $request, Builder|Relation $query)
{
return $query;
}
/**
* Build a "show" query for the given repository.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function showQuery(RestifyRequest $request, Builder|Relation $query)
{
return $query;
}
public static function matches(): array
{
return array_map(static fn (string $type) => MatchFilter::make()->setType($type)->partial(), static::$match);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Restify;
use App\Models\User;
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
class UserRepository extends Repository
{
public static string $model = User::class;
public static array $sort = ['id', 'username', 'email', 'created_at', 'updated_at'];
public static array $match = [
'id' => 'int',
'username' => 'string',
];
public function fields(RestifyRequest $request): array
{
return [
field('username')->rules('required'),
field('email')->storingRules('required', 'unique:users')->updatingRules('unique:users'),
field('created_at')->label('createdAt')->readOnly(),
field('updated_at')->label('updatedAt')->readOnly(),
];
}
}

View File

@ -31,39 +31,51 @@
"require": {
"php": ">=8.1",
"ext-pdo": "*",
"akaunting/laravel-setting": "^1.2",
"guzzlehttp/guzzle": "^7.4",
"inertiajs/inertia-laravel": "^0.5",
"innocenzi/laravel-vite": "^0.2",
"laravel-json-api/laravel": "^2.1",
"laravel/framework": "^9.0",
"laravel/tinker": "^2.7",
"nette/utils": "^3.2",
"spatie/file-system-watcher": "^1.1",
"tightenco/ziggy": "^1.4",
"wikimedia/composer-merge-plugin": "^2.0"
"binaryk/laravel-restify": "^8",
"guzzlehttp/guzzle": "^7",
"inertiajs/inertia-laravel": "^0",
"jackiedo/dotenv-editor": "^2",
"laravel/fortify": "*",
"laravel/framework": "^10",
"laravel/sanctum": "^3",
"laravel/tinker": "^2",
"nette/utils": "^4",
"opcodesio/log-viewer": "^2",
"outhebox/blade-flags": "^1",
"rawilk/laravel-settings": "^2",
"spatie/file-system-watcher": "^1",
"tightenco/ziggy": "^1",
"wikimedia/composer-merge-plugin": "^2"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.6",
"barryvdh/laravel-ide-helper": "^2.12",
"friendsofphp/php-cs-fixer": "^3.6",
"kkomelin/laravel-translatable-string-exporter": "^1.16",
"nunomaduro/collision": "^6.1",
"rector/rector": "^0.14.5",
"barryvdh/laravel-debugbar": "^3",
"doctrine/dbal": "^3.6",
"driftingly/rector-laravel": "^0",
"fakerphp/faker": "^1",
"friendsofphp/php-cs-fixer": "^3",
"fumeapp/modeltyper": "^2.1",
"glhd/laravel-dumper": "^1",
"laravel-lang/attributes": "^2",
"laravel-lang/lang": "^12",
"laravel-lang/publisher": "^14",
"laravel/pint": "^1",
"nunomaduro/collision": "^7",
"nunomaduro/larastan": "^2",
"rector/rector": "^0",
"roave/security-advisories": "dev-latest",
"spatie/laravel-ignition": "^1.0"
"spatie/laravel-ignition": "^2",
"thiagocordeiro/laravel-translator": "^1"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
"App\\": "app/"
}
},
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
"@php artisan package:discover --ansi",
"@php artisan vendor:publish --tag=blade-flags --tag=log-viewer-assets --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
@ -83,7 +95,6 @@
"extra": {
"merge-plugin": {
"include": [
"./composer.local.json"
],
"replace": true
}

View File

@ -173,7 +173,9 @@ return [
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RestifyServiceProvider::class,
App\Providers\RouteServiceProvider::class,
\App\Providers\FortifyServiceProvider::class,
],
@ -229,6 +231,7 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Vite' => Illuminate\Support\Facades\Vite::class,
],

147
config/fortify.php Normal file
View File

@ -0,0 +1,147 @@
<?php
use App\Providers\RouteServiceProvider;
use Laravel\Fortify\Features;
return [
/*
|--------------------------------------------------------------------------
| Fortify Guard
|--------------------------------------------------------------------------
|
| Here you may specify which authentication guard Fortify will use while
| authenticating users. This value should correspond with one of your
| guards that is already present in your "auth" configuration file.
|
*/
'guard' => 'web',
/*
|--------------------------------------------------------------------------
| Fortify Password Broker
|--------------------------------------------------------------------------
|
| Here you may specify which password broker Fortify can use when a user
| is resetting their password. This configured value should match one
| of your password brokers setup in your "auth" configuration file.
|
*/
'passwords' => 'users',
/*
|--------------------------------------------------------------------------
| Username / Email
|--------------------------------------------------------------------------
|
| This value defines which model attribute should be considered as your
| application's "username" field. Typically, this might be the email
| address of the users but you are free to change this value here.
|
| Out of the box, Fortify expects forgot password and reset password
| requests to have a field named 'email'. If the application uses
| another name for the field you may define it below as needed.
|
*/
'username' => 'username',
'email' => 'email',
/*
|--------------------------------------------------------------------------
| Home Path
|--------------------------------------------------------------------------
|
| Here you may configure the path where users will get redirected during
| authentication or password reset when the operations are successful
| and the user is authenticated. You are free to change this value.
|
*/
'home' => RouteServiceProvider::HOME,
/*
|--------------------------------------------------------------------------
| Fortify Routes Prefix / Subdomain
|--------------------------------------------------------------------------
|
| Here you may specify which prefix Fortify will assign to all the routes
| that it registers with the application. If necessary, you may change
| subdomain under which all of the Fortify routes will be available.
|
*/
'prefix' => '',
'domain' => null,
/*
|--------------------------------------------------------------------------
| Fortify Routes Middleware
|--------------------------------------------------------------------------
|
| Here you may specify which middleware Fortify will assign to the routes
| that it registers with the application. If necessary, you may change
| these middleware but typically this provided default is preferred.
|
*/
'middleware' => ['web'],
/*
|--------------------------------------------------------------------------
| Rate Limiting
|--------------------------------------------------------------------------
|
| By default, Fortify will throttle logins to five requests per minute for
| every email and IP address combination. However, if you would like to
| specify a custom rate limiter to call then you may specify it here.
|
*/
'limiters' => [
'login' => 'login',
'two-factor' => 'two-factor',
],
/*
|--------------------------------------------------------------------------
| Register View Routes
|--------------------------------------------------------------------------
|
| Here you may specify if the routes returning views should be disabled as
| you may not need them when building your own application. This may be
| especially true if you're writing a custom single-page application.
|
*/
'views' => false,
/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of the Fortify features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/
'features' => [
Features::registration(),
Features::resetPasswords(),
// Features::emailVerification(),
// Features::updateProfileInformation(),
// Features::updatePasswords(),
// Features::twoFactorAuthentication([
// 'confirm' => true,
// 'confirmPassword' => true,
// // 'window' => 0,
// ]),
],
];

View File

@ -4,7 +4,7 @@ return [
// Directories to search in.
'directories' => [
'app',
'resources/js',
'resources/ts',
'resources/views',
],
@ -22,7 +22,8 @@ return [
// If your function name contains $ escape it using \$ .
'functions' => [
'__',
'_t',
'_s',
'_v',
'@lang',
],

168
config/restify.php Normal file
View File

@ -0,0 +1,168 @@
<?php
use Binaryk\LaravelRestify\Http\Middleware\AuthorizeRestify;
use Binaryk\LaravelRestify\Http\Middleware\DispatchRestifyStartingEvent;
use Binaryk\LaravelRestify\Repositories\ActionLogRepository;
return [
'auth' => [
/*
|--------------------------------------------------------------------------
| Table containing authenticatable resource
|--------------------------------------------------------------------------
|
| This configuration contain the name of the table used for the authentication.
|
*/
'table' => 'users',
/*
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
| Next you may configure the package you're using for the personal tokens generation,
| this will be used for the verification of the authenticatable model and provide the
| authorizable functionality
|
| Supported: "sanctum"
*/
'provider' => 'sanctum',
/*
|--------------------------------------------------------------------------
| Auth frontend app url
|--------------------------------------------------------------------------
|
|URL used for reset password URL generating.
|
|
*/
'frontend_app_url' => env('FRONTEND_APP_URL', env('APP_URL')),
'password_reset_url' => env('FRONTEND_APP_URL').'/password/reset?token={token}&email={email}',
'user_verify_url' => env('FRONTEND_APP_URL').'/verify/{id}/{emailHash}',
'user_model' => "\App\Models\User",
],
/*
|--------------------------------------------------------------------------
| RestifyJS
|--------------------------------------------------------------------------
|
| This configuration is used for supporting the RestifyJS
|
*/
'restifyjs' => [
/*
| Token to authorize the setup endpoint.
*/
'token' => env('RESTIFYJS_TOKEN', 'testing'),
/*
| The API base url.
*/
'api_url' => env('API_URL', env('APP_URL')),
],
/*
|--------------------------------------------------------------------------
| Restify Base Route
|--------------------------------------------------------------------------
|
| This configuration is used as a prefix path where Restify will be accessible from.
| Feel free to change this path to anything you like.
|
*/
'base' => '/api/restify',
/*
|--------------------------------------------------------------------------
| Restify Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Restify route, giving you the
| chance to add your own middleware to this stack or override any of
| the existing middleware. Or, you can just stick with this stack.
|
*/
'middleware' => [
'api',
'auth:sanctum',
DispatchRestifyStartingEvent::class,
AuthorizeRestify::class,
],
/*
|--------------------------------------------------------------------------
| Restify Logs
|--------------------------------------------------------------------------
*/
'logs' => [
/*
| Repository used to list logs.
*/
'repository' => ActionLogRepository::class,
/**
| Inform restify to log or not action logs.
*/
'enable' => env('RESTIFY_ENABLE_LOGS', true),
/**
| Inform restify to log model changes from any source, or just restify. Set to `false` to log just restify logs.
*/
'all' => env('RESTIFY_WRITE_ALL_LOGS', false),
],
/*
|--------------------------------------------------------------------------
| Restify Search
|--------------------------------------------------------------------------
*/
'search' => [
/*
| Specify either the search should be case-sensitive or not.
*/
'case_sensitive' => true,
],
'repositories' => [
/*
| Specify either to serialize index meta (policy) information or not. For performance reasons we recommend disabling it.
*/
'serialize_index_meta' => false,
/*
| Specify either to serialize show meta (policy) information or not.
*/
'serialize_show_meta' => true,
],
'cache' => [
/*
| Specify the cache configuration for the resources policies.
| When enabled, methods from the policy will be cached for the active user.
*/
'policies' => [
'enabled' => false,
'ttl' => 5 * 60, // seconds
],
],
/*
| Specify if restify can call OpenAI for solution generation.
|
| By default this feature is enabled, but you still have to extend the Exception handler with the Restify one and set the API key.
*/
'ai_solutions' => true,
];

67
config/sanctum.php Normal file
View File

@ -0,0 +1,67 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:8000,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];

20
config/translator.php Normal file
View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
use Translator\Framework\LaravelConfigLoader;
use Translator\Infra\LaravelJsonTranslationRepository;
return [
'languages' => ['pt-br', 'es'],
'directories' => [
app_path(),
resource_path('views'),
],
'output' => resource_path('lang'),
'extensions' => ['php'],
'container' => [
'config_loader' => LaravelConfigLoader::class,
'translation_repository' => LaravelJsonTranslationRepository::class,
],
];

View File

@ -1,115 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Configurations
|--------------------------------------------------------------------------
| The following describes a set of configurations that can be used
| independently. Because Vite does not support generating multiple
| bundles, using separate configuration files is necessary.
| https://laravel-vite.dev/configuration/laravel-package.html#configs
*/
'configs' => [
'default' => [
'entrypoints' => [
'paths' => [
'resources/js/index.ts',
'resources/js/app.ts',
'resources/js/styles.ts',
'resources/js/_material.ts',
],
'ignore' => '/\\.(d\\.ts|json)$/',
],
'dev_server' => [
'enabled' => true,
'url' => env('DEV_SERVER_URL', 'http://localhost:3000'),
'ping_before_using_manifest' => true,
'ping_url' => null,
'ping_timeout' => 1,
'key' => env('DEV_SERVER_KEY'),
'cert' => env('DEV_SERVER_CERT'),
],
'build_path' => 'build',
],
],
/*
|--------------------------------------------------------------------------
| Aliases
|--------------------------------------------------------------------------
| You can define aliases to avoid having to make relative imports.
| Aliases will be written to tsconfig.json automatically so your IDE
| can know how to resolve them.
| https://laravel-vite.dev/configuration/laravel-package.html#aliases
*/
'aliases' => [
'@osm' => 'resources/js',
'@osm-images' => 'public/images',
'@osm-scss' => 'resources/scss',
],
/*
|--------------------------------------------------------------------------
| Commands
|--------------------------------------------------------------------------
| Before starting the development server or building the assets, you
| may need to run specific commands. With these options, you can
| define what to run, automatically.
| https://laravel-vite.dev/configuration/laravel-package.html#commands
*/
'commands' => [
'artisan' => [
'vite:tsconfig',
// 'typescript:generate'
],
'shell' => [],
],
/*
|--------------------------------------------------------------------------
| Testing
|--------------------------------------------------------------------------
| Depending on the way you are testing your application,
| you may or may not need to use the manifest. This option controls
| the manifest should be used in the "testing" environment.
| https://laravel-vite.dev/configuration/laravel-package.html#testing
*/
'testing' => [
'use_manifest' => false,
],
/*
|--------------------------------------------------------------------------
| Environment variable prefixes
|--------------------------------------------------------------------------
| This option defines the prefixes that environment variables must
| have in order to be accessible from the front-end.
| https://laravel-vite.dev/configuration/laravel-package.html#env_prefixes
*/
'env_prefixes' => ['VITE_', 'MIX_', 'SCRIPT_'],
/*
|--------------------------------------------------------------------------
| Default interfaces
|--------------------------------------------------------------------------
| Here you may change how some parts of the package work by replacing
| their associated logic.
| https://laravel-vite.dev/configuration/laravel-package.html#interfaces
*/
'interfaces' => [
'heartbeat_checker' => Innocenzi\Vite\HeartbeatCheckers\HttpHeartbeatChecker::class,
'tag_generator' => Innocenzi\Vite\TagGenerators\CallbackTagGenerator::class,
'entrypoints_finder' => Innocenzi\Vite\EntrypointsFinder\DefaultEntrypointsFinder::class,
],
/*
|--------------------------------------------------------------------------
| Default configuration
|--------------------------------------------------------------------------
| Here you may specify which of the configurations above you wish
| to use as your default one.
| https://laravel-vite.dev/configuration/laravel-package.html#default
*/
'default' => env('VITE_DEFAULT_CONFIG', 'default'),
];

View File

@ -1,47 +0,0 @@
<?php /** @noinspection PhpUnused */
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use JetBrains\PhpStorm\ArrayShape;
use Illuminate\Support\Carbon;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @noinspection PhpUndefinedMethodInspection
* @return array{name: mixed, email: mixed, email_verified_at: \Illuminate\Support\Carbon, password: string, remember_token: string}
*/
#[ArrayShape(['name' => 'string', 'email' => 'mixed', 'email_verified_at' => Carbon::class, 'password' => 'string', 'remember_token' => 'string'])]
public function definition(): array
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): Factory
{
return $this->state(static fn() => [
'email_verified_at' => null,
]);
}
}

View File

@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Laravel\Fortify\Fortify;
return new class() extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->text('two_factor_secret')
->after('password')
->nullable();
$table->text('two_factor_recovery_codes')
->after('two_factor_secret')
->nullable();
if (Fortify::confirmsTwoFactorAuthentication()) {
$table->timestamp('two_factor_confirmed_at')
->after('two_factor_recovery_codes')
->nullable();
}
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(array_merge([
'two_factor_secret',
'two_factor_recovery_codes',
], Fortify::confirmsTwoFactorAuthentication() ? [
'two_factor_confirmed_at',
] : []));
});
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class() extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};

View File

@ -0,0 +1,49 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class() extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('action_logs', function (Blueprint $table) {
$table->id();
$table->char('batch_id', 36);
$table->unsignedBigInteger('user_id')->index()->nullable();
$table->string('name');
$table->string('actionable_type');
$table->unsignedBigInteger('actionable_id');
$table->string('target_type')->nullable();
$table->unsignedBigInteger('target_id')->nullable();
$table->string('model_type')->nullable();
$table->unsignedBigInteger('model_id')->nullable();
$table->text('fields')->nullable();
$table->string('status', 25)->default('running');
$table->text('original')->nullable();
$table->text('changes')->nullable();
$table->text('exception')->nullable();
$table->json('meta')->nullable();
$table->timestamps();
$table->index(['actionable_type', 'actionable_id']);
$table->index(['batch_id', 'model_type', 'model_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('action_logs');
}
};

View File

@ -1,16 +0,0 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// \App\Models\User::factory(10)->create();
}
}

112
lang/en.json Normal file
View File

@ -0,0 +1,112 @@
{
"(and :count more error)": "(and :count more error)",
"(and :count more errors)": "(and :count more errors)",
"* Campi obbligatori": "* Mandatory Fields",
"Accedi": "Login",
"Account creato con successo. Puoi ora accedere.": "Account created successfully. You can now login.",
"Aggiornamento del frontend disponibile!": "An update of the frontend available!",
"Aggiungi": "Add",
"Aggiungi nuovo record": "Add new record",
"All rights reserved.": "All rights reserved.",
"Annulla": "Cancel",
"assistenza ufficiale": "official assistance",
"Bandiera della lingua :language": "Bandiera della lingua :language",
"Benvenuto in :name!": "Welcome to :name!",
"Cambia periodo": "Change period",
"Campi non validi. Controlla i dati inseriti": "Invalid fields. Check the entered data",
"Conferma": "Confirm",
"Conferma password": "Confirm Password",
"Connessione al database riuscita": "Successfully connected to the database",
"Crea account": "Create account",
"Creazione account amministratore": "Administrator account creation",
"Dashboard": "Dashboard",
"Database": "Database",
"Elimina": "Delete",
"Email": "Email",
"Errore durante il salvataggio: :error": "Error during the save: :error",
"Errore durante l'eliminazione: :error": "Errore durante l'eliminazione: :error",
"Esci": "Exit",
"Esempio: :example": "Example : :example",
"Forbidden": "Forbidden",
"Formato data corta": "Short date format",
"Formato data lunga": "Long date format",
"Formato date": "Date format",
"Formato orario": "Time format",
"forum": "forum",
"Go to page :page": "Go to page :page",
"Hello!": "Hello!",
"Ho visionato e accetto la licenza": "I have visioned and I accept the license",
"Host": "Host",
"I formati sono impostabili attraverso lo standard previsto da :link.": "I formati sono impostabili attraverso lo standard previsto da :link.",
"If you did not create an account, no further action is required.": "If you did not create an account, no further action is required.",
"If you did not request a password reset, no further action is required.": "If you did not request a password reset, no further action is required.",
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:",
"Il tuo profilo": "Your profile",
"Impossibile connettersi al database selezionato! Controllare il nome del database": "Unable to connect to the selected database! Check the name of the database",
"Impossibile scrivere il file di configurazione. :action": "Unable to write the config file. :action",
"Impostazioni salvate correttamente": "Saved settings correctly",
"Inserisci le informazioni richieste per creare un nuovo account amministratore.": "Inserisci le informazioni richieste per creare un nuovo account amministratore.",
"L'utente del database non ha i seguenti permessi necessari: ": "The database user does not have the following necessary permits: ",
"La password è stata inviata alla tua email": "Your password has been sent to your email",
"Le credenziali non sono valide.": "The credentials are not valid.",
"Le password non corrispondono": "Passwords do not match",
"Licenza": "License",
"Lingua": "Language",
"Login": "Login",
"Logout": "Logout",
"No": "No",
"Nome database": "Database name",
"Nome utente": "Username",
"Nome utente/email": "Username/email",
"Non sono presenti dati": "There are no data",
"Not Found": "Not Found",
"Notifiche": "Notifications",
"of": "of",
"OpenSTAManager": "OpenSTAManager",
"OpenSTAManager è tutelato dalla licenza GPL 3.0, da accettare obbligatoriamente per poter utilizzare il gestionale.": "OpenSTAManager è tutelato dalla licenza GPL 3.0, da accettare obbligatoriamente per poter utilizzare il gestionale.",
"Page Expired": "Page Expired",
"Pagination Navigation": "Pagination Navigation",
"Password": "Password",
"Payment Required": "Payment Required",
"Please click the button below to verify your email address.": "Please click the button below to verify your email address.",
"Record eliminato!": "Record deleted!",
"Record salvato": "Record saved",
"Regards": "Regards",
"Register": "Register",
"Reimposta password": "Reset password",
"Reset della password effettuato con successo. Puoi ora accedere.": "Reset of the password done successfully. You can now access.",
"Reset Password": "Reset Password",
"Reset Password Notification": "Reset Password Notification",
"Resetta password": "Reset Password",
"results": "results",
"Ricarica": "Reload",
"Ricordami": "Remind me",
"Salva e installa": "Save and install",
"Se necessiti supporto puoi contattarci tramite l':contactLink o tramite il nostro :forumLink.": "Se necessiti supporto puoi contattarci tramite l':contactLink o tramite il nostro :forumLink.",
"Sei sicuro di voler eliminare questo record?": "Are you sure you want to eliminate this record?",
"Seleziona una voce dal menu a sinistra": "Select an entry from the menu on the left",
"Server Error": "Server Error",
"Service Unavailable": "Service Unavailable",
"Showing": "Showing",
"Si è verificato un errore durante la connessione al database: :error": "An error occurred during the connection to the database: :error",
"Stampa": "Print",
"Sì": "Yes",
"Testa il database": "Try the database",
"The :attribute must contain at least one letter.": "The :attribute must contain at least one letter.",
"The :attribute must contain at least one number.": "The :attribute must contain at least one number.",
"The :attribute must contain at least one symbol.": "The :attribute must contain at least one symbol.",
"The :attribute must contain at least one uppercase and one lowercase letter.": "The :attribute must contain at least one uppercase and one lowercase letter.",
"The given :attribute has appeared in a data leak. Please choose a different :attribute.": "The given :attribute has appeared in a data leak. Please choose a different :attribute.",
"The given data was invalid.": "The given data was invalid.",
"This password reset link will expire in :count minutes.": "This password reset link will expire in :count minutes.",
"to": "to",
"Toggle navigation": "Toggle navigation",
"Too Many Requests": "Too Many Requests",
"Unauthorized": "Unauthorized",
"Verify Email Address": "Verify Email Address",
"Versione": "Version",
"Versioni tradotte": "Translated versions",
"Whoops!": "Whoops!",
"You are receiving this email because we received a password reset request for your account.": "You are receiving this email because we received a password reset request for your account.",
"È ora possibile lavorare offline!": "It is now possible to work offline!"
}

9
lang/en/auth.php Normal file
View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
return [
'failed' => 'These credentials do not match our records.',
'password' => 'The password is incorrect.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];

8
lang/en/pagination.php Normal file
View File

@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
return [
'next' => 'Next &raquo;',
'previous' => '&laquo; Previous',
];

11
lang/en/passwords.php Normal file
View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
return [
'reset' => 'Your password has been reset!',
'sent' => 'We have emailed your password reset link!',
'throttled' => 'Please wait before retrying.',
'token' => 'This password reset token is invalid.',
'user' => 'We can\'t find a user with that email address.',
];

View File

@ -1,33 +1,25 @@
<?php
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute must be accepted.',
'accepted_if' => 'The :attribute must be accepted when :other is :value.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute must only contain letters.',
'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute must only contain letters and numbers.',
'alpha' => 'The :attribute may only contain letters.',
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
'alpha_num' => 'The :attribute may only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'ascii' => 'The :attribute must only contain single-byte alphanumeric characters and symbols.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'numeric' => 'The :attribute must be between :min and :max.',
'string' => 'The :attribute must be between :min and :max characters.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
@ -35,27 +27,33 @@ return [
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'decimal' => 'The :attribute must have :decimal decimal places.',
'declined' => 'The :attribute must be declined.',
'declined_if' => 'The :attribute must be declined when :other is :value.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',
'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'filled' => 'The :attribute field is required.',
'gt' => [
'numeric' => 'The :attribute must be greater than :value.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'string' => 'The :attribute must be greater than :value characters.',
'array' => 'The :attribute must have more than :value items.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'numeric' => 'The :attribute must be greater than :value.',
'string' => 'The :attribute must be greater than :value characters.',
],
'gte' => [
'numeric' => 'The :attribute must be greater than or equal :value.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'string' => 'The :attribute must be greater than or equal :value characters.',
'array' => 'The :attribute must have :value items or more.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'numeric' => 'The :attribute must be greater than or equal :value.',
'string' => 'The :attribute must be greater than or equal :value characters.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
@ -65,92 +63,154 @@ return [
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lowercase' => 'The :attribute must be lowercase.',
'lt' => [
'numeric' => 'The :attribute must be less than :value.',
'file' => 'The :attribute must be less than :value kilobytes.',
'string' => 'The :attribute must be less than :value characters.',
'array' => 'The :attribute must have less than :value items.',
'file' => 'The :attribute must be less than :value kilobytes.',
'numeric' => 'The :attribute must be less than :value.',
'string' => 'The :attribute must be less than :value characters.',
],
'lte' => [
'numeric' => 'The :attribute must be less than or equal :value.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'string' => 'The :attribute must be less than or equal :value characters.',
'array' => 'The :attribute must not have more than :value items.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'numeric' => 'The :attribute must be less than or equal :value.',
'string' => 'The :attribute must be less than or equal :value characters.',
],
'mac_address' => 'The :attribute must be a valid MAC address.',
'max' => [
'numeric' => 'The :attribute must not be greater than :max.',
'file' => 'The :attribute must not be greater than :max kilobytes.',
'string' => 'The :attribute must not be greater than :max characters.',
'array' => 'The :attribute must not have more than :max items.',
'array' => 'The :attribute may not have more than :max items.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'numeric' => 'The :attribute may not be greater than :max.',
'string' => 'The :attribute may not be greater than :max characters.',
],
'max_digits' => 'The :attribute must not have more than :max digits.',
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
'file' => 'The :attribute must be at least :min kilobytes.',
'numeric' => 'The :attribute must be at least :min.',
'string' => 'The :attribute must be at least :min characters.',
],
'min_digits' => 'The :attribute must have at least :min digits.',
'missing' => 'The :attribute field must be missing.',
'missing_if' => 'The :attribute field must be missing when :other is :value.',
'missing_unless' => 'The :attribute field must be missing unless :other is :value.',
'missing_with' => 'The :attribute field must be missing when :values is present.',
'missing_with_all' => 'The :attribute field must be missing when :values are present.',
'multiple_of' => 'The :attribute must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => 'The password is incorrect.',
'password' => [
'letters' => 'The :attribute must contain at least one letter.',
'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',
'numbers' => 'The :attribute must contain at least one number.',
'symbols' => 'The :attribute must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values is present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
'file' => 'The :attribute must be :size kilobytes.',
'numeric' => 'The :attribute must be :size.',
'string' => 'The :attribute must be :size characters.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'starts_with' => 'The :attribute must start with one of the following: :values',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid timezone.',
'timezone' => 'The :attribute must be a valid zone.',
'ulid' => 'The :attribute must be a valid ULID.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute must be a valid URL.',
'uppercase' => 'The :attribute must be uppercase.',
'url' => 'The :attribute format is invalid.',
'uuid' => 'The :attribute must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
'attributes' => [
'address' => 'address',
'age' => 'age',
'amount' => 'amount',
'area' => 'area',
'available' => 'available',
'birthday' => 'birthday',
'body' => 'body',
'city' => 'city',
'content' => 'content',
'country' => 'country',
'created_at' => 'created at',
'creator' => 'creator',
'current_password' => 'current password',
'date' => 'date',
'date_of_birth' => 'date of birth',
'day' => 'day',
'deleted_at' => 'deleted at',
'description' => 'description',
'district' => 'district',
'duration' => 'duration',
'email' => 'email',
'excerpt' => 'excerpt',
'filter' => 'filter',
'first_name' => 'first name',
'gender' => 'gender',
'group' => 'group',
'hour' => 'hour',
'image' => 'image',
'last_name' => 'last name',
'lesson' => 'lesson',
'line_address_1' => 'line address 1',
'line_address_2' => 'line address 2',
'message' => 'message',
'middle_name' => 'middle name',
'minute' => 'minute',
'mobile' => 'mobile',
'month' => 'month',
'name' => 'name',
'national_code' => 'national code',
'number' => 'number',
'password' => 'password',
'password_confirmation' => 'password confirmation',
'phone' => 'phone',
'photo' => 'photo',
'postal_code' => 'postal code',
'price' => 'price',
'province' => 'province',
'recaptcha_response_field' => 'recaptcha response field',
'remember' => 'remember',
'restored_at' => 'restored at',
'result_text_under_image' => 'result text under image',
'role' => 'role',
'second' => 'second',
'sex' => 'sex',
'short_text' => 'short text',
'size' => 'size',
'state' => 'state',
'street' => 'street',
'student' => 'student',
'subject' => 'subject',
'teacher' => 'teacher',
'terms' => 'terms',
'test_description' => 'test description',
'test_locale' => 'test locale',
'test_name' => 'test name',
'text' => 'text',
'time' => 'time',
'title' => 'title',
'updated_at' => 'updated at',
'username' => 'username',
'year' => 'year',
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];

112
lang/it.json Normal file
View File

@ -0,0 +1,112 @@
{
"(and :count more error)": "(e :count altro errore)",
"(and :count more errors)": "(e :count altri errori)",
"* Campi obbligatori": "* Campi obbligatori",
"Accedi": "Accedi",
"Account creato con successo. Puoi ora accedere.": "Account creato con successo. Puoi ora accedere.",
"Aggiornamento del frontend disponibile!": "Aggiornamento del frontend disponibile!",
"Aggiungi": "Aggiungi",
"Aggiungi nuovo record": "Aggiungi nuovo record",
"All rights reserved.": "Tutti i diritti riservati",
"Annulla": "Annulla",
"assistenza ufficiale": "assistenza ufficiale",
"Bandiera della lingua :language": "Bandiera della lingua :language",
"Benvenuto in :name!": "Benvenuto in :name!",
"Cambia periodo": "Cambia periodo",
"Campi non validi. Controlla i dati inseriti": "Campi non validi. Controlla i dati inseriti",
"Conferma": "Conferma",
"Conferma password": "Conferma password",
"Connessione al database riuscita": "Connessione al database riuscita",
"Crea account": "Crea account",
"Creazione account amministratore": "Creazione account amministratore",
"Dashboard": "Dashboard",
"Database": "Database",
"Elimina": "Elimina",
"Email": "Email",
"Errore durante il salvataggio: :error": "Errore durante il salvataggio: :error",
"Errore durante l'eliminazione: :error": "Errore durante l'eliminazione: :error",
"Esci": "Esci",
"Esempio: :example": "Esempio: :example",
"Forbidden": "Vietato",
"Formato data corta": "Formato data corta",
"Formato data lunga": "Formato data lunga",
"Formato date": "Formato date",
"Formato orario": "Formato orario",
"forum": "forum",
"Go to page :page": "Vai alla pagina :page",
"Hello!": "Ciao!",
"Ho visionato e accetto la licenza": "Ho visionato e accetto la licenza",
"Host": "Host",
"I formati sono impostabili attraverso lo standard previsto da :link.": "I formati sono impostabili attraverso lo standard previsto da :link.",
"If you did not create an account, no further action is required.": "Se non hai creato un account, non è richiesta alcuna azione.",
"If you did not request a password reset, no further action is required.": "Se non hai richiesto un reset della password, non è richiesta alcuna azione.",
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "Se non riesci a cliccare sul pulsante \":actionText\", copia e incolla l'URL seguente\nnel tuo browser:",
"Il tuo profilo": "Il tuo profilo",
"Impossibile connettersi al database selezionato! Controllare il nome del database": "Impossibile connettersi al database selezionato! Controllare il nome del database",
"Impossibile scrivere il file di configurazione. :action": "Impossibile scrivere il file di configurazione. :action",
"Impostazioni salvate correttamente": "Impostazioni salvate correttamente",
"Inserisci le informazioni richieste per creare un nuovo account amministratore.": "Inserisci le informazioni richieste per creare un nuovo account amministratore.",
"L'utente del database non ha i seguenti permessi necessari: ": "L'utente del database non ha i seguenti permessi necessari: ",
"La password è stata inviata alla tua email": "La password è stata inviata alla tua email",
"Le credenziali non sono valide.": "Le credenziali non sono valide.",
"Le password non corrispondono": "Le password non corrispondono",
"Licenza": "Licenza",
"Lingua": "Lingua",
"Login": "Accedi",
"Logout": "Esci",
"No": "No",
"Nome database": "Nome database",
"Nome utente": "Nome utente",
"Nome utente/email": "Nome utente/email",
"Non sono presenti dati": "Non sono presenti dati",
"Not Found": "Non trovato",
"Notifiche": "Notifiche",
"of": "di",
"OpenSTAManager": "OpenSTAManager",
"OpenSTAManager è tutelato dalla licenza GPL 3.0, da accettare obbligatoriamente per poter utilizzare il gestionale.": "OpenSTAManager è tutelato dalla licenza GPL 3.0, da accettare obbligatoriamente per poter utilizzare il gestionale.",
"Page Expired": "Pagina scaduta",
"Pagination Navigation": "Navigazione della Paginazione",
"Password": "Password",
"Payment Required": "Pagamento richiesto",
"Please click the button below to verify your email address.": "Clicca sul pulsante qui sotto per verificare il tuo indirizzo email.",
"Record eliminato!": "Record eliminato!",
"Record salvato": "Record salvato",
"Regards": "Distinti saluti",
"Register": "Registrati",
"Reimposta password": "Reimposta password",
"Reset della password effettuato con successo. Puoi ora accedere.": "Reset della password effettuato con successo. Puoi ora accedere.",
"Reset Password": "Resetta la password",
"Reset Password Notification": "Notifica di reset della password",
"Resetta password": "Resetta password",
"results": "risultati",
"Ricarica": "Ricarica",
"Ricordami": "Ricordami",
"Salva e installa": "Salva e installa",
"Se necessiti supporto puoi contattarci tramite l':contactLink o tramite il nostro :forumLink.": "Se necessiti supporto puoi contattarci tramite l':contactLink o tramite il nostro :forumLink.",
"Sei sicuro di voler eliminare questo record?": "Sei sicuro di voler eliminare questo record?",
"Seleziona una voce dal menu a sinistra": "Seleziona una voce dal menu a sinistra",
"Server Error": "Errore server",
"Service Unavailable": "Servizio non disponibile",
"Showing": "Mostra",
"Si è verificato un errore durante la connessione al database: :error": "Si è verificato un errore durante la connessione al database: :error",
"Stampa": "Stampa",
"Sì": "Sì",
"Testa il database": "Testa il database",
"The :attribute must contain at least one letter.": ":Attribute deve contenere almeno una lettera.",
"The :attribute must contain at least one number.": ":Attribute deve contenere almeno un numero.",
"The :attribute must contain at least one symbol.": ":Attribute deve contenere almeno un carattere speciale.",
"The :attribute must contain at least one uppercase and one lowercase letter.": ":Attribute deve contenere almeno un carattere maiuscolo ed uno minuscolo.",
"The given :attribute has appeared in a data leak. Please choose a different :attribute.": ":Attribute sembra che faccia parte di un archivio con dati rubati. Per piacere, utilizza un valore differente.",
"The given data was invalid.": "I dati forniti non sono validi.",
"This password reset link will expire in :count minutes.": "Questo link di reset della password scadrà tra :count minuti.",
"to": "a",
"Toggle navigation": "Cambia navigazione",
"Too Many Requests": "Troppe richieste",
"Unauthorized": "Non autorizzato",
"Verify Email Address": "Verifica indirizzo email",
"Versione": "Versione",
"Versioni tradotte": "Versioni tradotte",
"Whoops!": "Ops!",
"You are receiving this email because we received a password reset request for your account.": "Hai ricevuto questa email perché abbiamo ricevuto una richiesta di reset della password per il tuo account.",
"È ora possibile lavorare offline!": "È ora possibile lavorare offline!"
}

9
lang/it/auth.php Normal file
View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
return [
'failed' => 'Credenziali non valide.',
'password' => 'Il campo :attribute non è corretto.',
'throttle' => 'Troppi tentativi di accesso. Riprova tra :seconds secondi.',
];

8
lang/it/pagination.php Normal file
View File

@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
return [
'next' => 'Successivo &raquo;',
'previous' => '&laquo; Precedente',
];

11
lang/it/passwords.php Normal file
View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
return [
'reset' => 'La password è stata reimpostata!',
'sent' => 'Ti abbiamo inviato una email con il link per il reset della password!',
'throttled' => 'Per favore, attendi prima di riprovare.',
'token' => 'Questo token di reset della password non è valido.',
'user' => 'Non riusciamo a trovare un utente con questo indirizzo email.',
];

216
lang/it/validation.php Normal file
View File

@ -0,0 +1,216 @@
<?php
declare(strict_types=1);
return [
'accepted' => ':Attribute deve essere accettato.',
'accepted_if' => ':Attribute deve essere accettato quando :other è :value.',
'active_url' => ':Attribute non è un URL valido.',
'after' => ':Attribute deve essere una data successiva al :date.',
'after_or_equal' => ':Attribute deve essere una data successiva o uguale al :date.',
'alpha' => ':Attribute può contenere solo lettere.',
'alpha_dash' => ':Attribute può contenere solo lettere, numeri e trattini.',
'alpha_num' => ':Attribute può contenere solo lettere e numeri.',
'array' => ':Attribute deve essere un array.',
'ascii' => ':Attribute deve contenere solo caratteri alfanumerici single-byte e simboli.',
'before' => ':Attribute deve essere una data precedente al :date.',
'before_or_equal' => ':Attribute deve essere una data precedente o uguale al :date.',
'between' => [
'array' => ':Attribute deve avere tra :min - :max elementi.',
'file' => ':Attribute deve trovarsi tra :min - :max kilobyte.',
'numeric' => ':Attribute deve trovarsi tra :min - :max.',
'string' => ':Attribute deve trovarsi tra :min - :max caratteri.',
],
'boolean' => 'Il campo :attribute deve essere vero o falso.',
'confirmed' => 'Il campo di conferma per :attribute non coincide.',
'current_password' => 'Password non valida.',
'date' => ':Attribute non è una data valida.',
'date_equals' => ':Attribute deve essere una data e uguale a :date.',
'date_format' => ':Attribute non coincide con il formato :format.',
'decimal' => ':Attribute deve avere :decimal cifre decimali.',
'declined' => ':Attribute deve essere rifiutato.',
'declined_if' => ':Attribute deve essere rifiutato quando :other è :value.',
'different' => ':Attribute e :other devono essere differenti.',
'digits' => ':Attribute deve essere di :digits cifre.',
'digits_between' => ':Attribute deve essere tra :min e :max cifre.',
'dimensions' => 'Le dimensioni dell\'immagine di :attribute non sono valide.',
'distinct' => ':Attribute contiene un valore duplicato.',
'doesnt_end_with' => ':Attribute non può terminare con uno dei seguenti valori: :values.',
'doesnt_start_with' => ':Attribute non può iniziare con uno dei seguenti valori: :values.',
'email' => ':Attribute non è valido.',
'ends_with' => ':Attribute deve finire con uno dei seguenti valori: :values',
'enum' => 'Il campo :attribute non è valido.',
'exists' => ':Attribute selezionato non è valido.',
'file' => ':Attribute deve essere un file.',
'filled' => 'Il campo :attribute deve contenere un valore.',
'gt' => [
'array' => ':Attribute deve contenere più di :value elementi.',
'file' => ':Attribute deve essere maggiore di :value kilobyte.',
'numeric' => ':Attribute deve essere maggiore di :value.',
'string' => ':Attribute deve contenere più di :value caratteri.',
],
'gte' => [
'array' => ':Attribute deve contenere un numero di elementi uguale o maggiore di :value.',
'file' => ':Attribute deve essere uguale o maggiore di :value kilobyte.',
'numeric' => ':Attribute deve essere uguale o maggiore di :value.',
'string' => ':Attribute deve contenere un numero di caratteri uguale o maggiore di :value.',
],
'image' => ':Attribute deve essere un\'immagine.',
'in' => ':Attribute selezionato non è valido.',
'in_array' => 'Il valore del campo :attribute non esiste in :other.',
'integer' => ':Attribute deve essere un numero intero.',
'ip' => ':Attribute deve essere un indirizzo IP valido.',
'ipv4' => ':Attribute deve essere un indirizzo IPv4 valido.',
'ipv6' => ':Attribute deve essere un indirizzo IPv6 valido.',
'json' => ':Attribute deve essere una stringa JSON valida.',
'lowercase' => ':Attribute deve contenere solo caratteri minuscoli.',
'lt' => [
'array' => ':Attribute deve contenere meno di :value elementi.',
'file' => ':Attribute deve essere minore di :value kilobyte.',
'numeric' => ':Attribute deve essere minore di :value.',
'string' => ':Attribute deve contenere meno di :value caratteri.',
],
'lte' => [
'array' => ':Attribute deve contenere un numero di elementi minore o uguale a :value.',
'file' => ':Attribute deve essere minore o uguale a :value kilobyte.',
'numeric' => ':Attribute deve essere minore o uguale a :value.',
'string' => ':Attribute deve contenere un numero di caratteri minore o uguale a :value.',
],
'mac_address' => 'Il campo :attribute deve essere un indirizzo MAC valido .',
'max' => [
'array' => ':Attribute non può avere più di :max elementi.',
'file' => ':Attribute non può essere superiore a :max kilobyte.',
'numeric' => ':Attribute non può essere superiore a :max.',
'string' => ':Attribute non può contenere più di :max caratteri.',
],
'max_digits' => ':Attribute non può contenere più di :max cifre.',
'mimes' => ':Attribute deve essere del tipo: :values.',
'mimetypes' => ':Attribute deve essere del tipo: :values.',
'min' => [
'array' => ':Attribute deve avere almeno :min elementi.',
'file' => ':Attribute deve essere almeno di :min kilobyte.',
'numeric' => ':Attribute deve essere almeno :min.',
'string' => ':Attribute deve contenere almeno :min caratteri.',
],
'min_digits' => ':Attribute deve contenere almeno :min cifre.',
'missing' => 'Il campo :attribute deve mancare.',
'missing_if' => 'Il campo :attribute deve mancare quando :other è :value.',
'missing_unless' => 'Il campo :attribute deve mancare a meno che :other non sia :value.',
'missing_with' => 'Il campo :attribute deve mancare quando è presente :values.',
'missing_with_all' => 'Il campo :attribute deve mancare quando sono presenti :values.',
'multiple_of' => ':Attribute deve essere un multiplo di :value',
'not_in' => 'Il valore selezionato per :attribute non è valido.',
'not_regex' => 'Il formato di :attribute non è valido.',
'numeric' => ':Attribute deve essere un numero.',
'password' => [
'letters' => ':Attribute deve contenere almeno un carattere.',
'mixed' => ':Attribute deve contenere almeno un carattere maiuscolo ed un carattere minuscolo.',
'numbers' => ':Attribute deve contenere almeno un numero.',
'symbols' => ':Attribute deve contenere almeno un simbolo.',
'uncompromised' => ':Attribute è presente negli archivi dei dati trafugati. Per piacere scegli un valore differente per :attribute.',
],
'present' => 'Il campo :attribute deve essere presente.',
'prohibited' => ':Attribute non consentito.',
'prohibited_if' => ':Attribute non consentito quando :other è :value.',
'prohibited_unless' => ':Attribute non consentito a meno che :other sia contenuto in :values.',
'prohibits' => ':Attribute impedisce a :other di essere presente.',
'regex' => 'Il formato del campo :attribute non è valido.',
'required' => 'Il campo :attribute è richiesto.',
'required_array_keys' => 'Il campo :attribute deve contenere voci per: :values.',
'required_if' => 'Il campo :attribute è richiesto quando :other è :value.',
'required_if_accepted' => ':Attribute è richiesto quando :other è accettato.',
'required_unless' => 'Il campo :attribute è richiesto a meno che :other sia in :values.',
'required_with' => 'Il campo :attribute è richiesto quando :values è presente.',
'required_with_all' => 'Il campo :attribute è richiesto quando :values sono presenti.',
'required_without' => 'Il campo :attribute è richiesto quando :values non è presente.',
'required_without_all' => 'Il campo :attribute è richiesto quando nessuno di :values è presente.',
'same' => ':Attribute e :other devono coincidere.',
'size' => [
'array' => ':Attribute deve contenere :size elementi.',
'file' => ':Attribute deve essere :size kilobyte.',
'numeric' => ':Attribute deve essere :size.',
'string' => ':Attribute deve contenere :size caratteri.',
],
'starts_with' => ':Attribute deve iniziare con uno dei seguenti: :values',
'string' => ':Attribute deve essere una stringa.',
'timezone' => ':Attribute deve essere una zona valida.',
'ulid' => ':Attribute deve essere un ULID valido.',
'unique' => ':Attribute è stato già utilizzato.',
'uploaded' => ':Attribute non è stato caricato.',
'uppercase' => ':Attribute deve contenere solo caratteri maiuscoli.',
'url' => 'Il formato del campo :attribute non è valido.',
'uuid' => ':Attribute deve essere un UUID valido.',
'attributes' => [
'address' => 'indirizzo',
'age' => 'età',
'amount' => 'Quantità',
'area' => 'la zona',
'available' => 'disponibile',
'birthday' => 'compleanno',
'body' => 'corpo',
'city' => 'città',
'content' => 'contenuto',
'country' => 'paese',
'created_at' => 'creato a',
'creator' => 'Creatore',
'current_password' => 'password attuale',
'date' => 'data',
'date_of_birth' => 'data di nascita',
'day' => 'giorno',
'deleted_at' => 'cancellato a',
'description' => 'descrizione',
'district' => 'quartiere',
'duration' => 'durata',
'email' => 'e-mail',
'excerpt' => 'estratto',
'filter' => 'filtro',
'first_name' => 'nome',
'gender' => 'genere',
'group' => 'gruppo',
'hour' => 'ora',
'image' => 'Immagine',
'last_name' => 'cognome',
'lesson' => 'lezione',
'line_address_1' => 'indirizzo di linea 1',
'line_address_2' => 'indirizzo di linea 2',
'message' => 'Messaggio',
'middle_name' => 'secondo nome',
'minute' => 'minuto',
'mobile' => 'cellulare',
'month' => 'mese',
'name' => 'nome',
'national_code' => 'codice nazionale',
'number' => 'numero',
'password' => 'parola d\'ordine',
'password_confirmation' => 'conferma password',
'phone' => 'telefono',
'photo' => 'foto',
'postal_code' => 'Codice Postale',
'price' => 'prezzo',
'province' => 'Provincia',
'recaptcha_response_field' => 'campo di risposta recaptcha',
'remember' => 'ricordare',
'restored_at' => 'restaurato a',
'result_text_under_image' => 'testo del risultato sotto l\'immagine',
'role' => 'ruolo',
'second' => 'secondo',
'sex' => 'sesso',
'short_text' => 'breve testo',
'size' => 'dimensione',
'state' => 'stato',
'street' => 'strada',
'student' => 'alunno',
'subject' => 'argomento',
'teacher' => 'insegnante',
'terms' => 'termini',
'test_description' => 'descrizione del testo',
'test_locale' => 'locale di prova',
'test_name' => 'nome di prova',
'text' => 'testo',
'time' => 'ora',
'title' => 'titolo',
'updated_at' => 'aggiornato a',
'username' => 'nome utente',
'year' => 'anno',
],
];

View File

@ -1,93 +1,69 @@
{
"name": "openstamanager",
"version": "3.0.0-dev.2",
"packageManager": "pnpm@7.14.0",
"packageManager": "pnpm@8.2.0",
"files": [],
"type": "module",
"scripts": {
"build": "vite build",
"build:dev": "vite build --mode development",
"build:watch": "vite build --watch",
"dev": "php artisan osm:dev-server-fix && vite",
"generate-barrels": "barrelsby -c ./.barrelsby.config.json && php artisan osm:barrels-generation-fix && eslint --fix \"resources/js/**/index.ts\"",
"serve": "php artisan serve",
"serve-dev": "concurrently --raw pnpm:serve pnpm:dev",
"serve-watch": "concurrently --raw pnpm:serve pnpm:watch",
"dev": "vite",
"preinstall": "npx only-allow pnpm",
"scss-types": "typed-scss-modules resources/scss -i node_modules"
},
"dependencies": {
"@inertiajs/inertia": "^0.11.1",
"@inertiajs/progress": "^0.2.7",
"@maicol07/inertia-mithril": "^0.5.2",
"@maicol07/mwc-card": "^0.25.3",
"@maicol07/mwc-layout-grid": "0.25.3-1",
"@material/data-table": "^14.0.0",
"@material/elevation": "^14.0.0",
"@material/mwc-button": "^0.27.0",
"@material/mwc-checkbox": "^0.27.0",
"@material/mwc-circular-progress": "^0.27.0",
"@material/mwc-dialog": "^0.27.0",
"@material/mwc-drawer": "^0.27.0",
"@material/mwc-fab": "^0.27.0",
"@material/mwc-formfield": "^0.27.0",
"@material/mwc-icon-button": "^0.27.0",
"@material/mwc-icon-button-toggle": "^0.27.0",
"@formkit/auto-animate": "1.0.0-beta.6",
"@maicol07/inertia-mithril": "^1.0.3",
"@maicol07/material-web-additions": "^1.2.11",
"@material/mwc-linear-progress": "^0.27.0",
"@material/mwc-list": "^0.27.0",
"@material/mwc-menu": "^0.27.0",
"@material/mwc-ripple": "^0.27.0",
"@material/mwc-select": "^0.27.0",
"@material/mwc-snackbar": "^0.27.0",
"@material/mwc-textarea": "^0.27.0",
"@material/mwc-textfield": "^0.27.0",
"@material/mwc-top-app-bar": "^0.27.0",
"@material/textfield": "^14.0.0",
"@material/theme": "^14.0.0",
"@material/typography": "^14.0.0",
"@mdi/font": "^7.0.96",
"async-wait-until": "2.0.12",
"cash-dom": "^8.1.1",
"@material/web": "1.0.0-pre.6",
"@mdi/js": "^7.2.96",
"classnames": "^2.3.2",
"collect.js": "^4.34.3",
"collect.js": "^4.36.1",
"coloquent": "npm:@maicol07/coloquent@^3.0.1-beta",
"deepmerge-ts": "^4.2.2",
"include-media": "^1.4.10",
"lit": "^2.4.0",
"locale-code": "^2.0.2",
"lodash-es": "^4.17.21",
"dayjs": "^1.11.7",
"include-media": "^2.0.0",
"lit": "^2.7.2",
"mithril": "^2.2.2",
"mithril-node-render": "^3.0.2",
"mithril-utilities": "^1.1.0",
"modern-normalize": "^1.1.0",
"postcss-scss": "^4.0.6",
"prntr": "^2.0.18",
"redaxios": "^0.5.1"
"readable-http-codes": "^1.1.1",
"ts-pattern": "^4.2.2",
"typescript-cookie": "^1.0.5"
},
"devDependencies": {
"@maicol07/eslint-config": "^2.2.2",
"@maicol07/eslint-config": "^2.2.4",
"@openstamanager/vite-config": "github:devcode-it/openstamanager-vite-config",
"@types/gulp": "^4.0.9",
"@types/lodash-es": "^4.17.6",
"@types/mithril": "^2.0.11",
"@types/node": "^18.11.6",
"@types/lodash-es": "^4.17.7",
"@types/mithril": "^2.0.12",
"@types/node": "^18.15.12",
"@types/ziggy-js": "^1.3.2",
"barrelsby": "^2.5.1",
"chokidar": "^3.5.3",
"concurrently": "^7.5.0",
"csstype": "^3.1.1",
"postcss": "^8.4.18",
"csstype": "^3.1.2",
"inertia-plugin": "^0.6.0",
"laravel-vite-plugin": "^0.7.4",
"postcss": "^8.4.23",
"postcss-html": "^1.5.0",
"sass": "^1.55.0",
"stylelint": "^14.14.0",
"sass": "^1.62.0",
"stylelint": "^15.5.0",
"stylelint-config-clean-order": "^5.0.1",
"stylelint-config-html": "^1.1.0",
"stylelint-config-idiomatic-order": "^9.0.0",
"stylelint-config-recommended-scss": "^8.0.0",
"stylelint-config-standard": "^29.0.0",
"stylelint-scss": "^4.3.0",
"typed-scss-modules": "^7.0.1",
"typescript": "^4.8.4",
"vite": "^3.2.0",
"vite-plugin-laravel": "^0.2.2",
"vite-plugin-pwa": "^0.13.1"
"stylelint-config-standard": "^33.0.0",
"stylelint-config-standard-scss": "^8.0.0",
"stylelint-scss": "^4.6.0",
"type-fest": "^3.8.0",
"typed-scss-modules": "^7.1.0",
"typescript": "^5.0.4",
"vite": "^4.3.0",
"vite-plugin-laravel-translations": "^0.1.4",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-pwa": "^0.14.7"
},
"publishConfig": {
"access": "public"

17
phpstan.neon Normal file
View File

@ -0,0 +1,17 @@
includes:
- ./vendor/nunomaduro/larastan/extension.neon
parameters:
paths:
- app/
# Level 9 is the highest level
level: 5
# ignoreErrors:
# - '#PHPDoc tag @var#'
#
# excludePaths:
# - ./*/*/FileToBeExcluded.php
#
# checkMissingIterableValueType: false

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
<?php /** @noinspection DevelopmentDependenciesUsageInspection */
<?php
/** @noinspection DevelopmentDependenciesUsageInspection */
declare(strict_types=1);
@ -6,26 +8,26 @@ use Rector\CodingStyle\Rector\Catch_\CatchExceptionNameMatchingTypeRector;
use Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector;
use Rector\CodingStyle\Rector\Encapsed\WrapEncapsedVariableInCurlyBracesRector;
use Rector\Config\RectorConfig;
use Rector\Laravel\Set\LaravelSetList;
use Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector;
use Rector\Php81\Rector\ClassConst\FinalizePublicClassConstantRector;
use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use RectorLaravel\Set\LaravelSetList;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/app',
__DIR__ . '/config',
__DIR__ . '/database'
__DIR__.'/app',
__DIR__.'/config',
__DIR__.'/database',
]);
// define sets of rules
$rectorConfig->sets([
SetList::PHP_80,
SetList::PHP_81,
// SetList::PHP_82,
LevelSetList::UP_TO_PHP_81,
SetList::PHP_82,
LevelSetList::UP_TO_PHP_82,
SetList::CODE_QUALITY,
SetList::CODING_STYLE,
SetList::DEAD_CODE,
@ -33,8 +35,9 @@ return static function (RectorConfig $rectorConfig): void {
SetList::MYSQL_TO_MYSQLI,
SetList::PSR_4,
SetList::PRIVATIZATION,
SetList::TYPE_DECLARATION_STRICT,
LaravelSetList::LARAVEL_90
SetList::TYPE_DECLARATION,
LaravelSetList::LARAVEL_90,
LaravelSetList::LARAVEL_CODE_QUALITY,
]);
$rectorConfig->skip([
@ -43,6 +46,6 @@ return static function (RectorConfig $rectorConfig): void {
RenameParamToMatchTypeRector::class,
FinalizeClassesWithoutChildrenRector::class,
FinalizePublicClassConstantRector::class,
CatchExceptionNameMatchingTypeRector::class
CatchExceptionNameMatchingTypeRector::class,
]);
};

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View File

Before

Width:  |  Height:  |  Size: 711 B

After

Width:  |  Height:  |  Size: 711 B

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,373 +0,0 @@
import '@material/mwc-linear-progress';
import '@material/mwc-list/mwc-list-item.js';
import '@osm/WebComponents/Select';
import type {LinearProgress as MWCLinearProgress} from '@material/mwc-linear-progress';
import {
type TableRowAttributes,
Component,
Mdi,
TableColumn,
TableFooter,
TableRow
} from '@osm/Components';
import type {Cash} from 'cash-dom';
import type {
Children,
Vnode,
VnodeDOM
} from 'mithril';
type PaginationAction = 'first' | 'next' | 'previous' | 'last';
export type Attributes = {
'rows-per-page'?: number,
'default-rows-per-page'?: number,
'aria-label'?: string,
checkable?: boolean,
paginated?: boolean
};
export class DataTable extends Component<Attributes> {
rows: Children[] = [];
columns: Children[];
footer: Children[];
rowsPerPage = {
options: [10, 25, 50, 75, 100],
currentStart: 0,
value: 10,
currentEnd: 10
};
oninit(vnode: Vnode<Attributes>) {
super.oninit(vnode);
let defaultRowsPerPage: number = Number.parseInt(this.attrs.get('default-rows-per-page', '10') as string, 10);
if (Number.isInteger(defaultRowsPerPage)) {
if (!this.rowsPerPage.options.includes(defaultRowsPerPage)) {
[defaultRowsPerPage] = this.rowsPerPage.options;
}
this.rowsPerPage.value = defaultRowsPerPage;
}
}
oncreate(vnode: VnodeDOM<Attributes>) {
super.oncreate(vnode);
$(this.element)
.find('thead th.mdc-data-table__header-cell--with-sort')
.on('click', this.onColumnClicked.bind(this));
$(this.element)
.find('.mdc-data-table__pagination-rows-per-page-select')
.val(String(this.rowsPerPage.value))
.on('selected', this.onPaginationSelected.bind(this));
$(this.element)
// eslint-disable-next-line sonarjs/no-duplicate-string
.find('.mdc-data-table__pagination-button')
.on('click', this.onPaginationButtonClicked.bind(this));
}
onbeforeupdate(vnode: VnodeDOM<Attributes, this>) {
super.onbeforeupdate(vnode);
const children = (vnode.children as Children[]).flat();
this.rows = this.tableRows(children);
this.columns = this.filterElements(children, TableColumn);
this.footer = this.filterElements(children, TableFooter);
const rowsPerPage = this.attrs.get('rows-per-page');
if (rowsPerPage) {
this.rowsPerPage.options = rowsPerPage
.split(',')
.map((value: string) => Number.parseInt(value, 10));
if (this.rowsPerPage.currentStart === 0) {
this.rowsPerPage.currentEnd = this.rowsPerPage.value >= this.rows.length
? this.rows.length
: this.rowsPerPage.value;
}
}
}
onupdate(vnode: VnodeDOM<Attributes, this>) {
super.onupdate(vnode);
const rows: Cash = $(this.element).find('tbody tr');
rows.hide().slice(this.rowsPerPage.currentStart, this.rowsPerPage.currentEnd).show();
if (this.rowsPerPage.currentStart === 0) {
this.paginate('first');
}
}
view() {
return (
<div className="mdc-data-table" {...this.attrs.all()}>
<div className="mdc-data-table__table-container">
<table
className="mdc-data-table__table"
aria-label={this.attrs.get('aria-label')}
>
<thead>
<tr className="mdc-data-table__header-row">
{this.attrs.has('checkable') && <TableColumn type="checkbox" />}
{this.columns}
</tr>
</thead>
<tbody className="mdc-data-table__content">{this.rows}</tbody>
{this.footer}
</table>
{this.attrs.has('paginated') && (
<div className="mdc-data-table__pagination">
<div className="mdc-data-table__pagination-trailing">
<div className="mdc-data-table__pagination-rows-per-page">
<div className="mdc-data-table__pagination-rows-per-page-label">
{__('Righe per pagina')}
</div>
<material-select
outlined
className="mdc-data-table__pagination-rows-per-page-select"
fixedMenuPosition
// @ts-ignore
style="--mdc-select-width: 112px; --mdc-select-height: 36px; --mdc-menu-item-height: 36px;"
>
{this.rowsPerPage.options.map((rowsPerPage) => (
<mwc-list-item key={rowsPerPage} value={String(rowsPerPage)}>
{rowsPerPage}
</mwc-list-item>
))}
</material-select>
</div>
<div className="mdc-data-table__pagination-navigation">
<div className="mdc-data-table__pagination-total">
{__(':start-:chunk di :total', {
start: this.rowsPerPage.currentStart + 1,
chunk: this.rowsPerPage.currentEnd > this.rows.length
? this.rows.length
: this.rowsPerPage.currentEnd,
total: this.rows.length
})}
</div>
<mwc-icon-button
className="mdc-data-table__pagination-button"
data-page="first"
disabled
>
<Mdi icon="page-first" />
</mwc-icon-button>
<mwc-icon-button
className="mdc-data-table__pagination-button"
data-page="previous"
disabled
>
<Mdi icon="chevron-left" />
</mwc-icon-button>
<mwc-icon-button
className="mdc-data-table__pagination-button"
data-page="next"
>
<Mdi icon="chevron-right" />
</mwc-icon-button>
<mwc-icon-button
className="mdc-data-table__pagination-button"
data-page="last"
>
<Mdi icon="page-last" />
</mwc-icon-button>
</div>
</div>
</div>
)}
<div className="mdc-data-table__progress-indicator">
<div className="mdc-data-table__scrim" />
<mwc-linear-progress
className="mdc-data-table__linear-progress"
indeterminate
/>
</div>
</div>
</div>
);
}
tableRows(children: Children[]): Children[] {
let rows = this.filterElements(children, TableRow);
if (this.attrs.has('checkable')) {
rows = rows.map<Children>((row: Children) => {
if (!row) {
return '';
}
const rowNode = row as Vnode<TableRowAttributes>;
return (
<TableRow key={rowNode.key} checkable {...rowNode.attrs}>
{rowNode.children}
</TableRow>
);
});
}
return rows;
}
filterElements(
elements: Children[],
tag: typeof TableRow | typeof TableColumn | typeof TableFooter | string
): Children[] {
const filtered = [];
for (const element of elements) {
if ((element as Vnode).tag === tag) {
filtered.push(element);
}
}
return filtered;
}
getProgress(): Element & Partial<MWCLinearProgress> | null {
return this.element.querySelector('.mdc-data-table__progress-indicator mwc-linear-progress');
}
showProgress() {
this.manageProgress(true);
}
hideProgress() {
this.manageProgress(false);
}
onColumnClicked(event: Event) {
this.showProgress();
const column: Cash = $(event.target as Element).closest('th');
const ascendingClass = 'mdc-data-table__header-cell--sorted';
// Clean previously sorted info and arrows
const columns = $(this.element).find('thead th');
columns.removeClass(ascendingClass);
columns.off('click').on('click', this.onColumnClicked.bind(this));
// Add ony one header to sort
column.addClass(ascendingClass);
// Do sorting
this.sortTable(column, false);
// Set/remove callbacks
column.off('click');
column.find('mwc-icon-button-toggle').on('click', () => {
this.sortTable(column);
});
}
sortTable(column: Cash, toggleClass = true) {
const cells = $(this.element)
.find(`tr td:nth-child(${column.index() + 1})`)
.get();
// Handle button class
if (toggleClass) {
column.toggleClass('mdc-data-table__header-cell--sorted-descending');
}
const isNumeric = column.attr('type') === 'numeric';
const isDescending = column.hasClass(
'mdc-data-table__header-cell--sorted-descending'
);
cells.sort((a: HTMLElement, b: HTMLElement) => {
let aValue: string | number = a.textContent as string;
let bValue: string | number = b.textContent as string;
if (isNumeric) {
aValue = Number.parseFloat(aValue);
bValue = Number.parseFloat(bValue);
}
if (!isDescending) {
const temporary = aValue;
aValue = bValue;
bValue = temporary;
}
if (typeof aValue === 'string' && typeof bValue === 'string') {
return aValue.localeCompare(bValue);
}
return aValue < bValue ? -1 : (aValue > bValue ? 1 : 0);
});
for (const cell of cells) {
const row = $(cell).parent();
row.appendTo(row.parent());
}
this.hideProgress();
}
onPaginationSelected(event: Event & {detail: {index: number}}) {
const selectValue = $(event.target as HTMLFormElement).val();
const rowsPerPage = Number.parseInt(selectValue as string, 10);
this.rowsPerPage = {
...this.rowsPerPage,
value: rowsPerPage,
currentStart: 0,
currentEnd: rowsPerPage
};
m.redraw();
}
onPaginationButtonClicked(event: Event) {
const button: HTMLButtonElement | null = (event.target as HTMLElement).closest('.mdc-data-table__pagination-button');
this.paginate(button?.dataset.page as PaginationAction);
m.redraw();
}
paginate(action: PaginationAction) {
if (action === 'first' || action === 'last') {
const checkPagination = () => (action === 'first' ? this.rowsPerPage.currentStart > 0 : this.rowsPerPage.currentEnd < this.rows.length);
let check = checkPagination();
while (check) {
this.paginate(action === 'first' ? 'previous' : 'next');
check = checkPagination();
}
} else {
const increments = {
next: this.rowsPerPage.value,
previous: -this.rowsPerPage.value
};
const increment = increments[action];
this.rowsPerPage.currentStart += increment;
if (this.rowsPerPage.currentStart < 0) {
this.rowsPerPage.currentStart = 0;
}
this.rowsPerPage.currentEnd += increment;
}
const paginationButtons: NodeListOf<HTMLButtonElement> = this.element.querySelectorAll('.mdc-data-table__pagination-button');
const disabled = {
first: this.rowsPerPage.currentStart === 0,
previous: this.rowsPerPage.currentStart === 0,
next: this.rowsPerPage.currentEnd >= this.rows.length,
last: this.rowsPerPage.currentEnd >= this.rows.length
};
for (const button of paginationButtons) {
button.disabled = disabled[button.dataset.page as PaginationAction];
}
}
private manageProgress(show: boolean) {
$(this.element).toggleClass('mdc-data-table--in-progress');
const progress = this.getProgress();
if (progress) {
(progress as MWCLinearProgress)[show ? 'open' : 'close']();
}
}
}

View File

@ -1,56 +0,0 @@
import type {Cash} from 'cash-dom/dist/cash';
import {inRange} from 'lodash-es';
import type {
Vnode,
VnodeDOM
} from 'mithril';
import {Component} from '../Component';
type Attributes = {type?: string};
export class TableCell extends Component<Attributes> {
view(vnode: Vnode) {
this.attrs.addClassNames('mdc-data-table__cell', {
[`mdc-data-table__cell--${this.attrs.get('type') as string}`]: this.attrs.has(
'type'
)
});
if (
(!Array.isArray(vnode.children) || vnode.children.length === 0)
&& this.attrs.get('type') === 'checkbox'
) {
vnode.children = [<mwc-checkbox key="checkbox" className="mdc-data-table__row-checkbox" />];
}
return <td {...this.attrs.all()}>{vnode.children}</td>;
}
oncreate(vnode: VnodeDOM<Attributes>) {
super.oncreate(vnode);
const checkboxes = (): Cash => $(this.element)
.closest('.mdc-data-table')
.find('tbody tr[checkable] mwc-checkbox');
const cell: Cash = $(this.element);
cell.children('mwc-checkbox').on('change', () => {
const row = cell.parent();
row.toggleClass('mdc-data-table__row--selected');
const headerCheckbox = cell
.closest('.mdc-data-table')
.find('thead th mwc-checkbox');
const checks = checkboxes();
const checked = checks.filter('[checked]');
if (inRange(checked.length, 1, checks.length)) {
headerCheckbox.prop('indeterminate', true);
headerCheckbox.prop('checked', false);
} else {
headerCheckbox.prop('checked', checks.length === checked.length);
headerCheckbox.prop('indeterminate', false);
}
});
}
}

View File

@ -1,153 +0,0 @@
import '@material/mwc-icon-button-toggle';
import type {Cash} from 'cash-dom';
import type {
Children,
Vnode,
VnodeDOM
} from 'mithril';
import {Component} from '../Component';
import {Mdi} from '../Mdi';
type Attributes = {
type?: 'numeric' | 'checkbox',
id?: string,
sortable?: boolean,
filterable?: boolean,
};
export class TableColumn extends Component<Attributes> {
view(vnode: Vnode) {
this.attrs.addClassNames('mdc-data-table__header-cell', {
[`mdc-data-table__header-cell--${this.attrs.get(
'type'
) as string}`]: this.attrs.has('type')
});
let {children}: {children?: Children} = vnode;
if (this.attrs.has('sortable')) {
this.attrs.addClassNames('mdc-data-table__header-cell--with-sort');
this.attrs
.put('aria-sort', 'none')
.put('data-column-id', this.attrs.get('id'));
children = (
<div className="mdc-data-table__header-cell-wrapper">
<mwc-icon-button-toggle style="--mdc-icon-button-size: 28px; display: none;">
<Mdi icon="arrow-down-thin" slot="onIcon" />
<Mdi icon="arrow-up-thin" slot="offIcon" />
</mwc-icon-button-toggle>
&nbsp;
<div className="mdc-data-table__header-cell-label">
{children}
</div>
</div>
);
}
if ((
(!children || (Array.isArray(children) && children.length === 0))
&& this.attrs.get('type') === 'checkbox'
)) {
children = <mwc-checkbox className="mdc-data-table__header-row-checkbox" />;
}
if (this.attrs.get('type') !== 'checkbox' && this.attrs.has('filterable')) {
children = (
<>
{children}
<div style="margin-top: 8px;">
<text-field
outlined
className="mdc-data-table__filter-textfield"
label={__('Filtro')}
compact
/>
</div>
</>
);
}
return (
<th {...this.attrs.all()} role="columnheader" scope="col">
{children}
</th>
);
}
oncreate(vnode: VnodeDOM<Attributes>) {
super.oncreate(vnode);
if (this.attrs.get('type') === 'checkbox') {
const checkbox = $(this.element).children(
'.mdc-data-table__header-row-checkbox'
);
checkbox.on('change', this.onCheckboxClicked.bind(this));
}
// Handle click on a column (add arrows)
const observer = new MutationObserver(this.onClassChanged.bind(this));
observer.observe(this.element, {
attributes: true,
attributeFilter: ['class']
});
$(this.element)
.find('.mdc-data-table__filter-textfield')
.on('input', this.onFilterInput.bind(this))
.on('click', (event: Event) => event.stopPropagation());
}
onCheckboxClicked(event: Event) {
const row: Cash = $(this.element)
.closest('table')
.find('tbody tr[checkable]');
const selectedClass = 'mdc-data-table__row--selected';
const checkbox = event.target as HTMLInputElement;
row.toggleClass(selectedClass, checkbox.checked);
row.find('mwc-checkbox').prop('checked', checkbox.checked);
}
onClassChanged(mutations: MutationRecord[]) {
for (const mutation of mutations) {
const {classList} = mutation.target as HTMLElement;
const ascendingClass = 'mdc-data-table__header-cell--sorted';
const descendingClass = 'mdc-data-table__header-cell--sorted-descending';
const onValue = classList.contains(descendingClass);
const button: Cash = $(this.element).find('mwc-icon-button-toggle');
button.prop('on', onValue);
if (
classList.contains(ascendingClass)
|| classList.contains(descendingClass)
) {
$(this.element).css('cursor', 'auto');
button.show();
} else if (
!classList.contains(ascendingClass)
&& !classList.contains(descendingClass)
) {
$(this.element).css('cursor', 'pointer');
button.hide();
}
}
}
onFilterInput(event: InputEvent) {
const index = $(this.element).index();
const rows: Cash = $(this.element).closest('table').find('tbody tr');
const {value} = event.target as HTMLInputElement;
rows.hide();
rows
.filter(
(index_, element) => $(element)
.find(`td:nth-child(${index + 1})`)
.text()
.search(value) !== -1
)
.show();
}
}

View File

@ -1,9 +0,0 @@
import type {Vnode} from 'mithril';
import {Component} from '../Component';
export class TableFooter extends Component {
view(vnode: Vnode) {
return <tfoot {...this.attrs.all()}>{vnode.children}</tfoot>;
}
}

View File

@ -1,42 +0,0 @@
import '@material/mwc-checkbox';
import {collect} from 'collect.js';
import type {
Children,
Vnode
} from 'mithril';
import {Component} from '../Component';
import {TableCell} from './TableCell';
export interface TableRowAttributes {
checkable?: boolean;
}
export class TableRow extends Component<TableRowAttributes> {
view(vnode: Vnode<TableRowAttributes>) {
this.attrs.addClassNames('mdc-data-table__row');
return (
<tr {...this.attrs.all()}>
{this.checkbox(vnode.children as Children[])}
{vnode.children}
</tr>
);
}
checkbox(children: Children[]): Children {
if (!this.attrs.has('checkable')) {
return <></>;
}
for (const child of children) {
const attributes = collect((child as Vnode).attrs);
if (attributes.get('type') === 'checkbox') {
break;
}
}
return <TableCell type="checkbox" />;
}
}

View File

@ -1,9 +0,0 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from './DataTable';
export * from './TableCell';
export * from './TableColumn';
export * from './TableFooter';
export * from './TableRow';

View File

@ -1,6 +0,0 @@
import {InertiaLink as Link} from '@maicol07/inertia-mithril';
import {LinkAttributes} from '@maicol07/inertia-mithril/dist/Link.js';
export class InertiaLink extends Link {
attrsTypes: LinkAttributes;
}

View File

@ -1,64 +0,0 @@
import '@material/mwc-circular-progress';
import '@material/mwc-button';
import type {Button} from '@material/mwc-button';
import type {CircularProgress} from '@material/mwc-circular-progress';
import {
Component,
Mdi
} from '@osm/Components';
import type CSS from 'csstype';
import type {VnodeDOM} from 'mithril';
import {
JSXElement,
MaterialIcons
} from '../typings';
type Attributes = JSXElement<Button> & {
icon?: string
};
export class LoadingButton extends Component<Attributes> {
view() {
return (
<mwc-button data-component-type="loading-button" {...this.attrs.all()}>
<span slot="icon" style="display: inline;">
<mwc-circular-progress
indeterminate
// @ts-ignore
style={this.getCSSProperties()}
/>
{this.attrs.has('icon') ? (
<Mdi icon={this.attrs.get('icon') as MaterialIcons}/>
) : (
''
)}
</span>
</mwc-button>
);
}
getCSSProperties() {
const css: CSS.Properties & Record<string, string> = {
display: 'none',
verticalAlign: 'bottom'
};
if (this.attrs.has('raised')) {
css['--mdc-theme-primary'] = '#ffffff';
}
if (this.attrs.has('icon')) {
css.marginRight = '8px';
}
return css;
}
oncreate(vnode: VnodeDOM<Attributes>) {
super.oncreate(vnode);
this.element.querySelector<CircularProgress>('mwc-circular-progress')
?.setAttribute('density', '-7');
}
}

View File

@ -1,36 +0,0 @@
import {CircularProgress} from '@material/mwc-circular-progress';
import {Manager} from './Manager';
export class CircularProgressManager extends Manager {
static selector = 'mwc-circular-progress';
static filter = (element: CircularProgress) => element.closest('mwc-button')?.dataset.componentType !== 'loading-button';
constructor(protected loading: CircularProgress) {
super(loading);
}
public show() {
this.loading.open();
}
public hide() {
this.loading.close();
}
public get indeterminate(): boolean {
return this.loading.indeterminate;
}
public set indeterminate(value: boolean) {
this.loading.indeterminate = value;
}
public get progress(): number {
return this.loading.progress;
}
public set progress(value: number) {
this.loading.progress = value;
}
}

View File

@ -1,19 +0,0 @@
import {Dialog} from '@material/mwc-dialog';
import {Manager} from './Manager';
export class DialogManager extends Manager {
static selector = 'dialog';
constructor(protected dialog: Dialog) {
super(dialog);
}
public show(dialog: Dialog) {
this.dialog.show();
}
public hide() {
this.dialog.close();
}
}

View File

@ -1,13 +0,0 @@
import {Button} from '@material/mwc-button';
import {CircularProgressManager} from '@osm/Components/Managers';
export class LoadingButtonManager extends CircularProgressManager {
static selector = 'mwc-button[data-component-type="loading-button"]';
constructor(private button: Button) {
const loading = button.querySelector('mwc-circular-progress');
if (loading) {
super(loading);
}
}
}

Some files were not shown because too many files have changed in this diff Show More