packages feed

atlassian-connect-descriptor 0.2.0.1 → 0.3.0.0

raw patch · 7 files changed

+523/−101 lines, 7 filesdep +bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring

API changes (from Hackage documentation)

- Data.Connect.Descriptor: GeneralPage :: Text -> Name GeneralPage -> Text -> Maybe Text -> Maybe IconDetails -> Maybe Integer -> [Condition] -> GeneralPage
- Data.Connect.Descriptor: data GeneralPage
- Data.Connect.Descriptor: generalPageConditions :: GeneralPage -> [Condition]
- Data.Connect.Descriptor: generalPageIcon :: GeneralPage -> Maybe IconDetails
- Data.Connect.Descriptor: generalPageKey :: GeneralPage -> Text
- Data.Connect.Descriptor: generalPageLocation :: GeneralPage -> Maybe Text
- Data.Connect.Descriptor: generalPageName :: GeneralPage -> Name GeneralPage
- Data.Connect.Descriptor: generalPageUrl :: GeneralPage -> Text
- Data.Connect.Descriptor: generalPageWeight :: GeneralPage -> Maybe Integer
- Data.Connect.Descriptor: jiraGeneralPages :: JIRAModules -> [GeneralPage]
- Data.Connect.Descriptor: jiraJiraProjectAdminTabPanels :: JIRAModules -> [JIRAProjectAdminTabPanel]
- Data.Connect.Descriptor: jiraWebPanels :: JIRAModules -> [WebPanel]
- Data.Connect.Descriptor: jiraWebhooks :: JIRAModules -> [Webhook]
+ Data.Connect.Descriptor: DialogOptions :: Maybe Integer -> Maybe Integer -> Maybe Bool -> DialogOptions
+ Data.Connect.Descriptor: Extraction :: Text -> ExtractionType -> Extraction
+ Data.Connect.Descriptor: ExtractionTypeDate :: ExtractionType
+ Data.Connect.Descriptor: ExtractionTypeNumber :: ExtractionType
+ Data.Connect.Descriptor: ExtractionTypeString :: ExtractionType
+ Data.Connect.Descriptor: ExtractionTypeText :: ExtractionType
+ Data.Connect.Descriptor: I18nText :: Text -> Maybe Text -> I18nText
+ Data.Connect.Descriptor: InlineDialogOptions :: Maybe Text -> Maybe Bool -> Maybe Bool -> Maybe Integer -> Maybe Bool -> Maybe Text -> Maybe Text -> Maybe Bool -> Maybe Bool -> InlineDialogOptions
+ Data.Connect.Descriptor: IssueEntityType :: EntityType
+ Data.Connect.Descriptor: JIRAEntityProperties :: Text -> I18nText -> Maybe EntityType -> [KeyConfiguration] -> JIRAEntityProperties
+ Data.Connect.Descriptor: JIRAGenericTabPanel :: Text -> I18nText -> Text -> [Condition] -> Maybe Weight -> ModuleParams -> JIRAGenericTabPanel
+ Data.Connect.Descriptor: JIRAPage :: Text -> I18nText -> Text -> Maybe Text -> Maybe Weight -> Maybe IconDetails -> [Condition] -> ModuleParams -> JIRAPage
+ Data.Connect.Descriptor: JIRAReport :: Text -> I18nText -> Text -> I18nText -> Maybe JIRAReportCategory -> Maybe Weight -> Maybe Text -> JIRAReport
+ Data.Connect.Descriptor: JIRASearchRequestView :: Text -> I18nText -> Text -> Maybe I18nText -> Maybe Weight -> [Condition] -> ModuleParams -> JIRASearchRequestView
+ Data.Connect.Descriptor: JIRAWebSection :: Text -> I18nText -> Text -> Maybe I18nText -> [Condition] -> Maybe Weight -> ModuleParams -> JIRAWebSection
+ Data.Connect.Descriptor: JIRAWorkflowPostFunction :: Text -> I18nText -> URLBean -> Maybe I18nText -> Maybe URLBean -> Maybe URLBean -> Maybe URLBean -> JIRAWorkflowPostFunction
+ Data.Connect.Descriptor: KeyConfiguration :: Text -> [Extraction] -> KeyConfiguration
+ Data.Connect.Descriptor: TargetDialog :: (Maybe DialogOptions) -> Target
+ Data.Connect.Descriptor: TargetInlineDialog :: (Maybe InlineDialogOptions) -> Target
+ Data.Connect.Descriptor: TargetPage :: Target
+ Data.Connect.Descriptor: URLBean :: Text -> URLBean
+ Data.Connect.Descriptor: WebItem :: Text -> I18nText -> Text -> Text -> Maybe I18nText -> Maybe IconDetails -> Maybe Weight -> Maybe Target -> [Text] -> Maybe WebItemContext -> [Condition] -> ModuleParams -> WebItem
+ Data.Connect.Descriptor: dI18n :: I18nText -> Maybe Text
+ Data.Connect.Descriptor: dValue :: I18nText -> Text
+ Data.Connect.Descriptor: data DialogOptions
+ Data.Connect.Descriptor: data EntityType
+ Data.Connect.Descriptor: data Extraction
+ Data.Connect.Descriptor: data ExtractionType
+ Data.Connect.Descriptor: data I18nText
+ Data.Connect.Descriptor: data InlineDialogOptions
+ Data.Connect.Descriptor: data JIRAEntityProperties
+ Data.Connect.Descriptor: data JIRAGenericTabPanel
+ Data.Connect.Descriptor: data JIRAPage
+ Data.Connect.Descriptor: data JIRAReport
+ Data.Connect.Descriptor: data JIRASearchRequestView
+ Data.Connect.Descriptor: data JIRAWebSection
+ Data.Connect.Descriptor: data JIRAWorkflowPostFunction
+ Data.Connect.Descriptor: data KeyConfiguration
+ Data.Connect.Descriptor: data Target
+ Data.Connect.Descriptor: data URLBean
+ Data.Connect.Descriptor: data WebItem
+ Data.Connect.Descriptor: doChrome :: DialogOptions -> Maybe Bool
+ Data.Connect.Descriptor: doHeight :: DialogOptions -> Maybe Integer
+ Data.Connect.Descriptor: doWidth :: DialogOptions -> Maybe Integer
+ Data.Connect.Descriptor: extractionObjectName :: Extraction -> Text
+ Data.Connect.Descriptor: extractionType :: Extraction -> ExtractionType
+ Data.Connect.Descriptor: idoCloseOthers :: InlineDialogOptions -> Maybe Bool
+ Data.Connect.Descriptor: idoIsRelativeToMouse :: InlineDialogOptions -> Maybe Bool
+ Data.Connect.Descriptor: idoOffsetX :: InlineDialogOptions -> Maybe Text
+ Data.Connect.Descriptor: idoOffsetY :: InlineDialogOptions -> Maybe Text
+ Data.Connect.Descriptor: idoOnHover :: InlineDialogOptions -> Maybe Bool
+ Data.Connect.Descriptor: idoOnTop :: InlineDialogOptions -> Maybe Bool
+ Data.Connect.Descriptor: idoPersistent :: InlineDialogOptions -> Maybe Bool
+ Data.Connect.Descriptor: idoShowDelay :: InlineDialogOptions -> Maybe Integer
+ Data.Connect.Descriptor: idoWidth :: InlineDialogOptions -> Maybe Text
+ Data.Connect.Descriptor: jepEntityType :: JIRAEntityProperties -> Maybe EntityType
+ Data.Connect.Descriptor: jepKey :: JIRAEntityProperties -> Text
+ Data.Connect.Descriptor: jepKeyConfigurations :: JIRAEntityProperties -> [KeyConfiguration]
+ Data.Connect.Descriptor: jepName :: JIRAEntityProperties -> I18nText
+ Data.Connect.Descriptor: jiraPageConditions :: JIRAPage -> [Condition]
+ Data.Connect.Descriptor: jiraPageIcon :: JIRAPage -> Maybe IconDetails
+ Data.Connect.Descriptor: jiraPageKey :: JIRAPage -> Text
+ Data.Connect.Descriptor: jiraPageLocation :: JIRAPage -> Maybe Text
+ Data.Connect.Descriptor: jiraPageName :: JIRAPage -> I18nText
+ Data.Connect.Descriptor: jiraPageParams :: JIRAPage -> ModuleParams
+ Data.Connect.Descriptor: jiraPageUrl :: JIRAPage -> Text
+ Data.Connect.Descriptor: jiraPageWeight :: JIRAPage -> Maybe Weight
+ Data.Connect.Descriptor: jmAdminPages :: JIRAModules -> [JIRAPage]
+ Data.Connect.Descriptor: jmConfigurePage :: JIRAModules -> Maybe JIRAPage
+ Data.Connect.Descriptor: jmGeneralPages :: JIRAModules -> [JIRAPage]
+ Data.Connect.Descriptor: jmJiraComponentTabPanels :: JIRAModules -> [JIRAGenericTabPanel]
+ Data.Connect.Descriptor: jmJiraEntityProperties :: JIRAModules -> [JIRAEntityProperties]
+ Data.Connect.Descriptor: jmJiraIssueTabPanels :: JIRAModules -> [JIRAGenericTabPanel]
+ Data.Connect.Descriptor: jmJiraProfileTabPanels :: JIRAModules -> [JIRAGenericTabPanel]
+ Data.Connect.Descriptor: jmJiraProjectAdminTabPanels :: JIRAModules -> [JIRAProjectAdminTabPanel]
+ Data.Connect.Descriptor: jmJiraProjectTabPanels :: JIRAModules -> [JIRAGenericTabPanel]
+ Data.Connect.Descriptor: jmJiraReports :: JIRAModules -> [JIRAReport]
+ Data.Connect.Descriptor: jmJiraSearchRequestViews :: JIRAModules -> [JIRASearchRequestView]
+ Data.Connect.Descriptor: jmJiraVersionTabPanels :: JIRAModules -> [JIRAGenericTabPanel]
+ Data.Connect.Descriptor: jmJiraWorkflowPostFunctions :: JIRAModules -> [JIRAWorkflowPostFunction]
+ Data.Connect.Descriptor: jmWebItems :: JIRAModules -> [WebItem]
+ Data.Connect.Descriptor: jmWebPanels :: JIRAModules -> [WebPanel]
+ Data.Connect.Descriptor: jmWebSections :: JIRAModules -> [JIRAWebSection]
+ Data.Connect.Descriptor: jmWebhooks :: JIRAModules -> [Webhook]
+ Data.Connect.Descriptor: jpatpParams :: JIRAProjectAdminTabPanel -> ModuleParams
+ Data.Connect.Descriptor: jrDescription :: JIRAReport -> I18nText
+ Data.Connect.Descriptor: jrKey :: JIRAReport -> Text
+ Data.Connect.Descriptor: jrName :: JIRAReport -> I18nText
+ Data.Connect.Descriptor: jrReportCategory :: JIRAReport -> Maybe JIRAReportCategory
+ Data.Connect.Descriptor: jrThumbnailUrl :: JIRAReport -> Maybe Text
+ Data.Connect.Descriptor: jrUrl :: JIRAReport -> Text
+ Data.Connect.Descriptor: jrWeight :: JIRAReport -> Maybe Weight
+ Data.Connect.Descriptor: jsrvConditions :: JIRASearchRequestView -> [Condition]
+ Data.Connect.Descriptor: jsrvDescription :: JIRASearchRequestView -> Maybe I18nText
+ Data.Connect.Descriptor: jsrvKey :: JIRASearchRequestView -> Text
+ Data.Connect.Descriptor: jsrvName :: JIRASearchRequestView -> I18nText
+ Data.Connect.Descriptor: jsrvParams :: JIRASearchRequestView -> ModuleParams
+ Data.Connect.Descriptor: jsrvUrl :: JIRASearchRequestView -> Text
+ Data.Connect.Descriptor: jsrvWeight :: JIRASearchRequestView -> Maybe Weight
+ Data.Connect.Descriptor: jtpConditions :: JIRAGenericTabPanel -> [Condition]
+ Data.Connect.Descriptor: jtpKey :: JIRAGenericTabPanel -> Text
+ Data.Connect.Descriptor: jtpName :: JIRAGenericTabPanel -> I18nText
+ Data.Connect.Descriptor: jtpParams :: JIRAGenericTabPanel -> ModuleParams
+ Data.Connect.Descriptor: jtpUrl :: JIRAGenericTabPanel -> Text
+ Data.Connect.Descriptor: jtpWeight :: JIRAGenericTabPanel -> Maybe Weight
+ Data.Connect.Descriptor: jwpfCreate :: JIRAWorkflowPostFunction -> Maybe URLBean
+ Data.Connect.Descriptor: jwpfDescription :: JIRAWorkflowPostFunction -> Maybe I18nText
+ Data.Connect.Descriptor: jwpfEdit :: JIRAWorkflowPostFunction -> Maybe URLBean
+ Data.Connect.Descriptor: jwpfKey :: JIRAWorkflowPostFunction -> Text
+ Data.Connect.Descriptor: jwpfName :: JIRAWorkflowPostFunction -> I18nText
+ Data.Connect.Descriptor: jwpfTriggered :: JIRAWorkflowPostFunction -> URLBean
+ Data.Connect.Descriptor: jwpfView :: JIRAWorkflowPostFunction -> Maybe URLBean
+ Data.Connect.Descriptor: jwsConditions :: JIRAWebSection -> [Condition]
+ Data.Connect.Descriptor: jwsKey :: JIRAWebSection -> Text
+ Data.Connect.Descriptor: jwsLocation :: JIRAWebSection -> Text
+ Data.Connect.Descriptor: jwsName :: JIRAWebSection -> I18nText
+ Data.Connect.Descriptor: jwsParams :: JIRAWebSection -> ModuleParams
+ Data.Connect.Descriptor: jwsTooltip :: JIRAWebSection -> Maybe I18nText
+ Data.Connect.Descriptor: jwsWeight :: JIRAWebSection -> Maybe Weight
+ Data.Connect.Descriptor: kcExtractions :: KeyConfiguration -> [Extraction]
+ Data.Connect.Descriptor: kcPropertyKey :: KeyConfiguration -> Text
+ Data.Connect.Descriptor: noParams :: ModuleParams
+ Data.Connect.Descriptor: simpleText :: Text -> I18nText
+ Data.Connect.Descriptor: toUrl :: Text -> URLBean
+ Data.Connect.Descriptor: type ModuleParams = HashMap Text Text
+ Data.Connect.Descriptor: type Weight = Integer
+ Data.Connect.Descriptor: ubUrl :: URLBean -> Text
+ Data.Connect.Descriptor: wiConditions :: WebItem -> [Condition]
+ Data.Connect.Descriptor: wiContext :: WebItem -> Maybe WebItemContext
+ Data.Connect.Descriptor: wiIcon :: WebItem -> Maybe IconDetails
+ Data.Connect.Descriptor: wiKey :: WebItem -> Text
+ Data.Connect.Descriptor: wiLocation :: WebItem -> Text
+ Data.Connect.Descriptor: wiName :: WebItem -> I18nText
+ Data.Connect.Descriptor: wiParams :: WebItem -> ModuleParams
+ Data.Connect.Descriptor: wiStyleClasses :: WebItem -> [Text]
+ Data.Connect.Descriptor: wiTarget :: WebItem -> Maybe Target
+ Data.Connect.Descriptor: wiTooltip :: WebItem -> Maybe I18nText
+ Data.Connect.Descriptor: wiUrl :: WebItem -> Text
+ Data.Connect.Descriptor: wiWeight :: WebItem -> Maybe Weight
+ Data.Connect.Descriptor: wpParams :: WebPanel -> ModuleParams
+ Data.Connect.Descriptor: wpTooltip :: WebPanel -> Maybe I18nText
- Data.Connect.Descriptor: JIRAModules :: [WebPanel] -> [GeneralPage] -> [Webhook] -> [JIRAProjectAdminTabPanel] -> JIRAModules
+ Data.Connect.Descriptor: JIRAModules :: [JIRAWebSection] -> [WebItem] -> [WebPanel] -> [JIRAPage] -> [JIRAPage] -> Maybe JIRAPage -> [JIRASearchRequestView] -> [JIRAGenericTabPanel] -> [JIRAGenericTabPanel] -> [JIRAGenericTabPanel] -> [JIRAProjectAdminTabPanel] -> [JIRAGenericTabPanel] -> [JIRAGenericTabPanel] -> [JIRAReport] -> [Webhook] -> [JIRAWorkflowPostFunction] -> [JIRAEntityProperties] -> JIRAModules
- Data.Connect.Descriptor: JIRAProjectAdminTabPanel :: Text -> Name JIRAProjectAdminTabPanel -> Text -> Text -> [Condition] -> Maybe Integer -> JIRAProjectAdminTabPanel
+ Data.Connect.Descriptor: JIRAProjectAdminTabPanel :: Text -> I18nText -> Text -> Text -> [Condition] -> Maybe Weight -> ModuleParams -> JIRAProjectAdminTabPanel
- Data.Connect.Descriptor: WebPanel :: Text -> Name WebPanel -> Text -> Text -> [Condition] -> Maybe Integer -> Maybe WebPanelLayout -> WebPanel
+ Data.Connect.Descriptor: WebPanel :: Text -> I18nText -> Text -> Text -> [Condition] -> Maybe I18nText -> Maybe Weight -> Maybe WebPanelLayout -> ModuleParams -> WebPanel
- Data.Connect.Descriptor: jpatpName :: JIRAProjectAdminTabPanel -> Name JIRAProjectAdminTabPanel
+ Data.Connect.Descriptor: jpatpName :: JIRAProjectAdminTabPanel -> I18nText
- Data.Connect.Descriptor: jpatpWeight :: JIRAProjectAdminTabPanel -> Maybe Integer
+ Data.Connect.Descriptor: jpatpWeight :: JIRAProjectAdminTabPanel -> Maybe Weight
- Data.Connect.Descriptor: wpName :: WebPanel -> Name WebPanel
+ Data.Connect.Descriptor: wpName :: WebPanel -> I18nText
- Data.Connect.Descriptor: wpWeight :: WebPanel -> Maybe Integer
+ Data.Connect.Descriptor: wpWeight :: WebPanel -> Maybe Weight

