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 +6/−1
- src/Data/Connect/AesonHelpers.hs +4/−0
- src/Data/Connect/BaseTypes.hs +49/−3
- src/Data/Connect/Descriptor.hs +48/−20
- src/Data/Connect/Modules.hs +380/−54
- tests/DescriptorTest.hs +21/−14
- tests/ModulesTest.hs +15/−9
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"