git.fiddlerwoaroof.com
src/stack.lisp
0d44e5e6
 (in-package :mfa-tool)
 (defpackage :mfa-tool.stack
   (:use :cl)
   (:export #:stack-interface
            #:format-stack-status))
 (in-package :mfa-tool.stack)
 
 (defun dispatch-with-action-creator (action-creator)
   (lambda (store data)
     (mfa-tool.store:dispatch store
                              (funcall action-creator data))))
 
 (defmacro with-pp ((pane) &body body)
   `(capi:apply-in-pane-process ,pane
                                (lambda ()
                                  ,@body)))
 
 (defun human-readable-stack-status (stack)
   (nstring-capitalize
    (substitute #\space #\_
                (string (daydreamer.aws-result:stack-status stack)))))
 (defun format-stack-status (stream stack &optional colon-p at-sign-p)
   (declare (ignore colon-p at-sign-p))
   (princ (human-readable-stack-status stack)
          stream))
 
 (defun get-output-columns (type col1 col2)
4dde8453
   `((:title ,(format nil "~a Name" type)
0d44e5e6
      :adjust :right
      :width (character ,(max (+ (length type) 5) col1)))
4dde8453
     (:title "Value"
0d44e5e6
      :adjust :left
      :width (character ,(max (+ (length type) 5) col2)))))
 
8a9ff578
 ;; doesn't work, seems to cause segfaults, but would be a cool feature :(
 (defun go-to-console (interface stack)
   (with-pp (interface)
     (mfa-tool::open-url
      (format nil "https://us-west-2.console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/stackinfo?stackId=~a"
              (quri:url-encode (daydreamer.aws-result:stack-id stack))))))
 
0d44e5e6
 (capi:define-interface stack-interface (capi:interface mfa-tool.stack-store:stack-store)
   ()
   (:panes
    (region-chooser capi:option-pane
                    :reader region-chooser
                    ;; :external-max-width '(character 35)
4dde8453
                    :items (list :|us-east-1| :|us-east-2|
                                 :|us-west-1| :|us-west-2|
                                 :|ca-central-1|
                                 :|eu-central-1|
                                 :|eu-west-1| :|eu-west-2|)
                    :selected-item (mfa-tool.aws-dispatcher::region capi:interface)
0d44e5e6
                    :selection-callback (dispatch-with-action-creator 'mfa-tool.aws-dispatcher::update-region)
                    :callback-type :interface-data)
 
    (stack-chooser capi:list-panel
                   :reader stack-chooser
                   ;; :external-max-width '(character 35)
                   :items ()
                   :print-function 'daydreamer.aws-result:stack-name
                   :selection-callback (dispatch-with-action-creator 'mfa-tool.aws-dispatcher:select-stack)
                   :callback-type :interface-data)
 
81fd0fa2
    (refresh-status capi:push-button
                    :text "Refresh"
                    :callback-type :interface
                    :callback (lambda (store)
                                (mfa-tool.store:dispatch store :refresh)))
8a9ff578
    #+(or)
    (open-web-console capi:push-button
                      :text "Open"
                      :callback-type :interface
                      :callback (lambda (store)
                                  (go-to-console
                                   (mfa-tool.stack-store:selected-stack store))))
0d44e5e6
    (status-display capi:display-pane
                    :background :transparent
                    :reader status-display
                    :text "")
 
    (outputs-display capi:multi-column-list-panel
                     :columns (get-output-columns "Output" 10 10)
                     :header-args (list :selection-callback :sort)
                     :sort-descriptions (list (capi:make-sorting-description
                                               :type "Output Name"
                                               :key 'car
                                               :sort 'string-lessp
                                               :reverse-sort 'string-greaterp)
                                              (capi:make-sorting-description
                                               :type "Value"
                                               :key 'cadr
                                               :sort 'string-lessp
                                               :reverse-sort 'string-greaterp))
                     :items nil
                     :vertical-scroll t
                     :reader outputs-display
                     :visible-min-height '(character 10)
                     :visible-min-width '(character 50))
    (parameters-display capi:multi-column-list-panel
                        :columns (get-output-columns "Parameter" 10 10)
                        :header-args (list :selection-callback :sort)
                        :sort-descriptions (list (capi:make-sorting-description
                                                  :type "Parameter Name"
                                                  :key 'car
                                                  :sort 'string-lessp
                                                  :reverse-sort 'string-greaterp)
                                                 (capi:make-sorting-description
                                                  :type "Value"
                                                  :key 'cadr
                                                  :sort 'string-lessp
                                                  :reverse-sort 'string-greaterp))
                        :items nil
                        :vertical-scroll t
                        :reader parameters-display
                        :visible-min-height '(character 10)
                        :visible-min-width '(character 50)))
   (:layouts
    (key-layout capi:column-layout
                '(region-chooser
                  stack-chooser)
                :visible-max-width '(character 35))
81fd0fa2
    (status-layout capi:row-layout
                   '(status-display
                     nil
                     #+(or)open-web-console
                     refresh-status)
                   :adjust :center)
0d44e5e6
    (attribute-layout capi:column-layout
81fd0fa2
                      '(status-layout
0d44e5e6
                        parameters-display
                        outputs-display))
    (main-layout capi:row-layout
                 '(key-layout
                   attribute-layout)))
   (:default-initargs
    :layout 'main-layout
    :title "Stack Explorer"
    :visible-min-width 800))
 
 (defmethod mfa-tool.store:execute :after ((interface stack-interface) (_ mfa-tool.aws-dispatcher:update-stacks))
   (with-pp (interface)
     (with-accessors ((stack-chooser stack-chooser)) interface
81fd0fa2
       (setf (capi:collection-items stack-chooser) (mfa-tool.stack-store:available-stacks interface)
             (capi:choice-selected-item
              (stack-chooser interface)) (mfa-tool.stack-store:selected-stack interface)))))
0d44e5e6
 
 (defun max-widths (cols)
   (loop for (col1 col2) in cols
         maximizing (length col1) into len1
         maximizing (length col2) into len2
         finally (return (list len1 len2))))
 
 (defmethod mfa-tool.store:execute :after ((interface stack-interface) (_ mfa-tool.aws-dispatcher:select-stack))
   (with-pp (interface)
     (with-accessors ((status-display status-display) (selected-stack mfa-tool.stack-store:selected-stack)
                      (outputs-display outputs-display) (outputs mfa-tool.stack-store:outputs)
                      (parameters-display parameters-display) (parameters mfa-tool.stack-store:parameters))
         interface
       (capi:modify-multi-column-list-panel-columns
        outputs-display :columns (apply 'get-output-columns "Output" (max-widths outputs)))
       (capi:modify-multi-column-list-panel-columns
        parameters-display :columns (apply 'get-output-columns "Parameter" (max-widths parameters)))
4dde8453
 
81fd0fa2
       (when (not (eq (capi:choice-selected-item (stack-chooser interface))
                      (mfa-tool.aws-dispatcher:stack _)))
         (setf (capi:choice-selected-item (stack-chooser interface)) (mfa-tool.stack-store:selected-stack interface)))
0d44e5e6
       (setf (capi:display-pane-text status-display)
             (format nil "~a: ~/mfa-tool.stack:format-stack-status/"
                     (daydreamer.aws-result:stack-name selected-stack)
                     selected-stack)
             (capi:collection-items parameters-display) parameters
             (capi:collection-items outputs-display) outputs))))