Files

atlassian-connect-descriptor.cabal view
@@ -10,7 +10,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             0.2.0.1+version:             0.3.0.0  -- A short (one-line) description of the package. synopsis:            Code that helps you create a valid Atlassian Connect Descriptor.@@ -46,6 +46,10 @@ -- Constraint on the version of Cabal needed to build this package. cabal-version:       >=1.10 +source-repository head+  type:     git+  location: git@bitbucket.org:robertmassaioli/atlassian-connect-descriptor.git+ flag network-uri    description: Get Network.URI from the network-uri package    default: True@@ -119,6 +123,7 @@     , time-units     , cases     , unordered-containers+    , bytestring    if flag(network-uri)      build-depends: network-uri >= 2.6, network >= 2.6
src/Data/Connect/AesonHelpers.hs view
@@ -2,6 +2,7 @@    ( baseOptions    , stripFieldNamePrefix    , dropSuffixAndSnakeCase+   , lowerAll    ) where  import qualified Cases            as CS@@ -25,6 +26,9 @@ lowerFirst :: String -> String lowerFirst (x : xs) = C.toLower x : xs lowerFirst [] = []++lowerAll :: String -> String+lowerAll = fmap C.toLower  dropSuffix :: String -> String -> String dropSuffix suffix = reverse . try (L.stripPrefix . reverse $ suffix) . reverse
src/Data/Connect/BaseTypes.hs view
@@ -2,7 +2,22 @@ {-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings          #-}-module Data.Connect.BaseTypes where+module Data.Connect.BaseTypes+   ( Key(..)+   , PluginKey(..)+   , Timeout(..)+   , Vendor(..)+   , Authentication(..)+   , AuthType(..)+   , IconDetails(..)+   , Name(..)+   , I18nText(..)+   , simpleText+   , URLBean(..)+   , toUrl+   , Length(..)+   )+   where  import           Data.Aeson import           Data.Aeson.Types@@ -19,6 +34,8 @@ -- | This data type represents an Atlassian Connect Add-on key. data PluginKey = PluginKey Text deriving (Show, Eq, Generic) +instance ToJSON PluginKey+ -- | Represents a timeout in seconds. newtype Timeout = Timeout DTU.Second deriving (Show, Eq, Enum, Num, Ord, Real, Integral) @@ -47,12 +64,41 @@    , iconHeight :: Maybe Integer -- ^ The height of the icon.    } deriving (Show, Generic) -instance ToJSON PluginKey- -- | Atlassian Connect descriptors contain many names: module names, add-on names, vendor names etc. We want to make sure -- that these names don't get put in places that they do not belong. Or, if they do get moved around, they get moved around -- specifically. We are just adding type saefty to names. data Name a = Name Text deriving (Show, Eq, Generic)++-- | Represents a standard text type in the descriptor than may be Internationalised in the future. However, currently+-- there is no I18n support: <http://goo.gl/9vJEsW>+data I18nText = I18nText+   { dValue :: Text -- ^ The raw text value that will show.+   , dI18n  :: Maybe Text -- ^ The potential i18n key that will be used when we eventually have I18n support: <http://goo.gl/9vJEsW>+   } deriving (Show, Generic)++instance ToJSON I18nText where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "d"+      }++-- | Since there is currently no I18n support (<http://goo.gl/9vJEsW>) we have this helper method to quickly create an 'I18nText' from a standard+-- 'Text' object.+simpleText :: Text -> I18nText+simpleText t = I18nText { dValue = t, dI18n = Nothing }++-- | This represents a URL wrapped as an object instead of as a plain text element.+data URLBean = URLBean+   { ubUrl :: Text -- ^ The raw URL.+   } deriving (Show, Generic)++instance ToJSON URLBean where+   toJSON = genericToJSON baseOptions+         { fieldLabelModifier = stripFieldNamePrefix "ub"+         }++-- | Wrap a regular 'Text' based URL inside a URLBean.+toUrl :: Text -> URLBean+toUrl = URLBean  instance ToJSON (Name PluginKey) instance ToJSON (Name Vendor)
src/Data/Connect/Descriptor.hs view
@@ -31,7 +31,7 @@ >     , lifecycle = Just defaultLifecycle >     , modules = Just exampleModules >     , enableLicensing = Just False->     , links = fromList+>     , links = HM.fromList >         [ ("documentation", toURI "http://awesome-devs.com/docs") >         , ("source", toURI "http://bitbucket.org/awesome-devs/connect-addon") >         ]@@ -43,31 +43,36 @@ > > exampleJIRAModules :: JIRAModules > exampleJIRAModules = emptyJIRAModules->     { jiraWebPanels =+>     { jmWebPanels = >         [ WebPanel >             { wpKey = "test-web-panel"->             , wpName = Name "Test Web Panel"+>             , wpName = simpleText "Test Web Panel"+>             , wpTooltip = Just $ simpleText "This is a test web panel..." >             , wpLocation = "some-location-in-jira" >             , wpUrl = "/panel/location/for" >             , wpConditions = [staticJiraCondition UserIsAdminJiraCondition]+>             , wpWeight = Nothing+>             , wpLayout = Nothing+>             , wpParams = noParams >             } >         ]->     , jiraGeneralPages =->         [ GeneralPage->             { generalPageKey = "test-general-page"->             , generalPageName = Name "Test General Page"->             , generalPageLocation = Just "some-other-location-in-jira"->             , generalPageWeight = Just 1234->             , generalPageUrl = "/panel/general-page"->             , generalPageIcon = Just IconDetails+>     , jmGeneralPages =+>         [ JIRAPage+>             { jiraPageKey = "test-general-page"+>             , jiraPageName = simpleText "Test General Page"+>             , jiraPageLocation = Just "some-other-location-in-jira"+>             , jiraPageWeight = Just 1234+>             , jiraPageUrl = "/panel/general-page"+>             , jiraPageIcon = Just IconDetails >                 { iconUrl = "/static/path/to/icon.png" >                 , iconWidth = Just 20 >                 , iconHeight = Just 40 >                 }->             , generalPageConditions = [staticJiraCondition UserHasIssueHistoryJiraCondition]+>             , jiraPageConditions = [staticJiraCondition UserHasIssueHistoryJiraCondition]+>             , jiraPageParams = noParams >             } >         ]->     , jiraWebhooks =+>     , jmWebhooks = >         [ Webhook >             { webhookEvent = JiraIssueDeleted >             , webhookUrl = "/webhook/handle-deletion"@@ -84,17 +89,22 @@      Plugin(..)    , pluginDescriptor    -- * Basic Types-   , Name(..)    , Key(..)    , PluginKey(..)    , Timeout(..)-   , IconDetails(..)-   , Length(..)-   -- * Authentication+   , Vendor(..)    , Authentication(..)    , AuthType(..)-   -- * Vendor Details-   , Vendor(..)+   , IconDetails(..)+   , Name(..)+   , I18nText(..)+   , simpleText+   , URLBean(..)+   , toUrl+   , Length(..)+   , Weight+   , ModuleParams+   , noParams    -- * Lifecycle    , Lifecycle(..)    , emptyLifecycle@@ -105,10 +115,28 @@    , emptyJIRAModules    , ConfluenceModules(..)    , emptyConfluenceModules+   -- ** Web Sections, Items and Panels+   , JIRAWebSection(..)+   , WebItem(..)    , WebPanel(..)    , WebPanelLayout(..)-   , GeneralPage(..)+   -- ** JIRA Pages+   , JIRAPage(..)+   -- ** JIRA Tab Panels+   , JIRAGenericTabPanel(..)    , JIRAProjectAdminTabPanel(..)+   -- ** JIRA Specific Modules+   , JIRASearchRequestView(..)+   , JIRAReport(..)+   , Target(..)+   , JIRAWorkflowPostFunction(..)+   , DialogOptions(..)+   , InlineDialogOptions(..)+   , JIRAEntityProperties(..)+   , EntityType(..)+   , KeyConfiguration(..)+   , Extraction(..)+   , ExtractionType(..)    -- ** Webhooks    , Webhook(..)    , WebhookEvent(..)
src/Data/Connect/Modules.hs view
@@ -6,12 +6,59 @@    , emptyJIRAModules    , ConfluenceModules(..)    , emptyConfluenceModules+   , JIRAWebSection(..)+   , WebItem(..)    , WebPanel(..)    , WebPanelLayout(..)-   , GeneralPage(..)+   , JIRAPage(..)+   , JIRAGenericTabPanel(..)    , JIRAProjectAdminTabPanel(..)+   , JIRASearchRequestView(..)+   , JIRAReport(..)+   , Target(..)+   , JIRAWorkflowPostFunction(..)+   , DialogOptions(..)+   , InlineDialogOptions(..)+   , JIRAEntityProperties(..)+   , EntityType(..)+   , KeyConfiguration(..)+   , Extraction(..)+   , ExtractionType(..)+   , ModuleParams+   , noParams+   , Weight    ) where +{-+Supported JIRA Modules++webSections+webItems+webPanels++generalPages+adminPages+configurePage++jiraProfileTabPanels+jiraVersionTabPanels+jiraProjectTabPanels+jiraProjectAdminTabPanels+jiraIssueTabPanels+jiraComponentTabPanels++jiraSearchRequestViews++jiraReports++webhooks++jiraWorkflowPostFunctions++jiraEntityProperties++-}+ import           Data.Aeson import           Data.Aeson.Types import           Data.Connect.AesonHelpers@@ -51,15 +98,28 @@ -- | A collection of all of the JIRA Modules that you can define. For more documentation on which Modules are supported -- the Atlassian Connect framework please see 'Modules'. You can also find more documentation on each of the modules. data JIRAModules = JIRAModules-   { jiraWebPanels                 :: [WebPanel]-   , jiraGeneralPages              :: [GeneralPage]-   , jiraWebhooks                  :: [Webhook]-   , jiraJiraProjectAdminTabPanels :: [JIRAProjectAdminTabPanel]+   { jmWebSections               :: [JIRAWebSection]+   , jmWebItems                  :: [WebItem]+   , jmWebPanels                 :: [WebPanel]+   , jmGeneralPages              :: [JIRAPage]+   , jmAdminPages                :: [JIRAPage]+   , jmConfigurePage             :: Maybe JIRAPage+   , jmJiraSearchRequestViews    :: [JIRASearchRequestView]+   , jmJiraProfileTabPanels      :: [JIRAGenericTabPanel]+   , jmJiraVersionTabPanels      :: [JIRAGenericTabPanel]+   , jmJiraProjectTabPanels      :: [JIRAGenericTabPanel]+   , jmJiraProjectAdminTabPanels :: [JIRAProjectAdminTabPanel]+   , jmJiraIssueTabPanels        :: [JIRAGenericTabPanel]+   , jmJiraComponentTabPanels    :: [JIRAGenericTabPanel]+   , jmJiraReports               :: [JIRAReport]+   , jmWebhooks                  :: [Webhook]+   , jmJiraWorkflowPostFunctions :: [JIRAWorkflowPostFunction]+   , jmJiraEntityProperties      :: [JIRAEntityProperties]    } deriving (Show, Generic)  instance ToJSON JIRAModules where    toJSON = genericToJSON baseOptions-      { fieldLabelModifier = stripFieldNamePrefix "jira"+      { fieldLabelModifier = stripFieldNamePrefix "jm"       }  -- | A collection of all of the Confluence Modules that you can define. For more documentation on which Modules are supported@@ -75,12 +135,42 @@  -- | Empty JIRA Modules; useful when you only want to define a few modules via Haskell record syntax. emptyJIRAModules :: JIRAModules-emptyJIRAModules = JIRAModules [] [] [] []+emptyJIRAModules = JIRAModules [] [] [] [] [] Nothing [] [] [] [] [] [] [] [] [] [] []  -- | Empty Confluence Modules; useful when you only want to define a few modules via Haskell record syntax. emptyConfluenceModules :: ConfluenceModules emptyConfluenceModules = ConfluenceModules [] +-- | Represents the weight of an element in a menu.+type Weight = Integer++-- | The standard representation for module parameters.+type ModuleParams = HM.HashMap T.Text T.Text++-- | No parameters. A useful helper when you don't want to pass any parameters to a module.+noParams :: ModuleParams+noParams = HM.empty++-- | A 'JIRAWebSection' represents a location in the host application that you can add 'WebItem's to. In this way you+-- can give your add-on sections to inject content into.+--+-- For more information read the Atlassian Connect documentation:+-- <https://developer.atlassian.com/static/connect/docs/modules/jira/web-section.html>+data JIRAWebSection = JIRAWebSection+   { jwsKey        :: T.Text -- ^ The add-on unique key for this module.+   , jwsName       :: I18nText -- ^ The name of this section, likely to appear in the User Interface.+   , jwsLocation   :: T.Text -- ^ The location in the application interface where the web section should appear.+   , jwsTooltip    :: Maybe I18nText -- ^ The internationalised text to be used in the link's tooltip.+   , jwsConditions :: [Condition] -- ^ The conditions under which to show this web section.+   , jwsWeight     :: Maybe Weight -- ^ The higher the weight the lower down the menu it will appear.+   , jwsParams     :: ModuleParams -- ^ Optional parameters to pass to the web section.+   } deriving (Show, Generic)++instance ToJSON JIRAWebSection where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "tt"+      }+ -- | A 'WebPanel' is an injectable segment of the host application that you can place content inside. Currently the -- WebPanel has the same structure for both JIRA and Confluence but, potentially, that could change in the future. -- You can read their Atlassian Connect documentation here:@@ -103,12 +193,14 @@ -- WebPanels are a great way to inject your add-on's content into the host application. data WebPanel = WebPanel    { wpKey        :: T.Text -- ^ The add-on unique key for this module.-   , wpName       :: Name WebPanel -- ^ The name of this panel, likely to appear in the User Interface.+   , wpName       :: I18nText -- ^ The name of this panel, likely to appear in the User Interface.    , wpUrl        :: T.Text -- ^ The relative URI that the host product will hit to get HTML content.    , wpLocation   :: T.Text -- ^ The location that this content should be injected in the host product.    , wpConditions :: [Condition] -- ^ The 'Condition's that need to be met for this module to be displayed.-   , wpWeight     :: Maybe Integer-   , wpLayout     :: Maybe WebPanelLayout+   , wpTooltip    :: Maybe I18nText -- ^ A tooltip that explains what this is for.+   , wpWeight     :: Maybe Weight -- ^ Web panels can be ordered and a higher weight makes you appear lower down the page.+   , wpLayout     :: Maybe WebPanelLayout -- ^ You can specify the dimensions of this panel. This will only be considered in certain locations.+   , wpParams     :: ModuleParams -- ^ You can pass parameters to the web panel.    } deriving (Show, Generic)  instance ToJSON WebPanel where@@ -127,40 +219,130 @@       { fieldLabelModifier = stripFieldNamePrefix "wpl"       } -{-+-- | A 'WebItem' is a like that can be placed in one of an Atlassian Products many menus. Currently the WebItem has the+-- same structure for both JIRA and Confluence. You can read their documentation here:+--+-- * JIRA Web Items: <https://developer.atlassian.com/static/connect/docs/modules/jira/web-item.html>+-- * Confluence Web Items: <https://developer.atlassian.com/static/connect/docs/modules/confluence/web-item.html>+--+-- Web items are very useful for providing links to your Atlassian Connect pages. See 'GeneralPage' or 'AdminPage' for+-- more information. data WebItem = WebItem-   { wiName         :: Name WebItem-   , wiKey          :: T.Text-   -- TODO add tooltip support-   , wiLocation     :: T.Text-   , wiUrl          :: T.Text-   , wiConditions   :: [Condition]-   , wiContext      :: Maybe WebItemContext-   , wiIcon         :: Maybe IconDetails-   , wiStyleClasses :: [String]+   { wiKey          :: T.Text -- ^ The add-on unique key for this module.+   , wiName         :: I18nText -- ^ The name of this web item. It will appear as the text of the link.+   , wiLocation     :: T.Text -- ^ Where in the product UI this web item will appear.+   , wiUrl          :: T.Text -- ^ The URL to direct the user to. May be relative to the host Product or the Addon depending on the context.+   , wiTooltip      :: Maybe I18nText -- ^ An optional tooltip for the link.+   , wiIcon         :: Maybe IconDetails -- ^ An optional icon to display with the link text or as the link+   , wiWeight       :: Maybe Weight -- ^ The higher the weight the lower down in the location menu this web item will appear.+   , wiTarget       :: Maybe Target -- ^ Determines the way the link is opened. In the page, in a dialog or in an inline dialog.+   , wiStyleClasses :: [T.Text] -- ^ Specifies custom styles for the web item target page+   , wiContext      :: Maybe WebItemContext -- ^ Determines if the url is relative to the page, product or connect addon.+   , wiConditions   :: [Condition] -- ^ Determines the conditions under which to show this link.+   , wiParams       :: ModuleParams -- ^ Optional parameters that you can pass to the web item.    } deriving (Show, Generic) +instance ToJSON WebItem where+   toJSON = genericToJSON baseOptions+         { fieldLabelModifier = lowerAll . stripFieldNamePrefix "wi"+         }++-- | A 'Target' represents the location that a link will be opened into.+data Target+   = TargetPage -- ^ Open the link into the current page.+   | TargetDialog (Maybe DialogOptions) -- ^ Open the link into a dialog on the page with the given options.+   | TargetInlineDialog (Maybe InlineDialogOptions) -- ^ Open the link into an inline dialog with the given options.+   deriving (Show)++tp :: String -> T.Text+tp = T.pack++instance ToJSON Target where+   toJSON (TargetPage) = object [tp "type" .= tp "page"]+   toJSON (TargetDialog potentialOptions) = object $ tp "type" .= tp "dialog" :+      case potentialOptions of+         Just options -> [tp "options" .= toJSON options]+         Nothing -> []+   toJSON (TargetInlineDialog potentialOptions) = object $ tp "type" .= tp "inlinedialog" :+      case potentialOptions of+               Just options -> [tp "options" .= toJSON options]+               Nothing -> []++-- | Options for a dialog that a link may be opened into.+data DialogOptions = DialogOptions+   { doHeight :: Maybe Integer -- ^ The height of the dialog on the page.+   , doWidth  :: Maybe Integer -- ^ The width of the dialog on the page.+   , doChrome :: Maybe Bool -- ^ Whether the dialog should contain the AUI header and buttons. Default is true+   } deriving (Show, Generic)++instance ToJSON DialogOptions where+   toJSON = genericToJSON baseOptions+         { fieldLabelModifier = lowerAll . stripFieldNamePrefix "do"+         }++-- | Options for an inline dialog that a link may be opened into.+data InlineDialogOptions = InlineDialogOptions+   { idoWidth             :: Maybe T.Text -- ^ Sets how wide the inline-dialog is in pixels+   , idoOnTop             :: Maybe Bool -- ^ Determines if the dialog should be shown above the trigger or not+   , idoIsRelativeToMouse :: Maybe Bool -- ^ Determines if the dialog should be shown relative to where the mouse is at the time of the event trigger+   , idoShowDelay         :: Maybe Integer -- ^ Determines how long in milliseconds after a show trigger is fired until the dialog is shown+   , idoOnHover           :: Maybe Bool -- ^ Determines whether the inline-Dialog will show on a mouseOver or mouseClick of the trigger+   , idoOffsetX           :: Maybe T.Text -- ^ Sets an offset distance of the inline-dialog from the trigger element along the x-axis in pixels+   , idoOffsetY           :: Maybe T.Text -- ^ Sets an offset distance of the inline-dialog from the trigger element along the y-axis in pixels+   , idoPersistent        :: Maybe Bool -- ^ This option, ignores the 'closeOthers' option+   , idoCloseOthers       :: Maybe Bool -- ^ Cetermines if all other dialogs on the screen are closed when this one is opened+   } deriving (Show, Generic)++instance ToJSON InlineDialogOptions where+   toJSON = genericToJSON baseOptions+         { fieldLabelModifier = lowerAll . stripFieldNamePrefix "ido"+         }++-- TODO this cannot have a generic implimentation++-- | Wether to open the url relative to the current page, the current addon or the current product. This lets you control+-- where Atlassian Connect web items point to. data WebItemContext = PageContext | AddonContext | ProductContext    deriving(Show, Generic)  instance ToJSON WebItemContext where-   toJSON PageContext = String . T.pack $ "page"-   toJSON AddonContext = String . T.pack $ "addon"-   toJSON ProductContext = String . T.pack $ "product"--}+   toJSON PageContext = stj "page"+   toJSON AddonContext = stj "addon"+   toJSON ProductContext = stj "product" +stj :: String -> Value+stj = String . T.pack++-- | JIRA has the concept of a TabPanel which is a panel where you can inject content along with a 'WebItem' that is+-- automatically created for you so that you can navigate to the tab panel in question. Tab panels often have a common format+-- and this 'JIRAGenericTabPanel' encapsulates that common format and allows you to apply it to many different scenarios.+data JIRAGenericTabPanel = JIRAGenericTabPanel+   { jtpKey        :: T.Text -- ^ The add-on unique key for this module.+   , jtpName       :: I18nText -- ^ The user facing name of this panel. Likely to appear as the name of the link to the tab panel.+   , jtpUrl        :: T.Text -- ^ The URL to your addon where you will provide the content for the panel.+   , jtpConditions :: [Condition] -- ^ The conditions under which this tapb panel should be displayed.+   , jtpWeight     :: Maybe Weight -- ^ The higher the weight the lower down in the list of tabs the link to this tab panel will be displayed.+   , jtpParams     :: ModuleParams -- ^ Optional parameters for the tab panel.+   } deriving (Show, Generic)++instance ToJSON JIRAGenericTabPanel where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "jtp"+      }+ -- TODO update the docs for the JIRAProjectAdminTabPanel based on this question: http://goo.gl/c6QUdd  -- | A 'JIRAProjectAdminTabPanel' is useful for when you want to add a page to the administration screens of a project. -- This module will create a web item in the sidebar of every project for you and provide a web panel in the JIRA Project -- Admin section. data JIRAProjectAdminTabPanel = JIRAProjectAdminTabPanel-   { jpatpKey        :: T.Text-   , jpatpName       :: Name JIRAProjectAdminTabPanel-   , jpatpUrl        :: T.Text-   , jpatpLocation   :: T.Text-   , jpatpConditions :: [Condition]-   , jpatpWeight     :: Maybe Integer+   { jpatpKey        :: T.Text -- ^ The add-on unique key for this module.+   , jpatpName       :: I18nText -- ^ The user facing name of this panel. Likely to appear as the name of the link to the tab panel.+   , jpatpUrl        :: T.Text -- ^ The URL to your addon where you will provide the content for the panel.+   , jpatpLocation   :: T.Text -- ^ The location in JIRA Admin that you wish the link to this panel to appear.+   , jpatpConditions :: [Condition] -- ^ The conditions under which this panel should be displayed. UserIsAdminCondition is redundant.+   , jpatpWeight     :: Maybe Weight -- ^ The higher the weight the lower down in the list of tabs the link to this tab panel will be displayed.+   , jpatpParams     :: ModuleParams -- ^ Optional parameters for the tab panel.    } deriving (Show, Generic)  instance ToJSON JIRAProjectAdminTabPanel where@@ -168,41 +350,185 @@       { fieldLabelModifier = stripFieldNamePrefix "jpatp"       } -instance ToJSON (Name JIRAProjectAdminTabPanel) where-   toJSON = nameToValue---- | A 'GeneralPage' makes your add-on take a large section of screen realestate, with the intention of displaying--- your own page with no other distracting content. This is very useful for pages like Configuration screens or--- Statistics pages where you really want the user to be fully working with your add-on inside the host product.+-- | A 'JIRAPage' is gives you a location in the host product that you addon can present content and behave just like any+-- other host product page. The main types of pages in JIRA are: --+-- * General pages: for just getting a geniric chunk of realestate to display your content.+-- * Admin pages: for getting a page in the admin seciton of JIRA to display your content.+-- * Configuration page: Every Atlassian Connect plugin can have a configuration page to configure the plugin when installed.+--+-- This is very useful for pages like Configuration screens or Statistics pages where you really want the user to be+-- immersed in working with your add-on inside the host product.+-- -- General pages, like Web Panels, are common to JIRA and Confluence and share the same json format. However they have -- separate documentation: -- -- * JIRA General Page: <https://developer.atlassian.com/static/connect/docs/modules/jira/general-page.html> -- * Confluence General Page: <https://developer.atlassian.com/static/connect/docs/modules/confluence/general-page.html> ----- Even though, at this point in time, the documentation looks identical.-data GeneralPage = GeneralPage-   { generalPageKey        :: T.Text -- ^ The add-on unique key for this module.-   , generalPageName       :: Name GeneralPage -- ^ The name of this General Page. Likely to be used in the page title.-   , generalPageUrl        :: T.Text -- ^ The relative URI that the host product will hit to get the HTML content for the page.-   , generalPageLocation   :: Maybe T.Text -- ^ The location for this General Page to display; see the docs for your options.-   , generalPageIcon       :: Maybe IconDetails -- ^ The optional icon to use for this general page.-   , generalPageWeight     :: Maybe Integer -- ^ Determines the order that this item appears in any menu or list.-                                            -- Lower numbers mean that it will appear higher in the list.-   , generalPageConditions :: [Condition] -- ^ The 'Condition's that need to be met for this module to be displayed.+-- Even though, at this point in time, the documentation looks identical. You can find the Admin page and Configure page+-- documentation in the official Atlassian Connect documentation too.+data JIRAPage = JIRAPage+   { jiraPageKey        :: T.Text -- ^ The add-on unique key for this module.+   , jiraPageName       :: I18nText -- ^ The name of this JIRA page. Likely to be used in the page title.+   , jiraPageUrl        :: T.Text -- ^ The relative URI that the host product will hit to get the HTML content for the page.+   , jiraPageLocation   :: Maybe T.Text -- ^ The location for this General Page to display; see the docs for your options.+   , jiraPageWeight     :: Maybe Weight -- ^ Determines the order that this item appears in any menu or list.+                                        -- Lower numbers mean that it will appear higher in the list.+   , jiraPageIcon       :: Maybe IconDetails -- ^ The optional icon to use for this JIRA page.+   , jiraPageConditions :: [Condition] -- ^ The 'Condition's that need to be met for this page to be displayed.+   , jiraPageParams     :: ModuleParams -- ^ Optional parameters for the page.    } deriving (Show, Generic) -instance ToJSON GeneralPage where+instance ToJSON JIRAPage where    toJSON = genericToJSON baseOptions-      { fieldLabelModifier = stripFieldNamePrefix "generalPage"+      { fieldLabelModifier = stripFieldNamePrefix "jiraPage"       } -instance ToJSON (Name WebPanel) where-   toJSON = nameToValue+-- |  A Search Request View allows you to render a custom representation of a search result. Rendering a custom XML+-- format is a common example.+--+-- For more information read the Atlassian Connect documentation:+-- <https://developer.atlassian.com/static/connect/docs/modules/jira/search-request-view.html>+data JIRASearchRequestView = JIRASearchRequestView+   { jsrvKey         :: T.Text -- ^ The add-on unique key for this module.+   , jsrvName        :: I18nText -- ^ The name of this Search Request View. Will appear in the Export menu.+   , jsrvUrl         :: T.Text -- ^ This URL will render the search results.+   , jsrvDescription :: Maybe I18nText -- ^ The description of this view.+   , jsrvWeight      :: Maybe Weight -- ^ A higher weight puts the link further down the export menu.+   , jsrvConditions  :: [Condition] -- ^ The conditions under which this option should show.+   , jsrvParams      :: ModuleParams -- ^ The optional parameters to this search request view.+   } deriving (Show, Generic) -instance ToJSON (Name GeneralPage) where-   toJSON = nameToValue+instance ToJSON JIRASearchRequestView where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "jsrv"+      } -nameToValue :: Name a -> Value-nameToValue (Name name) = object [ T.pack "value" .= name ]+-- | A 'JIRAReport' will provide a report on the JIRA issues in the project. It allows you to write custom reporting+-- for JIRA.+--+-- For more information read the Atlassian Connect documentation:+-- <https://developer.atlassian.com/static/connect/docs/modules/jira/report.html>+data JIRAReport = JIRAReport+   { jrKey            :: T.Text -- ^ The add-on unique key for this module.+   , jrName           :: I18nText -- ^ The user facing name of this report.+   , jrUrl            :: T.Text -- ^ The URL that will render the report back to the user.+   , jrDescription    :: I18nText -- ^ The required user facing description of this report.+   , jrReportCategory :: Maybe JIRAReportCategory -- ^ The category that this report should be placed inside.+   , jrWeight         :: Maybe Weight -- ^ A higher weight will push this report further down the list of reports.+   , jrThumbnailUrl   :: Maybe T.Text -- ^ A thumbnail that gives a gist of what this report is supposed to accomplish.+   } deriving (Show, Generic)++instance ToJSON JIRAReport where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "jr"+      }++-- | The report category for a 'JIRAReport'. Useful in organising the different types of reports.+data JIRAReportCategory+   = AgileRC -- ^ This report is visible to agile customers.+   | IssueAnalysisRC -- ^ This report does issue analysis.+   | ForecastManagementRC -- ^ This report considers future of the project state.+   | OtherRC -- ^ Any report that does not fit into the other categories goes here.+   deriving (Show)++instance ToJSON JIRAReportCategory where+   toJSON AgileRC = stj "agile"+   toJSON IssueAnalysisRC = stj "issue_analysis"+   toJSON ForecastManagementRC = stj "forecast_management"+   toJSON OtherRC = stj "other"++-- | A 'JIRAWorkflowPostFunction' carries out any additional processing required after a JIRA workflow transition is executed.+--+-- For more information read the Atlassian Connect documentation:+-- <https://developer.atlassian.com/static/connect/docs/modules/jira/workflow-post-function.html>+--+-- Or you could read the JIRA documentation on Workflow Post Functions to learn more:+-- <https://confluence.atlassian.com/display/Cloud/Advanced+Workflow+Configuration#AdvancedWorkflowConfiguration-postfunctions>+data JIRAWorkflowPostFunction = JIRAWorkflowPostFunction+   { jwpfKey         :: T.Text -- ^ The add-on unique key for this module.+   , jwpfName        :: I18nText -- ^ The user facing name of this workflow post function.+   , jwpfTriggered   :: URLBean -- ^ The add-on URL to hit when the post function is triggered. The URL will be POST'ed+                                -- to and you should read the Atlassian Connect docs for more details.+   , jwpfDescription :: Maybe I18nText -- ^ The user facing description of this post function.+   , jwpfCreate      :: Maybe URLBean -- ^ The add-on URL to the configuration page for the post function when it is created.+   , jwpfEdit        :: Maybe URLBean -- ^ The add-on URL to the configuration edit page of the post function.+   , jwpfView        :: Maybe URLBean -- ^ The add-on URL to the view page for the read-only view of the configuration.+   } deriving (Show, Generic)++instance ToJSON JIRAWorkflowPostFunction where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "jwpf"+      }++-- | 'JIRAEntityProperties' are used to set Key / Value pair information on JIRA Issues that can be searched via JQL and+-- are indexed by JIRA. The can also be accessed directly via rest api so they allow you to store data in client-only+-- Atlassian Connect plugins. Very handy!+--+-- The data stored as entity properties is in the JSON data format so multiple values can be stored against the one property.+--+-- For more information read the JIRA Documentation on the topic:+-- <https://developer.atlassian.com/display/JIRADEV/JIRA+Entity+Properties+Overview>+--+-- Or read the Atlassian Connect documentation on the topic:+-- <https://developer.atlassian.com/static/connect/docs/modules/jira/entity-property.html>+data JIRAEntityProperties = JIRAEntityProperties+   { jepKey               :: T.Text -- ^ The add-on unique key for this module.+   , jepName              :: I18nText -- ^ The user facing name of this entity property.+   , jepEntityType        :: Maybe EntityType -- ^ The entity type that you want to attach this property to. Issue by default.+   , jepKeyConfigurations :: [KeyConfiguration] -- ^ The list of key configurations that you wish to define.+   } deriving (Show, Generic)++instance ToJSON JIRAEntityProperties where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "jep"+      }++-- | An 'EntityType' represents the type of entity that the JIRA Entity Property should be attatched to. By default+-- entity types are attatched to issues.+data EntityType = IssueEntityType+   deriving (Show)++instance ToJSON EntityType where+   toJSON IssueEntityType = stj "issue"++-- | A 'KeyConfiguration' is the key for this particular property and the JSON flattened paths to the elements that+-- should be extracted from this property. For more information see the Atlassian Connect documentation:+-- <https://developer.atlassian.com/static/connect/docs/modules/fragment/index-key-configuration.html>+data KeyConfiguration = KeyConfiguration+   { kcPropertyKey :: T.Text -- ^ The name of the JIRA Entity Property+   , kcExtractions :: [Extraction] -- ^ All of the data extractions from the property that should be indexed.+   } deriving (Show, Generic)++instance ToJSON KeyConfiguration where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "kc"+      }++-- | An 'Extraction' represents a snippet of data that should be extracted from a 'KeyConfiguration' such that it is+-- Indexed by JIRA and capable of being searched in JQL.+data Extraction = Extraction+   { extractionObjectName :: T.Text+   , extractionType       :: ExtractionType+   } deriving (Show, Generic)++instance ToJSON Extraction where+   toJSON = genericToJSON baseOptions+      { fieldLabelModifier = stripFieldNamePrefix "extraction"+      }++-- | The style in which the data should be extracted and indexed. For example, you may want the data to be treated as a+-- Date or as a Number.+data ExtractionType+   = ExtractionTypeNumber -- ^ Index the data as a numeric type.+   | ExtractionTypeText -- ^ Index the data as a text based type, with words.+   | ExtractionTypeString -- ^ Index the data as an exact string.+   | ExtractionTypeDate -- ^ Index the data as a Date.+   deriving(Show)++instance ToJSON ExtractionType where+   toJSON ExtractionTypeNumber = stj "number"+   toJSON ExtractionTypeText = stj "text"+   toJSON ExtractionTypeString = stj "string"+   toJSON ExtractionTypeDate = stj "date"
tests/DescriptorTest.hs view
@@ -5,12 +5,13 @@ import           Control.Applicative import           Data.Aeson import           Data.Connect.Descriptor-import           Data.HashMap.Strict+import qualified Data.HashMap.Strict     as HM import           Data.Maybe              (fromJust) import qualified Data.Text               as T import           Network.URI import           Test.HUnit import           ValueExtractors+import qualified Data.ByteString.Lazy.Char8 as BLC  toURI :: String -> URI toURI = fromJust . parseURI@@ -26,7 +27,7 @@     , lifecycle = Just defaultLifecycle     , modules = Just exampleModules1     , enableLicensing = Just False-    , links = fromList+    , links = HM.fromList         [ ("documentation", toURI "http://awesome-devs.com/docs")         , ("source", toURI "http://bitbucket.org/awesome-devs/connect-addon")         ]@@ -38,31 +39,36 @@  exampleJIRAModules :: JIRAModules exampleJIRAModules = emptyJIRAModules-    { jiraWebPanels =+    { jmWebPanels =         [ WebPanel             { wpKey = "test-web-panel"-            , wpName = Name "Test Web Panel"+            , wpName = simpleText "Test Web Panel"             , wpLocation = "some-location-in-jira"             , wpUrl = "/panel/location/for"             , wpConditions = [staticJiraCondition UserIsAdminJiraCondition]+            , wpParams = HM.singleton "single" "ton"+            , wpTooltip = Just . simpleText $ "A random tooltip here."+            , wpWeight = Just 2468+            , wpLayout = Just $ WebPanelLayout (Pixels 963) (Percentage 40)             }         ]-    , jiraGeneralPages =-        [ GeneralPage-            { generalPageKey = "test-general-page"-            , generalPageName = Name "Test General Page"-            , generalPageLocation = Just "some-other-location-in-jira"-            , generalPageWeight = Just 1234-            , generalPageUrl = "/panel/general-page"-            , generalPageIcon = Just IconDetails+    , jmGeneralPages =+        [ JIRAPage+            { jiraPageKey = "test-general-page"+            , jiraPageName = simpleText "Test General Page"+            , jiraPageLocation = Just "some-other-location-in-jira"+            , jiraPageWeight = Just 1234+            , jiraPageUrl = "/panel/general-page"+            , jiraPageIcon = Just IconDetails                 { iconUrl = "/static/path/to/icon.png"                 , iconWidth = Just 20                 , iconHeight = Just 40                 }-            , generalPageConditions = [staticJiraCondition UserHasIssueHistoryJiraCondition]+            , jiraPageConditions = [staticJiraCondition UserHasIssueHistoryJiraCondition]+            , jiraPageParams = HM.empty             }         ]-    , jiraWebhooks =+    , jmWebhooks =         [ Webhook             { webhookEvent = JiraIssueDeleted             , webhookUrl = "/webhook/handle-deletion"@@ -78,6 +84,7 @@ basicDescriptorTest :: Test basicDescriptorTest = TestCase $ do     let jv = toJSON exampleDescriptor1+    BLC.putStrLn . encode $ exampleDescriptor1     isObject jv @? "Expect the descriptor to be one big json object."     (getString =<< get "key" jv) `isEqualTo` "my-example-connect"     (getString =<< get "baseUrl" jv) `isEqualTo` (T.pack . show $ baseURL)
tests/ModulesTest.hs view
@@ -8,6 +8,7 @@ import           Data.Connect.Conditions (JIRACondition (..),                                           staticJiraCondition) import           Data.Connect.Modules+import qualified Data.HashMap.Strict     as HM import           Test.HUnit import           ValueExtractors @@ -22,10 +23,14 @@ testWebPanelCorrectFormat = TestCase $ do     let wp = WebPanel               { wpKey = "web-panel-key"-              , wpName = Name "My web panel"+              , wpName = simpleText "My web panel"               , wpUrl = "/panel/my-panel?issue_key={issue.key}"               , wpLocation = "atl.jira.view.issue.right.context"               , wpConditions = [staticJiraCondition UserIsAdminJiraCondition]+              , wpTooltip = Just . simpleText $ "A tooltip for the web panel..."+              , wpWeight = Just 1234+              , wpLayout = Just $ WebPanelLayout (Pixels 321) (Percentage 80)+              , wpParams = HM.fromList [("one", "1"), ("two", "2")]               }     let jv = toJSON wp     isObject jv @? "Expected the web panel to be an object"@@ -37,14 +42,15 @@  testGeneralPageCorrectFormat :: Test testGeneralPageCorrectFormat = TestCase $ do-    let gp = GeneralPage-              { generalPageKey = "general-page-key"-              , generalPageName = Name "General Page Name"-              , generalPageUrl = "/panel/page-panel-name?page_id={page.id}"-              , generalPageLocation = Just "some-confluence-location"-              , generalPageIcon = Just $ IconDetails "/path/to/icon" (Just 10) (Just 20)-              , generalPageWeight = Just 10000-              , generalPageConditions = [staticJiraCondition IsIssueReportedByCurrentUserJiraCondition]+    let gp = JIRAPage+              { jiraPageKey = "general-page-key"+              , jiraPageName = simpleText "General Page Name"+              , jiraPageUrl = "/panel/page-panel-name?page_id={page.id}"+              , jiraPageLocation = Just "some-confluence-location"+              , jiraPageIcon = Just $ IconDetails "/path/to/icon" (Just 10) (Just 20)+              , jiraPageWeight = Just 10000+              , jiraPageConditions = [staticJiraCondition IsIssueReportedByCurrentUserJiraCondition]+              , jiraPageParams = HM.fromList [("gpOne", "gp1"), ("gpTwo", "gp2")]               }     let jv = toJSON gp     isObject jv @? "Expected the web panel to be an object"