जिरा के लिए स्ट्रक्चर प्लगइन कार्यों और उनके विश्लेषण के साथ रोजमर्रा के काम के लिए बहुत उपयोगी है; यह जीरा टिकटों के विज़ुअलाइज़ेशन और संरचना को एक नए स्तर पर ले जाता है, और यह सब सीधे तौर पर करता है।
और, हर कोई इसे नहीं जानता है, लेकिन संरचना सूत्रों की कार्यक्षमता आपके दिमाग को चकरा सकती है। सूत्रों का उपयोग करके, आप बेहद उपयोगी तालिकाएँ बना सकते हैं जो कार्यों के साथ काम को बहुत सरल बना सकती हैं, और सबसे महत्वपूर्ण बात यह है कि वे रिलीज़, महाकाव्य और परियोजनाओं का गहन विश्लेषण करने के लिए उपयोगी हैं।
इस लेख में, आप देखेंगे कि अपने स्वयं के सूत्र कैसे बनाएं, सबसे सरल उदाहरणों से शुरू होकर जटिल, बल्कि उपयोगी मामलों तक।
तो, यह पाठ किसके लिए है? किसी को आश्चर्य हो सकता है कि जब एएलएम वर्क्स वेबसाइट पर आधिकारिक दस्तावेज पाठकों के पढ़ने का इंतजार कर रहा है तो लेख क्यों लिखें। यह सच है। हालाँकि, मैं उन लोगों में से एक हूँ जिन्हें इस बात का ज़रा भी अंदाज़ा नहीं था कि संरचना इतनी व्यापक कार्यक्षमता को छिपा रही है: "रुको, यह हमेशा से एक विकल्प था?" उस अहसास ने मुझे सोचने पर मजबूर कर दिया, ऐसे अन्य लोग भी हो सकते हैं जो अभी भी नहीं जानते कि वे सूत्रों और संरचना के साथ किस तरह की चीजें कर सकते हैं।
यह लेख उन लोगों के लिए भी उपयोगी होगा जो पहले से ही सूत्रों से परिचित हैं। आप कस्टम फ़ील्ड का उपयोग करने के लिए कुछ दिलचस्प व्यावहारिक विकल्प सीखेंगे और, शायद, उनमें से कुछ को अपनी परियोजनाओं के लिए उधार लेंगे। वैसे, यदि आपके पास अपना खुद का कोई दिलचस्प उदाहरण है, तो मुझे खुशी होगी यदि आप उन्हें टिप्पणियों में साझा करेंगे .
प्रत्येक उदाहरण का विस्तार से विश्लेषण किया गया है, समस्या के विवरण से लेकर कोड की व्याख्या तक, पर्याप्त रूप से ताकि कोई प्रश्न न बचे। बेशक, स्पष्टीकरणों के साथ-साथ, प्रत्येक उदाहरण को कोड द्वारा चित्रित किया गया है जिसे आप विश्लेषण में पड़े बिना स्वयं आज़मा सकते हैं।
यदि आपको पढ़ने का मन नहीं है, लेकिन आप सूत्रों में रुचि रखते हैं, तो एएलएम वर्क्स वेबिनार देखें। ये 40 मिनट में मूल बातें समझाते हैं; वहां जानकारी बहुत ही संक्षिप्त तरीके से प्रस्तुत की जाती है।
उदाहरणों को समझने के लिए आपको किसी अतिरिक्त ज्ञान की आवश्यकता नहीं है, इसलिए जिसने भी जीरा और स्ट्रक्चर के साथ काम किया है, वह बिना किसी समस्या के अपनी तालिकाओं में उदाहरण दोहरा सकेगा।
डेवलपर्स ने अपनी एक्सपीआर भाषा के साथ काफी लचीला वाक्यविन्यास प्रदान किया। मूलतः, यहाँ का दर्शन है "जैसा चाहो वैसा लिखो, और यह काम करेगा"।
तो चलो शुरू हो जाओ!
तो, हम आख़िर फ़ार्मुलों का उपयोग क्यों करना चाहेंगे? खैर, कभी-कभी यह पता चलता है कि हमारे पास पर्याप्त मानक जीरा फ़ील्ड नहीं हैं, जैसे "असाइनी", "स्टोरी पॉइंट्स", इत्यादि। या हमें कुछ क्षेत्रों के लिए कुछ राशि की गणना करने, शेष क्षमता को संस्करण के अनुसार प्रदर्शित करने और यह पता लगाने की आवश्यकता है कि कार्य ने कितनी बार अपनी स्थिति बदली है। शायद हम अपनी संरचना को पढ़ने में आसान बनाने के लिए कई क्षेत्रों को एक में मिलाना भी चाहते हैं।
इन समस्याओं को हल करने के लिए, हमें सूत्रों की आवश्यकता है, और हम कस्टम फ़ील्ड बनाने के लिए उनका उपयोग करेंगे।
पहली चीज़ जो हमें करने की ज़रूरत है वह यह समझना है कि कोई सूत्र कैसे काम करता है। यह हमें किसी स्ट्रिंग पर किसी प्रकार का ऑपरेशन लागू करने की अनुमति देता है। क्योंकि हम संरचना में कई कार्य अपलोड कर रहे हैं, सूत्र संपूर्ण तालिका की प्रत्येक पंक्ति पर लागू हो जाता है। आमतौर पर, इसके सभी ऑपरेशनों का उद्देश्य इन पंक्तियों में कार्यों के साथ काम करना होता है।
इसलिए, यदि हम सूत्र से कुछ जिरा फ़ील्ड प्रदर्शित करने के लिए कहते हैं, उदाहरण के लिए, "असाइनी", तो सूत्र प्रत्येक कार्य के लिए लागू किया जाएगा, और हमारे पास एक और "असाइनी" कॉलम होगा।
सूत्रों में कई बुनियादी इकाइयाँ शामिल हैं:
हम कुछ उदाहरणों के माध्यम से सूत्रों और उनके वाक्यविन्यास से अधिक परिचित हो जाएंगे, और हम छह व्यावहारिक मामलों से गुजरेंगे।
प्रत्येक उदाहरण को देखने से पहले, हम इंगित करेंगे कि हम कौन सी संरचना सुविधाओं का उपयोग कर रहे हैं; नई सुविधाएँ जिनकी अभी तक व्याख्या नहीं की गई है वे बोल्ड अक्षरों में होंगी। निम्नलिखित प्रत्येक उदाहरण में जटिलता का स्तर बढ़ता जाएगा। उन्हें धीरे-धीरे आपको महत्वपूर्ण सूत्र विशेषताओं से परिचित कराने के लिए व्यवस्थित किया गया है।
यहां मूल संरचना है जिसे आप हर बार देखेंगे:
ये उदाहरण वेरिएबल मैपिंग से लेकर जटिल सरणियों तक के विषयों को कवर करते हैं:
सबसे पहले, आइए जानें कि सूत्रों के साथ कस्टम फ़ील्ड कैसे बनाएं। स्ट्रक्चर के ऊपरी-दाएँ भाग में, सभी कॉलमों के अंत में, एक "+" आइकन है - उस पर क्लिक करें। दिखाई देने वाली फ़ील्ड में, "फ़ॉर्मूला..." लिखें और उपयुक्त आइटम का चयन करें।
आइए एक सूत्र को सहेजने पर चर्चा करें। दुर्भाग्य से, किसी विशिष्ट सूत्र को अलग से कहीं सहेजना अभी भी संभव नहीं है (केवल आपकी नोटबुक में, जैसा कि मैं करता हूँ)। एएलएम वर्क्स वेबिनार में, टीम ने उल्लेख किया कि वे सूत्रों के एक बैंक पर काम कर रहे हैं, लेकिन अभी उन्हें बचाने का एकमात्र तरीका सूत्र के साथ पूरे दृश्य को सहेजना है।
जब हम किसी सूत्र पर काम करना समाप्त कर लेते हैं, तो हमें अपनी संरचना के दृश्य पर क्लिक करना होगा (यह संभवतः नीले तारांकन चिह्न से चिह्नित होगा) और वर्तमान दृश्य को अधिलेखित करने के लिए "सहेजें" पर क्लिक करना होगा। या आप नया दृश्य बनाने के लिए "इस रूप में सहेजें..." पर क्लिक कर सकते हैं। (इसे अन्य जिरा उपयोगकर्ताओं के लिए उपलब्ध कराना न भूलें क्योंकि नए दृश्य डिफ़ॉल्ट रूप से निजी होते हैं।)
सूत्र को एक विशेष दृश्य में शेष फ़ील्ड में सहेजा जाएगा, और आप इसे "विवरण देखें" मेनू के "उन्नत" टैब में देख सकते हैं।
संस्करण 8.2 से शुरू होकर, स्ट्रक्चर में अब 3 त्वरित क्लिक में सूत्रों को सहेजने की क्षमता है।
सेव संवाद सूत्र संपादन विंडो से उपलब्ध है। यदि यह विंडो खुली नहीं है, तो बस वांछित कॉलम में त्रिकोण ▼ आइकन पर क्लिक करें।
संपादन विंडो में हम "सहेजे गए कॉलम" फ़ील्ड देखते हैं, दाईं ओर एक नीले अधिसूचना वाला एक आइकन है, जिसका अर्थ है कि सूत्र में परिवर्तन सहेजे नहीं गए हैं। इस आइकन पर क्लिक करें और "इस रूप में सहेजें..." विकल्प चुनें।
फिर हमारे कॉलम (सूत्र) के लिए नाम दर्ज करें और चुनें कि इसे किस स्थान पर सहेजना है। "मेरे कॉलम" यदि हम इसे व्यक्तिगत सूची में सहेजना चाहते हैं। "वैश्विक", ताकि सूत्र सामान्य सूची में सहेजा जा सके, जहां इसे आपकी संरचना के सभी उपयोगकर्ताओं द्वारा संपादित किया जा सके। "सहेजें" पर क्लिक करें।
अब हमारा फॉर्मूला सेव हो गया है. हम इसे किसी भी संरचना में लोड कर सकते हैं या कहीं से भी पुनः सहेज सकते हैं। सूत्र को पुनः सहेजने से, इसे उन सभी संरचनाओं में अद्यतन किया जाएगा जिनमें इसका उपयोग किया जाता है।
वेरिएबल मैपिंग को सूत्र के साथ भी सहेजा जाता है, लेकिन हम मैपिंग के बारे में बाद में बात करेंगे।
अब, आइए अपने उदाहरणों पर आगे बढ़ें!
हमें कार्यों की सूची के साथ-साथ उन कार्यों पर काम करने की आरंभ और समाप्ति तिथियों वाली एक तालिका की आवश्यकता है। हमें इसे एक अलग एक्सेल-गैंट में निर्यात करने के लिए तालिका की भी आवश्यकता है। दुर्भाग्य से, जीरा और स्ट्रक्चर को यह नहीं पता कि ऐसी तारीखें कैसे प्रदान की जाएं।
प्रारंभ और समाप्ति तिथियां विशिष्ट स्थितियों में संक्रमण की तिथियां हैं, हमारे मामले में ये "प्रगति में" और "बंद" हैं। हमें इन तिथियों को लेने की जरूरत है, और उनमें से प्रत्येक को एक अलग क्षेत्र में प्रदर्शित करना होगा (यह गैंट को आगे निर्यात के लिए आवश्यक है)। तो, हमारे पास दो फ़ील्ड (दो सूत्र) होंगे।
उपयोग की गई संरचना सुविधाएँ
एक कोड उदाहरण
आरंभ तिथि के लिए फ़ील्ड:
firstTransitionToStart
अंतिम तिथि के लिए फ़ील्ड:
latestTransitionToDone
इस मामले में, कोड एक एकल वैरिएबल है, प्रारंभ दिनांक फ़ील्ड के लिए फ़र्स्टट्रांज़िशनटूस्टार्ट, और दूसरे फ़ील्ड के लिए लेटेस्टट्रांज़िशनटूडोन।
आइए अभी आरंभ दिनांक फ़ील्ड पर ध्यान केंद्रित करें। हमारा लक्ष्य कार्य को "प्रगति में" स्थिति में परिवर्तित करने की तिथि प्राप्त करना है (यह कार्य की तार्किक शुरुआत से मेल खाती है), इसलिए बाद में अनुमान लगाने की आवश्यकता को रोकने के लिए चर को स्पष्ट रूप से नाम दिया गया है, "पहला संक्रमण" के रूप में शुरू करना"।
किसी दिनांक को वेरिएबल में बदलने के लिए, हम वेरिएबल मैपिंग की ओर रुख करते हैं। आइए "सहेजें" बटन पर क्लिक करके अपना फॉर्मूला सहेजें।
हमारा वेरिएबल "वेरिएबल्स" अनुभाग में दिखाई दिया, जिसके आगे एक विस्मयादिबोधक चिह्न था। संरचना इंगित करती है कि यह जिरा में एक चर को किसी फ़ील्ड से लिंक नहीं कर सकता है, और हमें इसे स्वयं करना होगा (यानी इसे मैप करें)।
वेरिएबल पर क्लिक करें और मैपिंग इंटरफ़ेस पर जाएं। फ़ील्ड या आवश्यक ऑपरेशन का चयन करें - ऑपरेशन "संक्रमण दिनांक ..." देखें। ऐसा करने के लिए, चयन फ़ील्ड में "संक्रमण" लिखें। आपको एक साथ कई विकल्प पेश किए जाएंगे, और उनमें से एक हमारे लिए उपयुक्त है: "प्रगति में पहला संक्रमण"। लेकिन यह प्रदर्शित करने के लिए कि मैपिंग कैसे काम करती है, आइए "संक्रमण तिथि..." विकल्प चुनें।
उसके बाद, आपको वह स्थिति चुननी होगी जिसमें संक्रमण हुआ, और इस संक्रमण का क्रम - पहला या आखिरी।
"स्थिति" चुनें या दर्ज करें - "स्थिति: प्रगति पर" (या आपके वर्कफ़्लो में संबंधित स्थिति), और "संक्रमण" में - "स्थिति में पहला संक्रमण", क्योंकि किसी कार्य पर काम की शुरुआत सबसे पहला संक्रमण है संबंधित स्थिति के लिए.
यदि "संक्रमण तिथि..." के बजाय हमने प्रारंभ में प्रस्तावित विकल्प "प्रगति में पहला संक्रमण" चुना, तो परिणाम लगभग समान होगा - संरचना हमारे लिए आवश्यक पैरामीटर चुनेगी। एकमात्र बात यह है कि, "स्थिति: प्रगति में" के बजाय, हमारे पास "श्रेणी: प्रगति में" होगा।
मैं एक महत्वपूर्ण विशेषता पर ध्यान देना चाहता हूं: एक स्थिति और एक श्रेणी दो अलग-अलग चीजें हैं। एक स्थिति एक विशिष्ट स्थिति है, यह स्पष्ट है, लेकिन एक श्रेणी में कई स्थितियाँ शामिल हो सकती हैं। केवल तीन श्रेणियां हैं: "करने के लिए", "प्रगति में" और "पूरा"। जीरा में, उन्हें आमतौर पर क्रमशः ग्रे, नीले और हरे रंग से चिह्नित किया जाता है। स्थिति इन श्रेणियों में से किसी एक से संबंधित होनी चाहिए।
मैं एक ही श्रेणी की स्थितियों के साथ भ्रम से बचने के लिए इस तरह के मामलों में एक विशिष्ट स्थिति का संकेत देने की सलाह देता हूं। उदाहरण के लिए, हमारे पास प्रोजेक्ट पर "टू डू" श्रेणी की दो स्थितियाँ हैं, "ओपन" और "क्यूए क्यू"।
आइए अपने उदाहरण पर वापस जाएँ।
एक बार जब हम आवश्यक विकल्प चुन लेते हैं, तो हम फर्स्टट्रांज़िशनटूस्टार्ट वेरिएबल के लिए मैपिंग विकल्पों को पूरा करने के लिए "<बैक टू वेरिएबल्स लिस्ट" पर क्लिक कर सकते हैं। यदि हम सब कुछ ठीक करते हैं, तो हमें हरा चेक मार्क दिखाई देगा।
उसी समय, हमारे कस्टम फ़ील्ड में, हमें कुछ अजीब संख्याएँ दिखाई देती हैं जो बिल्कुल भी तारीख की तरह नहीं दिखती हैं। हमारे मामले में, सूत्र का परिणाम फर्स्टट्रांज़िशनटूस्टार्ट वैरिएबल का मान होगा, और इसका मान जनवरी 1970 से मिलीसेकंड है। सही तिथि प्राप्त करने के लिए, हमें एक विशिष्ट सूत्र प्रदर्शन प्रारूप चुनने की आवश्यकता है।
प्रारूप चयन संपादन विंडो के बिल्कुल नीचे स्थित है। वहां डिफ़ॉल्ट रूप से "सामान्य" चुना गया है। दिनांक को सही ढंग से प्रदर्शित करने के लिए हमें "दिनांक/समय" की आवश्यकता है।
दूसरे फ़ील्ड, नवीनतम ट्रांज़िशनटूडन के लिए, हम वही करेंगे। एकमात्र अंतर यह है कि मैपिंग करते समय हम पहले से ही "पूर्ण" श्रेणी का चयन कर सकते हैं, न कि स्थिति का (क्योंकि आमतौर पर केवल एक स्पष्ट कार्य पूरा होने की स्थिति होती है)। हम संक्रमण पैरामीटर के रूप में "नवीनतम संक्रमण" का चयन करते हैं, क्योंकि हम "संपन्न" श्रेणी के सबसे हालिया संक्रमण में रुचि रखते हैं।
दोनों क्षेत्रों के लिए अंतिम परिणाम इस तरह दिखेगा।
अब आइए देखें कि समान परिणाम कैसे प्राप्त किया जाए, लेकिन अपने स्वयं के प्रदर्शन प्रारूप के साथ।
हम पिछले उदाहरण से दिनांक प्रदर्शन प्रारूप से संतुष्ट नहीं हैं, क्योंकि हमें गैंट तालिका के लिए एक विशेष की आवश्यकता है - "01.01.2022"।
आइए संरचना में निर्मित फ़ंक्शंस का उपयोग करके दिनांक प्रदर्शित करें, उस प्रारूप को निर्दिष्ट करें जो हमारे लिए उपयुक्त है।
संरचना सुविधाओं का उपयोग किया गया
एक कोड उदाहरण
FORMAT_DATETIME(firstTransitionToStart;"dd.MM.yyyy")
डेवलपर्स ने कई अलग-अलग फ़ंक्शन प्रदान किए हैं, जिनमें हमारे अपने प्रारूप में तारीख प्रदर्शित करने के लिए एक अलग फ़ंक्शन भी शामिल है: FORMAT_DATETIME; हम यही उपयोग करने जा रहे हैं। फ़ंक्शन दो तर्कों का उपयोग करता है: एक दिनांक और वांछित प्रारूप की एक स्ट्रिंग।
हमने पिछले उदाहरण के समान मैपिंग नियमों का उपयोग करके पहला ट्रांज़िशनटूस्टार्ट वैरिएबल (पहला तर्क) सेट किया है। दूसरा तर्क प्रारूप को निर्दिष्ट करने वाली एक स्ट्रिंग है, और हम इसे इस तरह परिभाषित करते हैं: "dd.MM.yyyy"। यह उस फॉर्म से मेल खाता है जो हम चाहते हैं, "01.01.2022"।
इस प्रकार, हमारा सूत्र तुरंत वांछित रूप में परिणाम देगा। इसलिए, हम फ़ील्ड सेटिंग्स में "सामान्य" विकल्प रख सकते हैं।
कार्य की अंतिम तिथि वाला दूसरा क्षेत्र भी इसी प्रकार किया जाता है। परिणामस्वरूप, संरचना नीचे दी गई छवि की तरह दिखनी चाहिए।
सिद्धांत रूप में, सूत्र वाक्यविन्यास के साथ काम करने में कोई महत्वपूर्ण कठिनाइयाँ नहीं हैं। यदि आपको किसी वेरिएबल की आवश्यकता है, तो उसका नाम लिखें; यदि आपको किसी फ़ंक्शन की आवश्यकता है, तो बस उसका नाम लिखें और तर्क पारित करें (यदि वे आवश्यक हैं)।
जब स्ट्रक्चर का सामना किसी अज्ञात नाम से होता है, तो वह मान लेता है कि यह एक वेरिएबल है और इसे स्वयं मैप करने का प्रयास करता है, या हमसे मदद मांगता है।
वैसे, एक महत्वपूर्ण नोट: संरचना केस-असंवेदनशील है, इसलिए फर्स्टट्रांज़िशनटूस्टार्ट, फर्स्टट्रांज़िशनटूस्टार्ट, और firSttrAnsItiontOStarT एक ही वेरिएबल हैं। यही नियम कार्यों पर भी लागू होता है। स्पष्ट कोड शैली प्राप्त करने के लिए, उदाहरणों में हम MSDN द्वारा कैपिटलाइज़ेशन कन्वेंशन के नियमों का पालन करने का प्रयास करेंगे।
आइए अब वाक्यविन्यास में गहराई से उतरें और परिणाम प्रदर्शित करने के लिए एक विशेष प्रारूप देखें।
हम नियमित कार्यों (टास्क, बग, आदि) और कहानी-प्रकार के कार्यों के साथ काम करते हैं जिनमें उप-कार्य होते हैं। कुछ बिंदु पर, हमें यह पता लगाना होगा कि कर्मचारी ने एक निश्चित अवधि के दौरान किन कार्यों और उप-कार्यों पर काम किया।
समस्या यह है कि कई उपकार्य स्वयं कहानी के बारे में जानकारी प्रदान नहीं करते हैं, क्योंकि उन्हें "कहानी पर काम करना", "सेटिंग करना" या, उदाहरण के लिए, "प्रभाव को सक्रिय करना" कहा जाता है। और यदि हम एक निश्चित अवधि के लिए कार्यों की सूची का अनुरोध करते हैं, तो हमें बिना किसी अन्य उपयोगी जानकारी के "कहानी पर काम करना" नाम से एक दर्जन कार्य मिलेंगे।
हम दो स्तंभों में विभाजित सूची के साथ एक दृश्य देखना चाहेंगे: एक कार्य और एक मूल कार्य, ताकि भविष्य में कर्मचारियों द्वारा ऐसी सूची को समूहीकृत करना संभव हो सके।
हमारे प्रोजेक्ट पर, हमारे पास दो विकल्प हैं जब किसी कार्य में पेरेंट हो सकता है:
तो, हमें यह करना होगा:
जानकारी की धारणा को सरल बनाने के लिए, हम कार्य प्रकार के पाठ को रंग देंगे: यानी, "[कहानी]" या "[महाकाव्य]"।
हम क्या उपयोग करेंगे:
एक कोड उदाहरण
if( Parent.Issuetype = "Story"; """{color:green}[${Parent.Issuetype}]{color} ${Parent.Summary}"""; EpicLink; """{color:#713A82}[${EpicLink.Issuetype}]{color} ${EpicLink.EpicName}""" )
यदि हमें केवल एक स्ट्रिंग आउटपुट करने और वहां कार्य प्रकार और नाम डालने की आवश्यकता है, तो सूत्र if शर्त से क्यों शुरू होता है? क्या कार्य क्षेत्रों तक पहुँचने का कोई सार्वभौमिक तरीका नहीं है? हां, लेकिन कार्यों और महाकाव्यों के लिए, इन क्षेत्रों को अलग-अलग नाम दिया गया है और आपको उन्हें अलग-अलग एक्सेस करने की भी आवश्यकता है, यह जीरा की एक विशेषता है।
मतभेद मूल खोज के स्तर पर शुरू होते हैं। एक उपकार्य के लिए, माता-पिता "पैरेंट इश्यू" जीरा फ़ील्ड में रहते हैं, और एक नियमित कार्य के लिए, महाकाव्य "एपिक लिंक" फ़ील्ड में स्थित माता-पिता होगा। तदनुसार, हमें इन क्षेत्रों तक पहुँचने के लिए दो अलग-अलग विकल्प लिखने होंगे।
यहीं पर हमें if कंडीशन की आवश्यकता होती है। एक्सपीआर भाषा में स्थितियों से निपटने के विभिन्न तरीके हैं। उनके बीच चुनाव स्वाद का मामला है।
एक "एक्सेल-जैसी" विधि है:
if (condition1; result1; condition2; result2 … )
या अधिक "कोड-जैसी" विधि:
if condition1 : result1 else if condition2 : result2 else result3
उदाहरण में, मैंने पहला विकल्प इस्तेमाल किया; आइए अब अपने कोड को सरलीकृत तरीके से देखें:
if( Parent.Issuetype = "Story"; Some kind of result 1; EpicLink; Some kind of result 2 )
हम दो स्पष्ट स्थितियाँ देखते हैं:
आइए जानें कि वे क्या करते हैं, और पहले वाले से शुरू करते हैं, Parent.Issuetype=”Story”।
इस मामले में, पेरेंट एक वेरिएबल है जो स्वचालित रूप से "पैरेंट इश्यू" फ़ील्ड में मैप किया जाता है। यह वह जगह है जहां, जैसा कि हमने ऊपर चर्चा की, उपकार्य के लिए माता-पिता को रहना चाहिए। डॉट नोटेशन (.) का उपयोग करते हुए, हम इस पैरेंट की संपत्ति तक पहुंचते हैं, विशेष रूप से, इश्यूटाइप प्रॉपर्टी, जो "इश्यू टाइप" जीरा फ़ील्ड से मेल खाती है। यह पता चला है कि यदि ऐसा कोई कार्य मौजूद है, तो संपूर्ण Parent.Issuetype लाइन हमें मूल कार्य का प्रकार लौटाती है।
इसके अतिरिक्त, हमें कुछ भी परिभाषित या मैप करने की आवश्यकता नहीं थी, क्योंकि डेवलपर्स पहले ही हमारे लिए अपना सर्वश्रेष्ठ प्रयास कर चुके हैं। यहां, उदाहरण के लिए, उन सभी संपत्तियों (जिरा फ़ील्ड सहित) का एक लिंक है जो भाषा में पूर्वनिर्धारित हैं, और यहां आप सभी मानक चर की एक सूची देख सकते हैं, जिन्हें अतिरिक्त सेटिंग्स के बिना भी सुरक्षित रूप से एक्सेस किया जा सकता है।
इस प्रकार, पहली शर्त यह देखना है कि मूल कार्य का प्रकार कहानी है या नहीं। यदि पहली शर्त पूरी नहीं होती है, तो मूल कार्य का प्रकार स्टोरी नहीं है, या इसका अस्तित्व ही नहीं है। और यह हमें दूसरी स्थिति पर लाता है: एपिकलिंक।
वास्तव में, यह तब होता है जब हम जाँचते हैं कि क्या "एपिक लिंक" जीरा फ़ील्ड भरा हुआ है (अर्थात, हम इसके अस्तित्व की जाँच करते हैं)। EpicLink वैरिएबल भी मानक है और इसे मैप करने की आवश्यकता नहीं है। यह पता चलता है कि यदि कार्य में एपिक लिंक है तो हमारी स्थिति संतुष्ट है।
और तीसरा विकल्प तब होता है जब कोई भी शर्त पूरी नहीं होती है, यानी, कार्य का न तो कोई अभिभावक है और न ही एपिक लिंक। इस मामले में, हम कुछ भी प्रदर्शित नहीं करते हैं और फ़ील्ड को खाली छोड़ देते हैं। यह स्वचालित रूप से किया जाता है क्योंकि हमें कोई परिणाम नहीं मिलेगा।
हमने स्थितियों का पता लगा लिया, अब परिणामों की ओर बढ़ते हैं। दोनों ही मामलों में, यह टेक्स्ट और विशेष फ़ॉर्मेटिंग वाली एक स्ट्रिंग है।
परिणाम 1 (यदि मूल कहानी है):
"""{color:green}[${Parent.Issuetype}]{color} ${Parent.Summary}"""
परिणाम 2 (यदि महाकाव्य लिंक है):
"""{color:#713A82}[${EpicLink.Issuetype}]{color} ${EpicLink.EpicName}"""
दोनों परिणाम संरचना में समान हैं: दोनों में आउटपुट स्ट्रिंग की शुरुआत और अंत में ट्रिपल कोट्स "" शामिल हैं, शुरुआती {रंग: रंग} और समापन {रंग} ब्लॉक में रंग विनिर्देश, साथ ही साथ किए गए ऑपरेशन भी शामिल हैं। $ प्रतीक. ट्रिपल उद्धरण संरचना को बताते हैं कि अंदर चर, संचालन, या फ़ॉर्मेटिंग ब्लॉक (जैसे रंग) होंगे।
पहली शर्त के परिणाम के लिए, हम:
इस प्रकार, हमें स्ट्रिंग मिलती है "[कहानी] कुछ कार्य का नाम।" जैसा कि आपने अनुमान लगाया होगा, सारांश भी एक मानक चर है। ऐसी स्ट्रिंग्स के निर्माण की योजना को स्पष्ट करने के लिए, मैं आधिकारिक दस्तावेज़ से एक छवि साझा करना चाहता हूँ।
इसी तरह, हम दूसरे परिणाम के लिए स्ट्रिंग एकत्र करते हैं, लेकिन हेक्स कोड के माध्यम से रंग सेट करते हैं। मुझे पता चला कि महाकाव्य का रंग "#713ए82" था (वैसे, आप टिप्पणियों में महाकाव्य के लिए अधिक सटीक रंग सुझा सकते हैं)। उन फ़ील्ड्स (गुणों) के बारे में न भूलें जो एपिक के लिए बदलते हैं। "सारांश" के बजाय "एपिकनाम" का उपयोग करें, "पैरेंट" के बजाय "एपिकलिंक" का उपयोग करें।
परिणामस्वरूप, हमारे सूत्र की योजना को शर्तों की तालिका के रूप में दर्शाया जा सकता है।
शर्त: मूल-कार्य मौजूद है, और इसका प्रकार कहानी है।
परिणाम: मूल-कार्य के हरे प्रकार और उसके नाम वाली पंक्ति।
शर्त: एपिक लिंक फ़ील्ड भर गया है।
परिणाम: प्रकार और उसके नाम के महाकाव्य रंग के साथ पंक्ति।
डिफ़ॉल्ट रूप से, फ़ील्ड में "सामान्य" डिस्प्ले विकल्प चुना जाता है, और यदि आप इसे नहीं बदलते हैं, तो परिणाम रंग बदले बिना और ब्लॉक की पहचान किए बिना सादे पाठ जैसा दिखेगा। यदि आप डिस्प्ले फॉर्मेट को "विकी मार्कअप" में बदलते हैं, तो टेक्स्ट रूपांतरित हो जाएगा।
अब, आइए उन वेरिएबल्स से परिचित हों जो जिरा फ़ील्ड्स से संबंधित नहीं हैं - स्थानीय वेरिएबल्स।
पिछले उदाहरण से, आपने सीखा कि हम स्टोरी प्रकार के कार्यों के साथ काम कर रहे हैं, जिनमें उप-कार्य हैं। यह अनुमान के साथ एक विशेष मामले को जन्म देता है। स्टोरी स्कोर प्राप्त करने के लिए, हम इसके उप-कार्यों के स्कोर को संक्षेप में प्रस्तुत करते हैं, जिसका अनुमान अमूर्त स्टोरी बिंदुओं में लगाया जाता है।
दृष्टिकोण असामान्य है, लेकिन यह हमारे लिए काम करता है। इसलिए, जब स्टोरी में कोई अनुमान नहीं होता है, लेकिन उपकार्य होता है, तो कोई समस्या नहीं होती है, लेकिन जब स्टोरी और उपकार्य दोनों में अनुमान होता है, तो संरचना से मानक विकल्प, "Σ स्टोरी पॉइंट्स", गलत तरीके से काम करता है।
ऐसा इसलिए है क्योंकि कहानी का अनुमान उप-कार्यों के योग में जोड़ा जाता है। परिणामस्वरूप, स्टोरी में गलत राशि प्रदर्शित होती है। हम इससे बचना चाहेंगे और स्टोरी में स्थापित अनुमान और उपकार्यों के योग के साथ असंगतता का संकेत जोड़ना चाहेंगे।
हमें कई शर्तों की आवश्यकता है, क्योंकि यह सब इस बात पर निर्भर करता है कि स्टोरी में अनुमान निर्धारित किया गया है या नहीं।
तो शर्तें ये हैं:
जब स्टोरी में कोई अनुमान नहीं होता है , तो हम यह इंगित करने के लिए उप-कार्यों के अनुमान का योग नारंगी रंग में प्रदर्शित करते हैं कि यह मान अभी तक स्टोरी में सेट नहीं किया गया है
यदि स्टोरी में कोई अनुमान है , तो जांचें कि क्या यह उप-कार्यों के अनुमान के योग से मेल खाता है:
इन शर्तों की शब्दावली भ्रमित करने वाली हो सकती है, तो आइए इन्हें एक योजना में व्यक्त करें।
संरचना सुविधाओं का उपयोग किया गया
एक कोड उदाहरण
with isEstimated = storypoints != undefined: with childrenSum = sum#children{storypoints}: with isStory = issueType = "Story": with isErr = isStory AND childrenSum != storypoints: with color = if isStory : if isEstimated : if isErr : "red" else "green" else "orange": if isEstimated : """{color:$color}$storypoints{color} ${if isErr :""" ($childrenSum)"""}""" else """{color:$color}$childrenSum{color}"""
कोड में गोता लगाने से पहले, आइए अपनी योजना को और अधिक "कोड-जैसी" तरीके से बदलें ताकि यह समझ सकें कि हमें किन वेरिएबल्स की आवश्यकता है।
इस योजना से हम देखते हैं कि हमें इसकी आवश्यकता होगी:
स्थिति चर:
पाठ रंग का एक चर - रंग
अनुमान के दो चर:
इसके अलावा, रंग परिवर्तन कई स्थितियों पर भी निर्भर करता है, उदाहरण के लिए, एक अनुमान की उपलब्धता पर और पंक्ति में कार्य के प्रकार पर (नीचे दी गई योजना देखें)।
इसलिए, रंग निर्धारित करने के लिए, हमें एक अन्य कंडीशन वेरिएबल, isStory की आवश्यकता होगी, जो इंगित करता है कि कार्य का प्रकार स्टोरी है या नहीं।
एसपी वैरिएबल (स्टोरीप्वाइंट) मानक होगा, जिसका अर्थ है कि यह स्वचालित रूप से उपयुक्त जीरा फ़ील्ड पर मैप हो जाएगा। हमें बाकी वेरिएबल्स को स्वयं परिभाषित करना चाहिए और वे हमारे लिए स्थानीय होंगे।
आइए अब योजनाओं को कोड में लागू करने का प्रयास करें। सबसे पहले, आइए सभी वेरिएबल्स को परिभाषित करें।
with isEstimated = storypoints != undefined: with childrenSum = sum#children{storypoints}: with isStory = issueType = "Story": with isErr = isStory AND childrenSum != storypoints:
पंक्तियाँ समान वाक्यविन्यास योजना द्वारा एकजुट होती हैं: कीवर्ड के साथ, चर नाम, और पंक्ति के अंत में कोलन प्रतीक ":"।
with कीवर्ड का उपयोग स्थानीय चर (और कस्टम फ़ंक्शंस, लेकिन एक अलग उदाहरण में उस पर अधिक) को दर्शाने के लिए किया जाता है। यह सूत्र बताता है कि अगला एक वेरिएबल है जिसे मैप करने की आवश्यकता नहीं है। कोलन ":" वेरिएबल परिभाषा के अंत को चिह्नित करता है।
इस प्रकार, हम isEstimated वैरिएबल बनाते हैं (अनुस्मारक, वह मामला महत्वपूर्ण नहीं है)। हम इसमें 1 या 0 स्टोर करेंगे, यह इस बात पर निर्भर करेगा कि स्टोरी पॉइंट फ़ील्ड भरा हुआ है या नहीं। स्टोरीप्वाइंट वैरिएबल स्वचालित रूप से मैप किया जाता है क्योंकि हमने पहले इसी नाम से कोई स्थानीय वैरिएबल नहीं बनाया है (उदाहरण के लिए, स्टोरीप्वाइंट = ... :) के साथ।
अपरिभाषित चर किसी चीज़ की गैर-मौजूदगी को दर्शाता है (जैसे शून्य, NaN और अन्य भाषाओं में)। इसलिए, अभिव्यक्ति स्टोरीपॉइंट != अपरिभाषित को एक प्रश्न के रूप में पढ़ा जा सकता है: "क्या स्टोरी पॉइंट फ़ील्ड भर गया है?"।
इसके बाद, हमें सभी बाल कार्यों के कहानी बिंदुओं का योग निर्धारित करना चाहिए। ऐसा करने के लिए, हम एक स्थानीय चर बनाते हैं:childrenSum।
with childrenSum = sum#children{storypoints}:
इस राशि की गणना एकत्रीकरण फ़ंक्शन के माध्यम से की जाती है। (आप आधिकारिक दस्तावेज में इस तरह के कार्यों के बारे में पढ़ सकते हैं।) संक्षेप में, संरचना वर्तमान दृश्य के पदानुक्रम को ध्यान में रखते हुए, कार्यों के साथ विभिन्न संचालन कर सकती है।
हम योग फ़ंक्शन का उपयोग करते हैं, और इसके अतिरिक्त, "#" प्रतीक का उपयोग करके, हम स्पष्टीकरण बच्चों को पास करते हैं, जो योग की गणना को केवल वर्तमान पंक्ति के किसी भी बच्चे के कार्यों तक सीमित करता है। घुंघराले कोष्ठक में, हम इंगित करते हैं कि हम किस क्षेत्र को संक्षेप में प्रस्तुत करना चाहते हैं - हमें कहानी बिंदुओं में एक अनुमान की आवश्यकता है।
अगला स्थानीय चर, isStory, एक शर्त संग्रहीत करता है: क्या वर्तमान पंक्ति में कार्य प्रकार एक कहानी है।
with isStory = issueType = "Story":
हम पिछले उदाहरण से परिचित इश्यूटाइप वैरिएबल की ओर मुड़ते हैं, यानी, कार्य का प्रकार जो स्वयं वांछित फ़ील्ड पर मैप होता है। हम ऐसा इसलिए कर रहे हैं क्योंकि यह एक मानक चर है और हमने पहले इसे इसके माध्यम से परिभाषित नहीं किया है।
अब आइए isErr वेरिएबल को परिभाषित करें - यह उपकार्य योग और स्टोरी अनुमान के बीच एक विसंगति का संकेत देता है।
with isErr = isStory AND childrenSum != storypoints:
यहां हम isStory औरchildrenSum स्थानीय वेरिएबल्स का उपयोग कर रहे हैं जिन्हें हमने पहले बनाया था। किसी त्रुटि का संकेत देने के लिए, हमें दो शर्तों को एक साथ पूरा करने की आवश्यकता है: समस्या का प्रकार कहानी है (कहानी है) और (और) बच्चों के अंकों का योग (चिल्ड्रेन्ससम) कार्य में निर्धारित अनुमान के बराबर (!=) नहीं है (कहानीबिंदु) ). JQL की तरह ही, हम AND या OR जैसी स्थितियाँ बनाते समय लिंक शब्दों का उपयोग कर सकते हैं।
ध्यान दें, प्रत्येक स्थानीय चर के लिए पंक्ति के अंत में एक ":" प्रतीक होता है। यह वेरिएबल को परिभाषित करने वाले सभी ऑपरेशनों के बाद अंत में होना चाहिए। उदाहरण के लिए, यदि हमें किसी वेरिएबल की परिभाषा को कई पंक्तियों में विभाजित करने की आवश्यकता है, तो कोलन ":" केवल अंतिम ऑपरेशन के बाद रखा जाता है। जैसा कि रंग चर वाले उदाहरण में है - पाठ का रंग।
with color = if isStory : if isEstimated : if isErr : "red" else "green" else "orange":
यहाँ हम बहुत सारे ":" देखते हैं, लेकिन वे अलग-अलग भूमिकाएँ निभाते हैं। if isStory के बाद का कोलन isStory स्थिति का परिणाम है। आइए निर्माण को याद करें: यदि स्थिति: परिणाम। आइए इस निर्माण को अधिक जटिल रूप में प्रस्तुत करें, जो एक चर को परिभाषित करता है।
with variable = (if condition: (if condition2 : result2 else result3) ):
यह पता चला है कि यदि शर्त 2: परिणाम 2 अन्यथा परिणाम 3, जैसा कि यह था, पहली स्थिति का परिणाम है, और अंत में एक कोलन ":" है, जो चर की परिभाषा को पूरा करता है।
पहली नज़र में, रंग की परिभाषा जटिल लग सकती है, हालाँकि, वास्तव में, हमने यहाँ उदाहरण की शुरुआत में प्रस्तुत रंग परिभाषा योजना का वर्णन किया है। यह सिर्फ इतना है कि पहली स्थिति के परिणामस्वरूप, एक और स्थिति शुरू होती है - एक नेस्टेड स्थिति, और उसमें एक और।
लेकिन अंतिम परिणाम पहले प्रस्तुत योजना से थोड़ा अलग है।
if isEstimated : """{color:$color}$storypoints{color} ${if isErr :""" ($childrenSum)"""}""" else """{color:$color}$childrenSum{color}"""
हमें कोड में "{color}$sp'' दो बार लिखने की ज़रूरत नहीं है, जैसा कि स्कीम में था; हम चीज़ों के बारे में अधिक होशियार हो जायेंगे। शाखा में, यदि कार्य का अनुमान है, तो हम हमेशा {color: $color}$storypoints{color} प्रदर्शित करेंगे (अर्थात्, आवश्यक रंग में कहानी बिंदुओं में केवल एक अनुमान), और यदि कोई त्रुटि है, तो एक स्थान के बाद, हम उप-कार्य अनुमान के योग के साथ पंक्ति को पूरक करेंगे: ($childrenSum)।
यदि कोई त्रुटि नहीं है, तो इसे जोड़ा नहीं जाएगा. मैं इस तथ्य पर भी आपका ध्यान आकर्षित करता हूं कि कोई ":" प्रतीक नहीं है, क्योंकि हम एक चर को परिभाषित नहीं करते हैं, लेकिन एक शर्त के माध्यम से अंतिम परिणाम प्रदर्शित करते हैं।
हम नीचे दी गई छवि में "∑SP (mod)" फ़ील्ड में अपने काम का मूल्यांकन कर सकते हैं। स्क्रीनशॉट विशेष रूप से दो अतिरिक्त फ़ील्ड दिखाता है:
इन उदाहरणों की सहायता से, हमने संरचना भाषा की मुख्य विशेषताओं का विश्लेषण किया है जो आपको अधिकांश समस्याओं को हल करने में मदद करेगी। आइए अब दो और उपयोगी सुविधाओं, हमारे कार्यों और सरणियों पर नज़र डालें। हम देखेंगे कि अपना स्वयं का कस्टम फ़ंक्शन कैसे बनाएं।
कभी-कभी एक स्प्रिंट में कई कार्य होते हैं और हम उनमें छोटे-छोटे बदलाव करने से चूक सकते हैं। उदाहरण के लिए, हम एक नया उप-कार्य या इस तथ्य से चूक सकते हैं कि कहानियों में से एक अगले चरण में चली गई है। कार्यों में नवीनतम महत्वपूर्ण परिवर्तनों के बारे में हमें सूचित करने वाला एक उपकरण होना अच्छा होगा।
हम कल से हुए तीन प्रकार के कार्य स्थिति परिवर्तनों में रुचि रखते हैं: हमने कार्य पर काम करना शुरू कर दिया, एक नया कार्य सामने आया, कार्य बंद हो गया। इसके अतिरिक्त, यह देखना उपयोगी होगा कि कार्य "नहीं करेंगे" संकल्प के साथ बंद कर दिया गया है।
ऐसा करने के लिए, हम इमोजी की एक श्रृंखला के साथ एक फ़ील्ड बनाएंगे जो नवीनतम परिवर्तनों के लिए ज़िम्मेदार हैं। उदाहरण के लिए, यदि कोई कार्य कल बनाया गया था और हमने उस पर काम करना शुरू कर दिया था, तो इसे दो इमोजी के साथ चिह्नित किया जाएगा: "प्रगति पर" और "नया कार्य"।
हमें ऐसे कस्टम फ़ील्ड की आवश्यकता क्यों है, यदि कई अतिरिक्त फ़ील्ड प्रदर्शित किए जा सकते हैं, उदाहरण के लिए, "प्रगति में" स्थिति या एक अलग "रिज़ॉल्यूशन" फ़ील्ड में संक्रमण की तारीख? उत्तर सरल है - लोग टेक्स्ट की तुलना में इमोजी को अधिक आसानी से और तेजी से समझते हैं, जो विभिन्न क्षेत्रों में स्थित है और इसका विश्लेषण करने की आवश्यकता है। सूत्र सब कुछ एक जगह एकत्र करेगा और हमारे लिए उसका विश्लेषण करेगा, जिससे अधिक उपयोगी चीजों के लिए हमारा प्रयास और समय बचेगा।
आइए निर्धारित करें कि विभिन्न इमोजी किसके लिए जिम्मेदार होंगे:
संरचना सुविधाओं का उपयोग किया गया
एक कोड उदाहरण
if defined(issueType): with now = now(): with daysScope = 1.3: with workDaysBetween(today, from)= ( with weekends = (Weeknum(today) - Weeknum(from)) * 2: HOURS_BETWEEN(from;today)/24 - weekends ): with daysAfterCreated = workDaysBetween(now,created): with daysAfterStart = workDaysBetween(now,latestTransitionToProgress): with daysAfterDone = workDaysBetween(now, resolutionDate): with isWontDo = resolution = "Won't Do": with isRecentCreated = daysAfterCreated >= 0 and daysAfterCreated <= daysScope and not(resolution): with isRecentWork = daysAfterStart >= 0 and daysAfterStart <= daysScope : with isRecentDone = daysAfterDone >= 0 and daysAfterDone <= daysScope : concat( if isRecentCreated : "*️⃣", if isRecentWork : "🚀", if isRecentDone : "✅", if isWontDo : "❌")
समाधान का एक विश्लेषण
आरंभ करने के लिए, आइए उन वैश्विक चरों के बारे में सोचें जिनकी हमें रुचि की घटनाओं को निर्धारित करने के लिए आवश्यकता है। हमें यह जानने की जरूरत है, यदि कल से:
नए मैपिंग वेरिएबल के साथ पहले से मौजूद वेरिएबल का उपयोग करने से हमें इन सभी स्थितियों की जांच करने में मदद मिलेगी।
चलिए कोड पर चलते हैं। पहली पंक्ति एक शर्त से शुरू होती है जो जांच करती है कि कार्य प्रकार मौजूद है या नहीं।
if defined(issueType):
यह अंतर्निहित परिभाषित फ़ंक्शन के माध्यम से किया जाता है, जो निर्दिष्ट फ़ील्ड के अस्तित्व की जांच करता है। जाँच सूत्र की गणना को अनुकूलित करने के लिए की जाती है।
यदि लाइन कोई कार्य नहीं है, तो हम बेकार गणनाओं के साथ संरचना को लोड नहीं करेंगे। यह पता चला है कि if के बाद का सारा कोड परिणाम है, मेरा मतलब है, if (स्थिति: परिणाम) निर्माण का दूसरा भाग। और यदि शर्त पूरी नहीं हुई तो कोड भी काम नहीं करेगा।
गणनाओं को अनुकूलित करने के लिए now = now(): के साथ अगली पंक्ति की भी आवश्यकता है। कोड में आगे, हमें कई बार वर्तमान तिथि के साथ विभिन्न तिथियों की तुलना करनी होगी। एक ही गणना कई बार न करने के लिए, हम इस तिथि की एक बार गणना करेंगे और इसे अब एक स्थानीय चर बना देंगे।
हमारे "कल" को अलग रखना भी अच्छा होगा। सुविधाजनक "कल" अनुभवजन्य रूप से 1.3 दिनों में बदल गया। आइए इसे एक वेरिएबल बनाएं: डेज़स्कोप = 1.3: के साथ।
अब हमें दो तिथियों के बीच दिनों की संख्या की कई बार गणना करने की आवश्यकता है। उदाहरण के लिए, वर्तमान तिथि और कार्य आरंभ तिथि के बीच. बेशक, इसमें एक अंतर्निहित DAYS_BETWEEN फ़ंक्शन है, जो हमें उपयुक्त लगता है। लेकिन, उदाहरण के लिए, यदि कार्य शुक्रवार को बनाया गया था, तो सोमवार को हमें नए कार्य की सूचना नहीं दिखाई देगी, क्योंकि वास्तव में 1.3 दिन से अधिक समय बीत चुका है। इसके अलावा, DAYS_BETWEEN फ़ंक्शन केवल दिनों की कुल संख्या की गणना करता है (अर्थात, 0.5 दिन 0 दिनों में बदल जाएंगे), जो हमारे लिए भी उपयुक्त नहीं है।
हमने एक आवश्यकता बनाई है - हमें इन तिथियों के बीच कार्य दिवसों की सटीक संख्या की गणना करने की आवश्यकता है; और एक कस्टम फ़ंक्शन इसमें हमारी सहायता करेगा.
इसका परिभाषित सिंटैक्स स्थानीय चर को परिभाषित करने के सिंटैक्स के समान है। एकमात्र अंतर और एकमात्र जोड़ पहले कोष्ठक में तर्कों की वैकल्पिक गणना है। दूसरे कोष्ठक में वे ऑपरेशन शामिल हैं जो हमारे फ़ंक्शन को कॉल करने पर निष्पादित किए जाएंगे। फ़ंक्शन की यह परिभाषा एकमात्र संभव नहीं है, लेकिन हम इसका उपयोग करेंगे (अन्य को आधिकारिक दस्तावेज़ में पाया जा सकता है)।
with workDaysBetween(today, from)= ( with weekends = (Weeknum(today) - Weeknum(from)) * 2: HOURS_BETWEEN(from;today)/24 - weekends ):
हमारा कस्टम वर्कडेज़बिटवीन फ़ंक्शन आज और तारीखों के बीच कार्य दिवसों की गणना करेगा, जिन्हें तर्क के रूप में पारित किया जाता है। फ़ंक्शन का तर्क बहुत सरल है: हम छुट्टी के दिनों की संख्या गिनते हैं और उन्हें तारीखों के बीच के दिनों की कुल संख्या से घटा देते हैं।
छुट्टी के दिनों की संख्या की गणना करने के लिए, हमें यह पता लगाना होगा कि आज से लेकर आज के बीच कितने सप्ताह बीत चुके हैं। ऐसा करने के लिए, हम प्रत्येक सप्ताह की संख्याओं के बीच अंतर की गणना करते हैं। हम यह संख्या वीकनम फ़ंक्शन से प्राप्त करेंगे, जो हमें वर्ष की शुरुआत से सप्ताह की संख्या प्रदान करती है। इस अंतर को दो से गुणा करने पर हमें बीते हुए अवकाश के दिनों की संख्या प्राप्त होती है।
इसके बाद, HOURS_BETWEEN फ़ंक्शन हमारी तिथियों के बीच घंटों की संख्या की गणना करता है। हम दिनों की संख्या प्राप्त करने के लिए परिणाम को 24 से विभाजित करते हैं, और इस संख्या में से छुट्टी के दिनों को घटाते हैं, इसलिए हमें तारीखों के बीच कार्यदिवस मिलते हैं।
अपने नए फ़ंक्शन का उपयोग करके, आइए सहायक चर के एक समूह को परिभाषित करें। ध्यान दें कि परिभाषाओं में कुछ तिथियाँ वैश्विक चर हैं, जिनके बारे में हमने उदाहरण की शुरुआत में बात की थी।
with daysAfterCreated = workDaysBetween(now,created): with daysAfterStart = workDaysBetween(now,latestTransitionToProgress): with daysAfterDone = workDaysBetween(now, resolutionDate):
कोड को पढ़ने के लिए सुविधाजनक बनाने के लिए, आइए वेरिएबल्स को परिभाषित करें जो शर्तों के परिणामों को संग्रहीत करते हैं।
with isWontDo = resolution = "Won't Do": with isRecentCreated = daysAfterCreated >= 0 and daysAfterCreated <= daysScope and not(resolution): with isRecentWork = daysAfterStart >= 0 and daysAfterStart <= daysScope : with isRecentDone = daysAfterDone >= 0 and daysAfterDone <= daysScope :
IsRecentCreated वैरिएबल के लिए, मैंने एक वैकल्पिक शर्त जोड़ी है, न कि (रिज़ॉल्यूशन), जो मुझे भविष्य की लाइन को सरल बनाने में मदद करती है, क्योंकि यदि कार्य पहले ही बंद हो चुका है, तो मुझे इसके हालिया निर्माण के बारे में जानकारी में कोई दिलचस्पी नहीं है।
अंतिम परिणाम का निर्माण कॉनकैट फ़ंक्शन के माध्यम से, रेखाओं को जोड़ते हुए किया जाता है।
concat( if isRecentCreated : "*️⃣", if isRecentWork : "🚀", if isRecentDone : "✅", if isWontDo : "❌")
यह पता चला है कि इमोजी लाइन में तभी होगा जब स्थिति में चर 1 के बराबर होगा। इस प्रकार, हमारी लाइन एक साथ कार्य में स्वतंत्र परिवर्तन प्रदर्शित कर सकती है।
हमने बिना अवकाश के कार्य दिवसों की गिनती के विषय पर चर्चा की है। इससे जुड़ी एक और समस्या है, जिसका विश्लेषण हम अपने पिछले उदाहरण में करेंगे और साथ ही एरे से भी परिचित होंगे।
कभी-कभी हम जानना चाहते हैं कि अवकाश के दिनों को छोड़कर कोई कार्य कितने समय से चल रहा है। उदाहरण के लिए, जारी संस्करण का विश्लेषण करना आवश्यक है। यह समझने के लिए कि हमें छुट्टी के दिनों की आवश्यकता क्यों है। सिवाय इसके कि एक सोमवार से गुरुवार तक चल रहा था, और दूसरा शुक्रवार से सोमवार तक चल रहा था। ऐसी स्थिति में, हम यह नहीं बता सकते कि कार्य समतुल्य हैं, हालाँकि कैलेंडर दिनों में अंतर हमें विपरीत बताता है।
दुर्भाग्य से, संरचना "बॉक्स से बाहर" छुट्टी के दिनों को अनदेखा करना नहीं जानती है, और "स्थिति में समय..." विकल्प वाला फ़ील्ड जीरा सेटिंग्स की परवाह किए बिना परिणाम उत्पन्न करता है - भले ही शनिवार और रविवार को छुट्टी के दिनों के रूप में निर्दिष्ट किया गया हो।
परिणामस्वरूप, हमारा लक्ष्य छुट्टी के दिनों को नज़रअंदाज़ करते हुए, कार्य दिवसों की सटीक संख्या की गणना करना और इस समय स्थिति परिवर्तन के प्रभाव को ध्यान में रखना है।
और स्टेटस का इससे क्या लेना-देना है? मुझे उत्तर देने दीजिए. मान लीजिए कि हमने गणना की कि 10 मार्च से 20 मार्च के बीच, कार्य तीन दिनों के लिए काम पर था। लेकिन इन 3 दिनों में से एक दिन यह रुका हुआ था और डेढ़ दिन समीक्षा में। पता चला कि कार्य केवल आधे दिन के लिए ही था।
स्थितियों के बीच स्विच करने की समस्या के कारण पिछले उदाहरण का समाधान हमारे लिए उपयुक्त नहीं है, क्योंकि कस्टम वर्कडेज़बिटवीन फ़ंक्शन केवल दो चयनित तिथियों के बीच के समय को ध्यान में रखता है।
इस समस्या को विभिन्न तरीकों से हल किया जा सकता है। उदाहरण में दी गई विधि प्रदर्शन के मामले में सबसे महंगी है, लेकिन छुट्टी के दिनों और स्थिति की गिनती के मामले में सबसे सटीक है। ध्यान दें कि इसका कार्यान्वयन केवल 7.4 (दिसंबर 2021) से पुराने स्ट्रक्चर संस्करण में काम करता है।
तो, सूत्र के पीछे का विचार इस प्रकार है:
इस प्रकार, हमें अतिरिक्त स्थितियों के बीच छुट्टी के दिनों और बदलावों को नजरअंदाज करते हुए, कार्य पर काम करने का सटीक समय मिलेगा।
संरचना सुविधाओं का उपयोग किया गया
एक कोड उदाहरण
if defined(issueType) : if status != "Open" : with finishDate = if toQA != Undefined : toQA else if toDone != Undefined : toDone else now(): with startDate = DEFAULT(toProgress, toDone): with statusWeekendsCount(dates, status) = ( dates.filter(x -> weekday(x) > 5 and historical_value(this,"status",x)=status).size() ): with overallDays = round(hours_between(startDate,finishDate)/24): with sequenceArray = SEQUENCE(0,overallDays): with datesArray = sequenceArray.map(DATE_ADD(startDate,$,"day")): with progressWeekends = statusWeekendsCount(datesArray, "in Progress"): with progressDays = (timeInProgress/86400000 - progressWeekends).round(1): with color = if( progressDays = 0 ; "gray" ; progressDays > 0 and progressDays <= 2.5; "green" ; progressDays > 2.5 and progressDays <= 4; "orange" ; progressDays > 4; "red" ): """{color:$color}$progressDays d{color}"""
समाधान का एक विश्लेषण
अपने एल्गोरिदम को कोड में स्थानांतरित करने से पहले, आइए संरचना के लिए गणना की सुविधा प्रदान करें।
if defined(issueType) : if status != "Open" :
यदि पंक्ति कोई कार्य नहीं है या उसकी स्थिति "खुली" है, तो हम उन पंक्तियों को छोड़ देंगे। हम केवल उन कार्यों में रुचि रखते हैं जिन पर काम शुरू किया गया है।
तिथियों के बीच दिनों की संख्या की गणना करने के लिए, हमें पहले ये तिथियां निर्धारित करनी होंगी: समाप्ति तिथि और प्रारंभ तिथि।
with finishDate = if toQA != Undefined : toQA else if toDone != Undefined : toDone else now(): with startDate = DEFAULT(toProgress, toDone):
हम मान लेंगे कि कार्य पूरा होने की तारीख (समाप्ति तिथि) है:
कार्य प्रारंभ होने की तिथि प्रारंभ होने की तिथि "प्रगति में" स्थिति में संक्रमण की तिथि से निर्धारित होती है। ऐसे मामले होते हैं जब कार्य-कार्य चरण में आए बिना ही कार्य बंद हो जाता है। ऐसे मामलों में, हम समापन तिथि को प्रारंभ तिथि मानते हैं, इसलिए, परिणाम 0 दिन है।
जैसा कि आपने अनुमान लगाया होगा कि toQA, toDone और toProgress वेरिएबल हैं जिन्हें पहले और पिछले उदाहरणों की तरह उपयुक्त स्थितियों में मैप करने की आवश्यकता है।
हम नया DEFAULT(toProgress, toDone) फ़ंक्शन भी देखते हैं। यह जाँचता है कि क्या toProgress का कोई मान है, और यदि नहीं, तो यह toDone वैरिएबल के मान का उपयोग करता है।
इसके बाद statusWeekendsCount कस्टम फ़ंक्शन की परिभाषा आती है, लेकिन हम इस पर बाद में लौटेंगे, क्योंकि यह तारीखों की सूचियों से निकटता से संबंधित है। इस सूची की परिभाषा पर सीधे जाना बेहतर है, ताकि बाद में हम समझ सकें कि इसमें अपना फ़ंक्शन कैसे लागू किया जाए।
हम निम्नलिखित रूप में तिथियों की एक सूची प्राप्त करना चाहते हैं: [प्रारंभ तिथि (मान लीजिए 11.03), 12.03, 13.03, 14.03... समाप्ति तिथि]। ऐसा कोई सरल कार्य नहीं है जो संरचना में हमारे लिए सभी कार्य कर सके। तो चलिए एक ट्रिक का सहारा लेते हैं:
अब, आइए देखें कि हम इसे कोड में कैसे लागू कर सकते हैं। हम सरणियों के साथ काम करेंगे।
with overallDays = round(hours_between(startDate,finishDate)/24): with sequenceArray = SEQUENCE(0,overallDays): with datesArray = sequenceArray.map(DATE_ADD(startDate,$,"day")):
हम गिनते हैं कि किसी कार्य पर कितने दिन लगेंगे। पिछले उदाहरण की तरह, 24 से भाग देकर और Hours_between(startDate,finishDate)फ़ंक्शन के माध्यम से। परिणाम समग्र दिवस चर में लिखा गया है।
हम SequenceArray वैरिएबल के रूप में संख्याओं के अनुक्रम की एक सरणी बनाते हैं। इस सरणी का निर्माण SEQUENCE(0,overallDays) फ़ंक्शन के माध्यम से किया गया है, जो 0 से समग्रदिनों के अनुक्रम के साथ वांछित आकार की एक सरणी बनाता है।
इसके बाद जादू आता है. सारणी के कार्यों में से एक मानचित्र है। यह सरणी के प्रत्येक तत्व पर निर्दिष्ट ऑपरेशन लागू करता है।
हमारा कार्य प्रत्येक संख्या (अर्थात दिन की संख्या) में आरंभ तिथि जोड़ना है। DATE_ADD फ़ंक्शन ऐसा कर सकता है, यह निर्दिष्ट तिथि में एक निश्चित संख्या में दिन, महीने या वर्ष जोड़ता है।
यह जानते हुए, आइए स्ट्रिंग को डिक्रिप्ट करें:
with datesArray = sequenceArray.map(DATE_ADD(startDate, $,"day"))
सीक्वेंसअरे में प्रत्येक तत्व के लिए, .map() फ़ंक्शन DATE_ADD(startDate, $, "day") लागू होता है।
आइए देखें कि DATE_ADD के लिए तर्कों में क्या पारित किया जाता है। पहली चीज़ है प्रारंभ दिनांक, वह दिनांक जिसमें वांछित संख्या जोड़ी जाएगी। यह संख्या दूसरे तर्क द्वारा निर्दिष्ट है, लेकिन हम $ देखते हैं।
$ प्रतीक एक सरणी तत्व को दर्शाता है। संरचना समझती है कि DATE_ADD फ़ंक्शन एक सरणी पर लागू होता है, और इसलिए $ के बजाय वांछित सरणी तत्व होगा (अर्थात, 0, 1, 2…)।
अंतिम तर्क "दिन" एक संकेत है कि हम एक दिन जोड़ते हैं, क्योंकि हम जो निर्दिष्ट करते हैं उसके आधार पर फ़ंक्शन एक दिन, महीना और वर्ष जोड़ सकता है।
इस प्रकार, dateArray वैरिएबल काम की शुरुआत से लेकर उसके पूरा होने तक तारीखों की एक श्रृंखला संग्रहीत करेगा।
चलिए उस कस्टम फ़ंक्शन पर वापस आते हैं जिसे हम भूल गए थे। यह अतिरिक्त दिनों को फ़िल्टर करेगा और शेष की गणना करेगा। हमने कोड का विश्लेषण करने से पहले उदाहरण की शुरुआत में ही इस एल्गोरिदम का वर्णन किया था, अर्थात् पैराग्राफ 3 और 4 में छुट्टी के दिनों और स्थितियों को फ़िल्टर करने के बारे में।
with statusWeekendsCount(dates, status) = ( dates.filter(x -> weekday(x) > 5 and historical_value(this,"status",x)=status).size() ):
हम कस्टम फ़ंक्शन में दो तर्क पारित करेंगे: तिथियों की एक सरणी, आइए इसे तिथियां कहते हैं, और आवश्यक स्थिति - स्थिति। हम स्थानांतरित दिनांक सरणी में .filter() फ़ंक्शन लागू करते हैं, जो सरणी में केवल उन रिकॉर्ड्स को रखता है जो फ़िल्टर स्थिति से गुज़र चुके हैं। हमारे मामले में, उनमें से दो हैं, और वे और के माध्यम से संयुक्त हैं। फ़िल्टर के बाद, हम .size() देखते हैं, यह उस पर सभी ऑपरेशन किए जाने के बाद सरणी का आकार लौटाता है।
यदि हम अभिव्यक्ति को सरल बनाते हैं, तो हमें कुछ इस तरह मिलता है: array.filter(condition1 andcondition2).size()। तो, परिणामस्वरूप, हमें हमारे लिए उपयुक्त दिनों की छुट्टी मिल गई, यानी, वे दिन जो शर्तों को पूरा करते थे।
आइए दोनों स्थितियों पर करीब से नज़र डालें:
x -> weekday(x) > 5 and historical_value(this,"status",x)=status
अभिव्यक्ति x -> फ़िल्टर सिंटैक्स का सिर्फ एक हिस्सा है, जो दर्शाता है कि हम सरणी के तत्व को x कहेंगे। इसलिए, प्रत्येक स्थिति में x प्रकट होता है (उसी तरह जैसे यह $ के साथ था)। यह पता चला है कि x स्थानांतरित दिनांक सरणी से प्रत्येक तिथि है।
पहली शर्त, कार्यदिवस(x) > 5, के लिए आवश्यक है कि दिनांक x का कार्यदिवस (अर्थात, प्रत्येक तत्व) 5 से अधिक हो - यह या तो शनिवार (6) या रविवार (7) है।
दूसरी शर्त ऐतिहासिक_मूल्य का उपयोग करती है।
historical_value(this,"status",x) = status
यह संस्करण 7.4 की संरचना की एक विशेषता है।
फ़ंक्शन कार्य के इतिहास तक पहुंचता है और निर्दिष्ट फ़ील्ड में एक विशिष्ट तिथि की खोज करता है। इस मामले में, हम "स्थिति" फ़ील्ड में दिनांक x खोज रहे हैं। यह वेरिएबल केवल फ़ंक्शन सिंटैक्स का हिस्सा है, यह स्वचालित रूप से मैप किया जाता है और लाइन में वर्तमान कार्य का प्रतिनिधित्व करता है।
इस प्रकार, स्थिति में, हम स्थानांतरित स्थिति तर्क और "स्थिति" फ़ील्ड की तुलना करते हैं, जो सरणी में प्रत्येक दिनांक x के लिए ऐतिहासिक_वैल्यू फ़ंक्शन द्वारा लौटाया जाता है। यदि वे मेल खाते हैं, तो प्रविष्टि सूची में बनी रहती है।
अंतिम स्पर्श वांछित स्थिति में दिनों की संख्या गिनने के लिए हमारे फ़ंक्शन का उपयोग है:
with progressWeekends = statusWeekendsCount(datesArray, "in Progress"): with progressDays = (timeInProgress/86400000 - progressWeekends).round(1):
सबसे पहले, आइए जानें कि हमारी डेटअरे में "प्रगति में" स्थिति के साथ कितने दिनों की छुट्टी मिली। यानी, हम अपनी तारीखों की सूची और वांछित स्थिति को कस्टम फ़ंक्शन statusWeekendsCount में भेज देते हैं। फ़ंक्शन उन सभी कार्यदिवसों और सभी छुट्टी के दिनों को हटा देता है जिनमें कार्य की स्थिति "प्रगति में" स्थिति से भिन्न होती है और सूची में शेष दिनों की संख्या लौटाता है।
फिर हम इस राशि को टाइमइनप्रोग्रेस वेरिएबल से घटाते हैं, जिसे हम "टाइम इन स्टेटस ..." विकल्प के माध्यम से मैप करते हैं।
संख्या 86400000 वह भाजक है जो मिलीसेकंड को दिनों में बदल देगी। परिणाम को दसवें तक पूर्णांकित करने के लिए .राउंड(1) फ़ंक्शन की आवश्यकता होती है, उदाहरण के लिए "4.1", अन्यथा आप इस प्रकार की प्रविष्टि प्राप्त कर सकते हैं: "4.0999999..."।
कार्य की लंबाई को इंगित करने के लिए, हम रंग चर का परिचय देते हैं। हम कार्य पर बिताए गए दिनों की संख्या के आधार पर इसे बदल देंगे।
with color = if( progressDays = 0 ; "gray" ; progressDays > 0 and progressDays <= 2.5; "green" ; progressDays > 2.5 and progressDays <= 4; "orange" ; progressDays > 4; "red" ):
और गणना किए गए दिनों के परिणाम के साथ अंतिम पंक्ति:
"""{color:$color}$progressDays d{color}"""
हमारा परिणाम नीचे दी गई छवि जैसा दिखेगा।
वैसे इसी फॉर्मूले से आप किसी भी स्टेटस का टाइम डिस्प्ले कर सकते हैं. यदि, उदाहरण के लिए, हम अपने कस्टम फ़ंक्शन में "रोकें" स्थिति पास करते हैं, और टाइमइनप्रोग्रेस वैरिएबल को "समय में ... - रोकें" के माध्यम से मैप करते हैं, तो हम विराम में सटीक समय की गणना करेंगे।
आप स्थितियों को संयोजित कर सकते हैं और "wip: 3.2d |" जैसी प्रविष्टि बना सकते हैं Rev: 12d”, यानी, काम में लगने वाले समय और समीक्षा में लगने वाले समय की गणना करें। आप केवल अपनी कल्पना और अपने कार्यप्रवाह तक ही सीमित हैं।
हमने इस सूत्र भाषा की विस्तृत संख्या में विशेषताएं प्रस्तुत की हैं जो आपको जीरा कार्यों का विश्लेषण करने के लिए कुछ समान करने या कुछ पूरी तरह से नया और दिलचस्प लिखने में मदद करेंगी।
मुझे आशा है कि लेख ने आपको सूत्रों को समझने में मदद की, या कम से कम इस विषय में आपकी रुचि जगाई। मैं यह दावा नहीं करता कि मेरे पास "सर्वोत्तम कोड और एल्गोरिदम" है, इसलिए यदि आपके पास उदाहरणों को बेहतर बनाने के बारे में विचार हैं, तो यदि आप उन्हें साझा करेंगे तो मुझे खुशी होगी!
बेशक, आपको यह समझने की ज़रूरत है कि एएलएम वर्क्स डेवलपर्स से बेहतर आपको फ़ार्मुलों के बारे में कोई नहीं बताएगा। इसलिए, मैं उनके दस्तावेज़ीकरण और वेबिनार के लिंक संलग्न कर रहा हूं। और यदि आप कस्टम फ़ील्ड के साथ काम करना शुरू करते हैं, तो यह देखने के लिए उन्हें अक्सर जांचें कि आप किन अन्य सुविधाओं का उपयोग कर सकते हैं।